Implement FCM Version in matrices / manifests.

"level" is an attribute on compatibility matrices / manifests
to specify the FCM Version they declare / implement. Value can
be "legacy" or a positive number, or empty (for old files).

Test: libvintf_test
Test: Built manifests / matrices has not changed (because
      value is "unspecified").

Bug: 69854976 device manfiest must specify FCM Version
Bug: 69636193 all matrices should be installed to system image
Bug: 64720381 deprecation schedule

Change-Id: I15d34343fae4ad79d86bd50e9de8c4f6ac09fdfd
Merged-In: I15d34343fae4ad79d86bd50e9de8c4f6ac09fdfd
diff --git a/parse_string.cpp b/parse_string.cpp
index a6bb418..7e23f5f 100644
--- a/parse_string.cpp
+++ b/parse_string.cpp
@@ -113,6 +113,33 @@
     }
 }
 
+bool parse(const std::string& s, Level* l) {
+    if (s.empty()) {
+        *l = Level::UNSPECIFIED;
+        return true;
+    }
+    if (s == "legacy") {
+        *l = Level::LEGACY;
+        return true;
+    }
+    size_t value;
+    if (!ParseUint(s, &value)) {
+        return false;
+    }
+    *l = static_cast<Level>(value);
+    return true;
+}
+
+std::ostream& operator<<(std::ostream& os, Level l) {
+    if (l == Level::UNSPECIFIED) {
+        return os;
+    }
+    if (l == Level::LEGACY) {
+        return os << "legacy";
+    }
+    return os << static_cast<size_t>(l);
+}
+
 // Notice that strtoull is used even though KernelConfigIntValue is signed int64_t,
 // because strtoull can accept negative values as well.
 // Notice that according to man strtoul, strtoull can actually accept