1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // Convert objects from and to xml.
18 
19 #include <tinyxml2.h>
20 
21 #include "parse_string.h"
22 #include "parse_xml.h"
23 
24 namespace android {
25 namespace vintf {
26 
27 // --------------- tinyxml2 details
28 
29 using NodeType = tinyxml2::XMLElement;
30 using DocType = tinyxml2::XMLDocument;
31 
32 // caller is responsible for deleteDocument() call
createDocument()33 inline DocType *createDocument() {
34     return new tinyxml2::XMLDocument();
35 }
36 
37 // caller is responsible for deleteDocument() call
createDocument(const std::string & xml)38 inline DocType *createDocument(const std::string &xml) {
39     DocType *doc = new tinyxml2::XMLDocument();
40     if (doc->Parse(xml.c_str()) == tinyxml2::XML_NO_ERROR) {
41         return doc;
42     }
43     delete doc;
44     return nullptr;
45 }
46 
deleteDocument(DocType * d)47 inline void deleteDocument(DocType *d) {
48     delete d;
49 }
50 
printDocument(DocType * d)51 inline std::string printDocument(DocType *d) {
52     tinyxml2::XMLPrinter p;
53     d->Print(&p);
54     return std::string{p.CStr()};
55 }
56 
createNode(const std::string & name,DocType * d)57 inline NodeType *createNode(const std::string &name, DocType *d) {
58     return d->NewElement(name.c_str());
59 }
60 
appendChild(NodeType * parent,NodeType * child)61 inline void appendChild(NodeType *parent, NodeType *child) {
62     parent->InsertEndChild(child);
63 }
64 
appendChild(DocType * parent,NodeType * child)65 inline void appendChild(DocType *parent, NodeType *child) {
66     parent->InsertEndChild(child);
67 }
68 
appendStrAttr(NodeType * e,const std::string & attrName,const std::string & attr)69 inline void appendStrAttr(NodeType *e, const std::string &attrName, const std::string &attr) {
70     e->SetAttribute(attrName.c_str(), attr.c_str());
71 }
72 
73 // text -> text
appendText(NodeType * parent,const std::string & text,DocType * d)74 inline void appendText(NodeType *parent, const std::string &text, DocType *d) {
75     parent->InsertEndChild(d->NewText(text.c_str()));
76 }
77 
nameOf(NodeType * root)78 inline std::string nameOf(NodeType *root) {
79     return root->Name() == NULL ? "" : root->Name();
80 }
81 
getText(NodeType * root)82 inline std::string getText(NodeType *root) {
83     return root->GetText() == NULL ? "" : root->GetText();
84 }
85 
getChild(NodeType * parent,const std::string & name)86 inline NodeType *getChild(NodeType *parent, const std::string &name) {
87     return parent->FirstChildElement(name.c_str());
88 }
89 
getRootChild(DocType * parent)90 inline NodeType *getRootChild(DocType *parent) {
91     return parent->FirstChildElement();
92 }
93 
getChildren(NodeType * parent,const std::string & name)94 inline std::vector<NodeType *> getChildren(NodeType *parent, const std::string &name) {
95     std::vector<NodeType *> v;
96     for (NodeType *child = parent->FirstChildElement(name.c_str());
97          child != nullptr;
98          child = child->NextSiblingElement(name.c_str())) {
99         v.push_back(child);
100     }
101     return v;
102 }
103 
getAttr(NodeType * root,const std::string & attrName,std::string * s)104 inline bool getAttr(NodeType *root, const std::string &attrName, std::string *s) {
105     const char *c = root->Attribute(attrName.c_str());
106     if (c == NULL)
107         return false;
108     *s = c;
109     return true;
110 }
111 
112 // --------------- tinyxml2 details end.
113 
114 // Helper functions for XmlConverter
parse(const std::string & attrText,bool * attr)115 static bool parse(const std::string &attrText, bool *attr) {
116     if (attrText == "true" || attrText == "1") {
117         *attr = true;
118         return true;
119     }
120     if (attrText == "false" || attrText == "0") {
121         *attr = false;
122         return true;
123     }
124     return false;
125 }
126 
127 // ---------------------- XmlNodeConverter definitions
128 
129 template<typename Object>
130 struct XmlNodeConverter : public XmlConverter<Object> {
XmlNodeConverterandroid::vintf::XmlNodeConverter131     XmlNodeConverter() {}
~XmlNodeConverterandroid::vintf::XmlNodeConverter132     virtual ~XmlNodeConverter() {}
133 
134     // sub-types should implement these.
135     virtual void mutateNode(const Object &o, NodeType *n, DocType *d) const = 0;
136     virtual bool buildObject(Object *o, NodeType *n) const = 0;
137     virtual std::string elementName() const = 0;
138 
139     // convenience methods for user
lastErrorandroid::vintf::XmlNodeConverter140     inline const std::string &lastError() const { return mLastError; }
serializeandroid::vintf::XmlNodeConverter141     inline NodeType *serialize(const Object &o, DocType *d) const {
142         NodeType *root = createNode(this->elementName(), d);
143         this->mutateNode(o, root, d);
144         return root;
145     }
serializeandroid::vintf::XmlNodeConverter146     inline std::string serialize(const Object &o) const {
147         DocType *doc = createDocument();
148         appendChild(doc, serialize(o, doc));
149         std::string s = printDocument(doc);
150         deleteDocument(doc);
151         return s;
152     }
deserializeandroid::vintf::XmlNodeConverter153     inline bool deserialize(Object *object, NodeType *root) const {
154         if (nameOf(root) != this->elementName()) {
155             return false;
156         }
157         return this->buildObject(object, root);
158     }
deserializeandroid::vintf::XmlNodeConverter159     inline bool deserialize(Object *o, const std::string &xml) const {
160         DocType *doc = createDocument(xml);
161         if (doc == nullptr) {
162             this->mLastError = "Not a valid XML";
163             return false;
164         }
165         bool ret = deserialize(o, getRootChild(doc));
166         deleteDocument(doc);
167         return ret;
168     }
operator ()android::vintf::XmlNodeConverter169     inline NodeType *operator()(const Object &o, DocType *d) const {
170         return serialize(o, d);
171     }
operator ()android::vintf::XmlNodeConverter172     inline std::string operator()(const Object &o) const {
173         return serialize(o);
174     }
operator ()android::vintf::XmlNodeConverter175     inline bool operator()(Object *o, NodeType *node) const {
176         return deserialize(o, node);
177     }
operator ()android::vintf::XmlNodeConverter178     inline bool operator()(Object *o, const std::string &xml) const {
179         return deserialize(o, xml);
180     }
181 
182     // convenience methods for implementor.
183 
184     // All append* functions helps mutateNode() to serialize the object into XML.
185     template <typename T>
appendAttrandroid::vintf::XmlNodeConverter186     inline void appendAttr(NodeType *e, const std::string &attrName, const T &attr) const {
187         return appendStrAttr(e, attrName, ::android::vintf::to_string(attr));
188     }
189 
appendAttrandroid::vintf::XmlNodeConverter190     inline void appendAttr(NodeType *e, const std::string &attrName, bool attr) const {
191         return appendStrAttr(e, attrName, attr ? "true" : "false");
192     }
193 
194     // text -> <name>text</name>
appendTextElementandroid::vintf::XmlNodeConverter195     inline void appendTextElement(NodeType *parent, const std::string &name,
196                 const std::string &text, DocType *d) const {
197         NodeType *c = createNode(name, d);
198         appendText(c, text, d);
199         appendChild(parent, c);
200     }
201 
202     // text -> <name>text</name>
203     template<typename Array>
appendTextElementsandroid::vintf::XmlNodeConverter204     inline void appendTextElements(NodeType *parent, const std::string &name,
205                 const Array &array, DocType *d) const {
206         for (const std::string &text : array) {
207             NodeType *c = createNode(name, d);
208             appendText(c, text, d);
209             appendChild(parent, c);
210         }
211     }
212 
213     template<typename T, typename Array>
appendChildrenandroid::vintf::XmlNodeConverter214     inline void appendChildren(NodeType *parent, const XmlNodeConverter<T> &conv,
215             const Array &array, DocType *d) const {
216         for (const T &t : array) {
217             appendChild(parent, conv(t, d));
218         }
219     }
220 
221     // All parse* functions helps buildObject() to deserialize XML to the object. Returns
222     // true if deserialization is successful, false if any error, and mLastError will be
223     // set to error message.
224     template <typename T>
parseOptionalAttrandroid::vintf::XmlNodeConverter225     inline bool parseOptionalAttr(NodeType *root, const std::string &attrName,
226             T &&defaultValue, T *attr) const {
227         std::string attrText;
228         bool success = getAttr(root, attrName, &attrText) &&
229                        ::android::vintf::parse(attrText, attr);
230         if (!success) {
231             *attr = std::move(defaultValue);
232         }
233         return true;
234     }
235 
236     template <typename T>
parseAttrandroid::vintf::XmlNodeConverter237     inline bool parseAttr(NodeType *root, const std::string &attrName, T *attr) const {
238         std::string attrText;
239         bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr);
240         if (!ret) {
241             mLastError = "Could not find/parse attr with name \"" + attrName + "\" for element <"
242                     + elementName() + ">";
243         }
244         return ret;
245     }
246 
parseAttrandroid::vintf::XmlNodeConverter247     inline bool parseAttr(NodeType *root, const std::string &attrName, std::string *attr) const {
248         bool ret = getAttr(root, attrName, attr);
249         if (!ret) {
250             mLastError = "Could not find attr with name \"" + attrName + "\" for element <"
251                     + elementName() + ">";
252         }
253         return ret;
254     }
255 
parseTextElementandroid::vintf::XmlNodeConverter256     inline bool parseTextElement(NodeType *root,
257             const std::string &elementName, std::string *s) const {
258         NodeType *child = getChild(root, elementName);
259         if (child == nullptr) {
260             mLastError = "Could not find element with name <" + elementName + "> in element <"
261                     + this->elementName() + ">";
262             return false;
263         }
264         *s = getText(child);
265         return true;
266     }
267 
parseTextElementsandroid::vintf::XmlNodeConverter268     inline bool parseTextElements(NodeType *root, const std::string &elementName,
269             std::vector<std::string> *v) const {
270         auto nodes = getChildren(root, elementName);
271         v->resize(nodes.size());
272         for (size_t i = 0; i < nodes.size(); ++i) {
273             v->at(i) = getText(nodes[i]);
274         }
275         return true;
276     }
277 
278     template <typename T>
parseChildandroid::vintf::XmlNodeConverter279     inline bool parseChild(NodeType *root, const XmlNodeConverter<T> &conv, T *t) const {
280         NodeType *child = getChild(root, conv.elementName());
281         if (child == nullptr) {
282             mLastError = "Could not find element with name <" + conv.elementName() + "> in element <"
283                     + this->elementName() + ">";
284             return false;
285         }
286         bool success = conv.deserialize(t, child);
287         if (!success) {
288             mLastError = conv.lastError();
289         }
290         return success;
291     }
292 
293     template <typename T>
parseOptionalChildandroid::vintf::XmlNodeConverter294     inline bool parseOptionalChild(NodeType *root, const XmlNodeConverter<T> &conv,
295             T &&defaultValue, T *t) const {
296         NodeType *child = getChild(root, conv.elementName());
297         if (child == nullptr) {
298             *t = std::move(defaultValue);
299             return true;
300         }
301         bool success = conv.deserialize(t, child);
302         if (!success) {
303             mLastError = conv.lastError();
304         }
305         return success;
306     }
307 
308     template <typename T>
parseChildrenandroid::vintf::XmlNodeConverter309     inline bool parseChildren(NodeType *root, const XmlNodeConverter<T> &conv, std::vector<T> *v) const {
310         auto nodes = getChildren(root, conv.elementName());
311         v->resize(nodes.size());
312         for (size_t i = 0; i < nodes.size(); ++i) {
313             if (!conv.deserialize(&v->at(i), nodes[i])) {
314                 mLastError = "Could not parse element with name <" + conv.elementName()
315                         + "> in element <" + this->elementName() + ">: " + conv.lastError();
316                 return false;
317             }
318         }
319         return true;
320     }
321 
322     template <typename T>
parseChildrenandroid::vintf::XmlNodeConverter323     inline bool parseChildren(NodeType *root, const XmlNodeConverter<T> &conv, std::set<T> *s) const {
324         std::vector<T> vec;
325         if (!parseChildren(root, conv, &vec)) {
326             return false;
327         }
328         s->clear();
329         s->insert(vec.begin(), vec.end());
330         if (s->size() != vec.size()) {
331             mLastError = "Duplicated elements <" + conv.elementName() + "> in element <"
332                     + this->elementName() + ">";
333             s->clear();
334             return false;
335         }
336         return true;
337     }
338 
parseTextandroid::vintf::XmlNodeConverter339     inline bool parseText(NodeType *node, std::string *s) const {
340         *s = getText(node);
341         return true;
342     }
343 
344     template <typename T>
parseTextandroid::vintf::XmlNodeConverter345     inline bool parseText(NodeType *node, T *s) const {
346         std::string text = getText(node);
347         bool ret = ::android::vintf::parse(text, s);
348         if (!ret) {
349             mLastError = "Could not parse text \"" + text + "\" in element <" + elementName() + ">";
350         }
351         return ret;
352     }
353 protected:
354     mutable std::string mLastError;
355 };
356 
357 template<typename Object>
358 struct XmlTextConverter : public XmlNodeConverter<Object> {
XmlTextConverterandroid::vintf::XmlTextConverter359     XmlTextConverter(const std::string &elementName)
360         : mElementName(elementName) {}
361 
mutateNodeandroid::vintf::XmlTextConverter362     virtual void mutateNode(const Object &object, NodeType *root, DocType *d) const override {
363         appendText(root, ::android::vintf::to_string(object), d);
364     }
buildObjectandroid::vintf::XmlTextConverter365     virtual bool buildObject(Object *object, NodeType *root) const override {
366         return this->parseText(root, object);
367     }
elementNameandroid::vintf::XmlTextConverter368     virtual std::string elementName() const { return mElementName; };
369 private:
370     std::string mElementName;
371 };
372 
373 // ---------------------- XmlNodeConverter definitions end
374 
375 const XmlTextConverter<Version> versionConverter{"version"};
376 
377 const XmlTextConverter<VersionRange> versionRangeConverter{"version"};
378 
379 const XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"};
380 
381 struct TransportArchConverter : public XmlNodeConverter<TransportArch> {
elementNameandroid::vintf::TransportArchConverter382     std::string elementName() const override { return "transport"; }
mutateNodeandroid::vintf::TransportArchConverter383     void mutateNode(const TransportArch &object, NodeType *root, DocType *d) const override {
384         if (object.arch != Arch::ARCH_EMPTY) {
385             appendAttr(root, "arch", object.arch);
386         }
387         appendText(root, ::android::vintf::to_string(object.transport), d);
388     }
buildObjectandroid::vintf::TransportArchConverter389     bool buildObject(TransportArch *object, NodeType *root) const override {
390         if (!parseOptionalAttr(root, "arch", Arch::ARCH_EMPTY, &object->arch) ||
391             !parseText(root, &object->transport)) {
392             return false;
393         }
394         if (!object->isValid()) {
395             this->mLastError = "transport == " + ::android::vintf::to_string(object->transport) +
396                     " and arch == " + ::android::vintf::to_string(object->arch) +
397                     " is not a valid combination.";
398             return false;
399         }
400         return true;
401     }
402 };
403 
404 const TransportArchConverter transportArchConverter{};
405 
406 struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> {
elementNameandroid::vintf::KernelConfigTypedValueConverter407     std::string elementName() const override { return "value"; }
mutateNodeandroid::vintf::KernelConfigTypedValueConverter408     void mutateNode(const KernelConfigTypedValue &object, NodeType *root, DocType *d) const override {
409         appendAttr(root, "type", object.mType);
410         appendText(root, ::android::vintf::to_string(object), d);
411     }
buildObjectandroid::vintf::KernelConfigTypedValueConverter412     bool buildObject(KernelConfigTypedValue *object, NodeType *root) const override {
413         std::string stringValue;
414         if (!parseAttr(root, "type", &object->mType) ||
415             !parseText(root, &stringValue)) {
416             return false;
417         }
418         if (!::android::vintf::parseKernelConfigValue(stringValue, object)) {
419             this->mLastError = "Could not parse kernel config value \"" + stringValue + "\"";
420             return false;
421         }
422         return true;
423     }
424 };
425 
426 const KernelConfigTypedValueConverter kernelConfigTypedValueConverter{};
427 
428 struct KernelConfigConverter : public XmlNodeConverter<KernelConfig> {
elementNameandroid::vintf::KernelConfigConverter429     std::string elementName() const override { return "config"; }
mutateNodeandroid::vintf::KernelConfigConverter430     void mutateNode(const KernelConfig &object, NodeType *root, DocType *d) const override {
431         appendChild(root, kernelConfigKeyConverter(object.first, d));
432         appendChild(root, kernelConfigTypedValueConverter(object.second, d));
433     }
buildObjectandroid::vintf::KernelConfigConverter434     bool buildObject(KernelConfig *object, NodeType *root) const override {
435         if (   !parseChild(root, kernelConfigKeyConverter, &object->first)
436             || !parseChild(root, kernelConfigTypedValueConverter, &object->second)) {
437             return false;
438         }
439         return true;
440     }
441 };
442 
443 const KernelConfigConverter kernelConfigConverter{};
444 
445 struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> {
elementNameandroid::vintf::HalInterfaceConverter446     std::string elementName() const override { return "interface"; }
mutateNodeandroid::vintf::HalInterfaceConverter447     void mutateNode(const HalInterface &intf, NodeType *root, DocType *d) const override {
448         appendTextElement(root, "name", intf.name, d);
449         appendTextElements(root, "instance", intf.instances, d);
450     }
buildObjectandroid::vintf::HalInterfaceConverter451     bool buildObject(HalInterface *intf, NodeType *root) const override {
452         std::vector<std::string> instances;
453         if (!parseTextElement(root, "name", &intf->name) ||
454             !parseTextElements(root, "instance", &instances)) {
455             return false;
456         }
457         intf->instances.clear();
458         intf->instances.insert(instances.begin(), instances.end());
459         if (intf->instances.size() != instances.size()) {
460             this->mLastError = "Duplicated instances in " + intf->name;
461             return false;
462         }
463         return true;
464     }
465 };
466 
467 const HalInterfaceConverter halInterfaceConverter{};
468 
469 struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
elementNameandroid::vintf::MatrixHalConverter470     std::string elementName() const override { return "hal"; }
mutateNodeandroid::vintf::MatrixHalConverter471     void mutateNode(const MatrixHal &hal, NodeType *root, DocType *d) const override {
472         appendAttr(root, "format", hal.format);
473         appendAttr(root, "optional", hal.optional);
474         appendTextElement(root, "name", hal.name, d);
475         appendChildren(root, versionRangeConverter, hal.versionRanges, d);
476         appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d);
477     }
buildObjectandroid::vintf::MatrixHalConverter478     bool buildObject(MatrixHal *object, NodeType *root) const override {
479         std::vector<HalInterface> interfaces;
480         if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format) ||
481             !parseOptionalAttr(root, "optional", false /* defaultValue */, &object->optional) ||
482             !parseTextElement(root, "name", &object->name) ||
483             !parseChildren(root, versionRangeConverter, &object->versionRanges) ||
484             !parseChildren(root, halInterfaceConverter, &interfaces)) {
485             return false;
486         }
487         for (auto&& interface : interfaces) {
488             std::string name{interface.name};
489             auto res = object->interfaces.emplace(std::move(name), std::move(interface));
490             if (!res.second) {
491                 this->mLastError = "Duplicated instance entry " + res.first->first;
492                 return false;
493             }
494         }
495         return true;
496     }
497 };
498 
499 const MatrixHalConverter matrixHalConverter{};
500 
501 struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
elementNameandroid::vintf::MatrixKernelConverter502     std::string elementName() const override { return "kernel"; }
mutateNodeandroid::vintf::MatrixKernelConverter503     void mutateNode(const MatrixKernel &kernel, NodeType *root, DocType *d) const override {
504         appendAttr(root, "version", kernel.mMinLts);
505         appendChildren(root, kernelConfigConverter, kernel.mConfigs, d);
506     }
buildObjectandroid::vintf::MatrixKernelConverter507     bool buildObject(MatrixKernel *object, NodeType *root) const override {
508         if (!parseAttr(root, "version", &object->mMinLts) ||
509             !parseChildren(root, kernelConfigConverter, &object->mConfigs)) {
510             return false;
511         }
512         return true;
513     }
514 };
515 
516 const MatrixKernelConverter matrixKernelConverter{};
517 
518 struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
elementNameandroid::vintf::ManifestHalConverter519     std::string elementName() const override { return "hal"; }
mutateNodeandroid::vintf::ManifestHalConverter520     void mutateNode(const ManifestHal &hal, NodeType *root, DocType *d) const override {
521         appendAttr(root, "format", hal.format);
522         appendTextElement(root, "name", hal.name, d);
523         if (!hal.transportArch.empty()) {
524             appendChild(root, transportArchConverter(hal.transportArch, d));
525         }
526         appendChildren(root, versionConverter, hal.versions, d);
527         appendChildren(root, halInterfaceConverter, iterateValues(hal.interfaces), d);
528     }
buildObjectandroid::vintf::ManifestHalConverter529     bool buildObject(ManifestHal *object, NodeType *root) const override {
530         std::vector<HalInterface> interfaces;
531         if (!parseOptionalAttr(root, "format", HalFormat::HIDL, &object->format) ||
532             !parseTextElement(root, "name", &object->name) ||
533             !parseChild(root, transportArchConverter, &object->transportArch) ||
534             !parseChildren(root, versionConverter, &object->versions) ||
535             !parseChildren(root, halInterfaceConverter, &interfaces)) {
536             return false;
537         }
538         object->interfaces.clear();
539         for (auto &&interface : interfaces) {
540             auto res = object->interfaces.emplace(interface.name,
541                                                   std::move(interface));
542             if (!res.second) {
543                 this->mLastError = "Duplicated instance entry " + res.first->first;
544                 return false;
545             }
546         }
547         if (!object->isValid()) {
548             this->mLastError = "'" + object->name + "' is not a valid Manifest HAL.";
549             return false;
550         }
551         return true;
552     }
553 };
554 
555 // Convert ManifestHal from and to XML. Returned object is guaranteed to have
556 // .isValid() == true.
557 const ManifestHalConverter manifestHalConverter{};
558 
559 const XmlTextConverter<KernelSepolicyVersion> kernelSepolicyVersionConverter{"kernel-sepolicy-version"};
560 const XmlTextConverter<VersionRange> sepolicyVersionConverter{"sepolicy-version"};
561 
562 struct SepolicyConverter : public XmlNodeConverter<Sepolicy> {
elementNameandroid::vintf::SepolicyConverter563     std::string elementName() const override { return "sepolicy"; }
mutateNodeandroid::vintf::SepolicyConverter564     void mutateNode(const Sepolicy &object, NodeType *root, DocType *d) const override {
565         appendChild(root, kernelSepolicyVersionConverter(object.kernelSepolicyVersion(), d));
566         appendChildren(root, sepolicyVersionConverter, object.sepolicyVersions(), d);
567     }
buildObjectandroid::vintf::SepolicyConverter568     bool buildObject(Sepolicy *object, NodeType *root) const override {
569         if (!parseChild(root, kernelSepolicyVersionConverter, &object->mKernelSepolicyVersion) ||
570             !parseChildren(root, sepolicyVersionConverter, &object->mSepolicyVersionRanges)) {
571             return false;
572         }
573         return true;
574     }
575 };
576 const SepolicyConverter sepolicyConverter{};
577 
578 const XmlTextConverter<VndkVersionRange> vndkVersionRangeConverter{"version"};
579 const XmlTextConverter<std::string> vndkLibraryConverter{"library"};
580 
581 struct VndkConverter : public XmlNodeConverter<Vndk> {
elementNameandroid::vintf::VndkConverter582     std::string elementName() const override { return "vndk"; }
mutateNodeandroid::vintf::VndkConverter583     void mutateNode(const Vndk &object, NodeType *root, DocType *d) const override {
584         appendChild(root, vndkVersionRangeConverter(object.mVersionRange, d));
585         appendChildren(root, vndkLibraryConverter, object.mLibraries, d);
586     }
buildObjectandroid::vintf::VndkConverter587     bool buildObject(Vndk *object, NodeType *root) const override {
588         if (!parseChild(root, vndkVersionRangeConverter, &object->mVersionRange) ||
589             !parseChildren(root, vndkLibraryConverter, &object->mLibraries)) {
590             return false;
591         }
592         return true;
593     }
594 };
595 
596 const VndkConverter vndkConverter{};
597 
598 struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> {
elementNameandroid::vintf::HalManifestSepolicyConverter599     std::string elementName() const override { return "sepolicy"; }
mutateNodeandroid::vintf::HalManifestSepolicyConverter600     void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
601         appendChild(root, versionConverter(m, d));
602     }
buildObjectandroid::vintf::HalManifestSepolicyConverter603     bool buildObject(Version *object, NodeType *root) const override {
604         return parseChild(root, versionConverter, object);
605     }
606 };
607 const HalManifestSepolicyConverter halManifestSepolicyConverter{};
608 
609 struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
elementNameandroid::vintf::HalManifestConverter610     std::string elementName() const override { return "manifest"; }
mutateNodeandroid::vintf::HalManifestConverter611     void mutateNode(const HalManifest &m, NodeType *root, DocType *d) const override {
612         appendAttr(root, "version", HalManifest::kVersion);
613         appendAttr(root, "type", m.mType);
614         appendChildren(root, manifestHalConverter, m.getHals(), d);
615         if (m.mType == SchemaType::DEVICE) {
616             appendChild(root, halManifestSepolicyConverter(m.device.mSepolicyVersion, d));
617         } else if (m.mType == SchemaType::FRAMEWORK) {
618             appendChildren(root, vndkConverter, m.framework.mVndks, d);
619         }
620     }
buildObjectandroid::vintf::HalManifestConverter621     bool buildObject(HalManifest *object, NodeType *root) const override {
622         Version version;
623         std::vector<ManifestHal> hals;
624         if (!parseAttr(root, "version", &version) ||
625             !parseAttr(root, "type", &object->mType) ||
626             !parseChildren(root, manifestHalConverter, &hals)) {
627             return false;
628         }
629         if (version != HalManifest::kVersion) {
630             this->mLastError = "Unrecognized manifest.version";
631             return false;
632         }
633         if (object->mType == SchemaType::DEVICE) {
634             // tags for device hal manifest only.
635             // <sepolicy> can be missing because it can be determined at build time, not hard-coded
636             // in the XML file.
637             if (!parseOptionalChild(root, halManifestSepolicyConverter, {},
638                     &object->device.mSepolicyVersion)) {
639                 return false;
640             }
641         } else if (object->mType == SchemaType::FRAMEWORK) {
642             if (!parseChildren(root, vndkConverter, &object->framework.mVndks)) {
643                 return false;
644             }
645             for (const auto &vndk : object->framework.mVndks) {
646                 if (!vndk.mVersionRange.isSingleVersion()) {
647                     this->mLastError = "vndk.version " + to_string(vndk.mVersionRange)
648                             + " cannot be a range for manifests";
649                     return false;
650                 }
651             }
652         }
653         for (auto &&hal : hals) {
654             std::string description{hal.name};
655             if (!object->add(std::move(hal))) {
656                 this->mLastError = "Duplicated manifest.hal entry " + description;
657                 return false;
658             }
659         }
660         return true;
661     }
662 };
663 
664 const HalManifestConverter halManifestConverter{};
665 
666 const XmlTextConverter<Version> avbVersionConverter{"vbmeta-version"};
667 struct AvbConverter : public XmlNodeConverter<Version> {
elementNameandroid::vintf::AvbConverter668     std::string elementName() const override { return "avb"; }
mutateNodeandroid::vintf::AvbConverter669     void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
670         appendChild(root, avbVersionConverter(m, d));
671     }
buildObjectandroid::vintf::AvbConverter672     bool buildObject(Version *object, NodeType *root) const override {
673         return parseChild(root, avbVersionConverter, object);
674     }
675 };
676 const AvbConverter avbConverter{};
677 
678 struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> {
elementNameandroid::vintf::CompatibilityMatrixConverter679     std::string elementName() const override { return "compatibility-matrix"; }
mutateNodeandroid::vintf::CompatibilityMatrixConverter680     void mutateNode(const CompatibilityMatrix &m, NodeType *root, DocType *d) const override {
681         appendAttr(root, "version", CompatibilityMatrix::kVersion);
682         appendAttr(root, "type", m.mType);
683         appendChildren(root, matrixHalConverter, iterateValues(m.mHals), d);
684         if (m.mType == SchemaType::FRAMEWORK) {
685             appendChildren(root, matrixKernelConverter, m.framework.mKernels, d);
686             appendChild(root, sepolicyConverter(m.framework.mSepolicy, d));
687             appendChild(root, avbConverter(m.framework.mAvbMetaVersion, d));
688         } else if (m.mType == SchemaType::DEVICE) {
689             appendChild(root, vndkConverter(m.device.mVndk, d));
690         }
691     }
buildObjectandroid::vintf::CompatibilityMatrixConverter692     bool buildObject(CompatibilityMatrix *object, NodeType *root) const override {
693         Version version;
694         std::vector<MatrixHal> hals;
695         if (!parseAttr(root, "version", &version) ||
696             !parseAttr(root, "type", &object->mType) ||
697             !parseChildren(root, matrixHalConverter, &hals)) {
698             return false;
699         }
700 
701         if (object->mType == SchemaType::FRAMEWORK) {
702             // <avb> and <sepolicy> can be missing because it can be determined at build time, not
703             // hard-coded in the XML file.
704             if (!parseChildren(root, matrixKernelConverter, &object->framework.mKernels) ||
705                 !parseOptionalChild(root, sepolicyConverter, {}, &object->framework.mSepolicy) ||
706                 !parseOptionalChild(root, avbConverter, {}, &object->framework.mAvbMetaVersion)) {
707                 return false;
708             }
709         } else if (object->mType == SchemaType::DEVICE) {
710             // <vndk> can be missing because it can be determined at build time, not hard-coded
711             // in the XML file.
712             if (!parseOptionalChild(root, vndkConverter, {}, &object->device.mVndk)) {
713                 return false;
714             }
715         }
716 
717         if (version != CompatibilityMatrix::kVersion) {
718             this->mLastError = "Unrecognized compatibility-matrix.version";
719             return false;
720         }
721         for (auto &&hal : hals) {
722             if (!object->add(std::move(hal))) {
723                 this->mLastError = "Duplicated compatibility-matrix.hal entry";
724                 return false;
725             }
726         }
727         return true;
728     }
729 };
730 
731 const CompatibilityMatrixConverter compatibilityMatrixConverter{};
732 
733 // Publicly available as in parse_xml.h
734 const XmlConverter<HalManifest> &gHalManifestConverter = halManifestConverter;
735 const XmlConverter<CompatibilityMatrix> &gCompatibilityMatrixConverter
736         = compatibilityMatrixConverter;
737 
738 // For testing in LibVintfTest
739 const XmlConverter<Version> &gVersionConverter = versionConverter;
740 const XmlConverter<KernelConfigTypedValue> &gKernelConfigTypedValueConverter
741         = kernelConfigTypedValueConverter;
742 const XmlConverter<MatrixHal> &gMatrixHalConverter = matrixHalConverter;
743 const XmlConverter<ManifestHal> &gManifestHalConverter = manifestHalConverter;
744 
745 } // namespace vintf
746 } // namespace android
747