Allow optional elements and attributes.
Per the document, allowed optional elements and attributes are:
* compatibility-matrix.hal.format
* compatibility-matrix.hal.optional
* manifest.hal.format
* manifest.hal.impl
This change is needed to support system/manifest.xml because
manifest.hal.impl is missing.
Test: `adb shell vintf` correctly shows system/manifest.xml
Test: libvintf
Change-Id: Ia54842d128ba1bc614c29f3b364642393d800086
diff --git a/parse_xml.cpp b/parse_xml.cpp
index c054350..8a3f69a 100644
--- a/parse_xml.cpp
+++ b/parse_xml.cpp
@@ -111,6 +111,19 @@
// --------------- tinyxml2 details end.
+// Helper functions for XmlConverter
+static bool parse(const std::string &attrText, bool *attr) {
+ if (attrText == "true" || attrText == "1") {
+ *attr = true;
+ return true;
+ }
+ if (attrText == "false" || attrText == "0") {
+ *attr = false;
+ return true;
+ }
+ return false;
+}
+
// ---------------------- XmlNodeConverter definitions
template<typename Object>
@@ -164,6 +177,8 @@
}
// convenience methods for implementor.
+
+ // All append* functions helps mutateNode() to serialize the object into XML.
template <typename T>
inline void appendAttr(NodeType *e, const std::string &attrName, const T &attr) const {
return appendStrAttr(e, attrName, ::android::vintf::to_string(attr));
@@ -200,6 +215,21 @@
}
}
+ // All parse* functions helps buildObject() to deserialize XML to the object. Returns
+ // true if deserialization is successful, false if any error, and mLastError will be
+ // set to error message.
+ template <typename T>
+ inline bool parseOptionalAttr(NodeType *root, const std::string &attrName,
+ T &&defaultValue, T *attr) const {
+ std::string attrText;
+ bool success = getAttr(root, attrName, &attrText) &&
+ ::android::vintf::parse(attrText, attr);
+ if (!success) {
+ *attr = std::move(defaultValue);
+ }
+ return true;
+ }
+
template <typename T>
inline bool parseAttr(NodeType *root, const std::string &attrName, T *attr) const {
std::string attrText;
@@ -218,25 +248,6 @@
return ret;
}
- inline bool parseAttr(NodeType *root, const std::string &attrName, bool *attr) const {
- std::string attrText;
- if (!getAttr(root, attrName, &attrText)) {
- mLastError = "Could not find attr with name " + attrName;
- return false;
- }
- if (attrText == "true" || attrText == "1") {
- *attr = true;
- return true;
- }
- if (attrText == "false" || attrText == "0") {
- *attr = false;
- return true;
- }
- mLastError = "Could not parse attr with name \"" + attrName
- + "\" and value \"" + attrText + "\"";
- return false;
- }
-
inline bool parseTextElement(NodeType *root,
const std::string &elementName, std::string *s) const {
NodeType *child = getChild(root, elementName);
@@ -273,6 +284,21 @@
}
template <typename T>
+ inline bool parseOptionalChild(NodeType *root, const XmlNodeConverter<T> &conv,
+ T &&defaultValue, T *t) const {
+ NodeType *child = getChild(root, conv.elementName());
+ if (child == nullptr) {
+ *t = std::move(defaultValue);
+ return true;
+ }
+ bool success = conv.deserialize(t, child);
+ if (!success) {
+ mLastError = conv.lastError();
+ }
+ return success;
+ }
+
+ template <typename T>
inline bool parseChildren(NodeType *root, const XmlNodeConverter<T> &conv, std::vector<T> *v) const {
auto nodes = getChildren(root, conv.elementName());
v->resize(nodes.size());
@@ -373,8 +399,8 @@
appendChildren(root, versionRangeConverter, hal.versionRanges, d);
}
bool buildObject(MatrixHal *object, NodeType *root) const override {
- if (!parseAttr(root, "format", &object->format) ||
- !parseAttr(root, "optional", &object->optional) ||
+ if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format) ||
+ !parseOptionalAttr(root, "optional", false /* defaultValue */, &object->optional) ||
!parseTextElement(root, "name", &object->name) ||
!parseChildren(root, versionRangeConverter, &object->versionRanges)) {
return false;
@@ -455,10 +481,10 @@
}
bool buildObject(ManifestHal *object, NodeType *root) const override {
std::vector<ManifestHalInterface> interfaces;
- if (!parseAttr(root, "format", &object->format) ||
+ if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format) ||
!parseTextElement(root, "name", &object->name) ||
!parseChild(root, transportConverter, &object->transport) ||
- !parseChild(root, halImplementationConverter, &object->impl) ||
+ !parseOptionalChild(root, halImplementationConverter, {}, &object->impl) ||
!parseChildren(root, versionConverter, &object->versions) ||
!parseChildren(root, manfiestHalInterfaceConverter, &interfaces)) {
return false;