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
24namespace android {
25namespace vintf {
26
27// --------------- tinyxml2 details
28
29using NodeType = tinyxml2::XMLElement;
30using DocType = tinyxml2::XMLDocument;
31
32// caller is responsible for deleteDocument() call
33inline DocType *createDocument() {
34    return new tinyxml2::XMLDocument();
35}
36
37// caller is responsible for deleteDocument() call
38inline 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
47inline void deleteDocument(DocType *d) {
48    delete d;
49}
50
51inline std::string printDocument(DocType *d) {
52    tinyxml2::XMLPrinter p;
53    d->Print(&p);
54    return std::string{p.CStr()};
55}
56
57inline NodeType *createNode(const std::string &name, DocType *d) {
58    return d->NewElement(name.c_str());
59}
60
61inline void appendChild(NodeType *parent, NodeType *child) {
62    parent->InsertEndChild(child);
63}
64
65inline void appendChild(DocType *parent, NodeType *child) {
66    parent->InsertEndChild(child);
67}
68
69inline 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
74inline void appendText(NodeType *parent, const std::string &text, DocType *d) {
75    parent->InsertEndChild(d->NewText(text.c_str()));
76}
77
78inline std::string nameOf(NodeType *root) {
79    return root->Name() == NULL ? "" : root->Name();
80}
81
82inline std::string getText(NodeType *root) {
83    return root->GetText() == NULL ? "" : root->GetText();
84}
85
86inline NodeType *getChild(NodeType *parent, const std::string &name) {
87    return parent->FirstChildElement(name.c_str());
88}
89
90inline NodeType *getRootChild(DocType *parent) {
91    return parent->FirstChildElement();
92}
93
94inline 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
104inline 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
115static 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
129template<typename Object>
130struct XmlNodeConverter : public XmlConverter<Object> {
131    XmlNodeConverter() {}
132    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
140    inline const std::string &lastError() const { return mLastError; }
141    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    }
146    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    }
153    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    }
159    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    }
169    inline NodeType *operator()(const Object &o, DocType *d) const {
170        return serialize(o, d);
171    }
172    inline std::string operator()(const Object &o) const {
173        return serialize(o);
174    }
175    inline bool operator()(Object *o, NodeType *node) const {
176        return deserialize(o, node);
177    }
178    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>
186    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
190    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>
195    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>
204    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>
214    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>
225    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>
237    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
247    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
256    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
268    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>
279    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>
294    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>
309    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>
323    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
339    inline bool parseText(NodeType *node, std::string *s) const {
340        *s = getText(node);
341        return true;
342    }
343
344    template <typename T>
345    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    }
353protected:
354    mutable std::string mLastError;
355};
356
357template<typename Object>
358struct XmlTextConverter : public XmlNodeConverter<Object> {
359    XmlTextConverter(const std::string &elementName)
360        : mElementName(elementName) {}
361
362    virtual void mutateNode(const Object &object, NodeType *root, DocType *d) const override {
363        appendText(root, ::android::vintf::to_string(object), d);
364    }
365    virtual bool buildObject(Object *object, NodeType *root) const override {
366        return this->parseText(root, object);
367    }
368    virtual std::string elementName() const { return mElementName; };
369private:
370    std::string mElementName;
371};
372
373// ---------------------- XmlNodeConverter definitions end
374
375const XmlTextConverter<Version> versionConverter{"version"};
376
377const XmlTextConverter<VersionRange> versionRangeConverter{"version"};
378
379const XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"};
380
381struct TransportArchConverter : public XmlNodeConverter<TransportArch> {
382    std::string elementName() const override { return "transport"; }
383    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    }
389    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
404const TransportArchConverter transportArchConverter{};
405
406struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> {
407    std::string elementName() const override { return "value"; }
408    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    }
412    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
426const KernelConfigTypedValueConverter kernelConfigTypedValueConverter{};
427
428struct KernelConfigConverter : public XmlNodeConverter<KernelConfig> {
429    std::string elementName() const override { return "config"; }
430    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    }
434    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
443const KernelConfigConverter kernelConfigConverter{};
444
445struct HalInterfaceConverter : public XmlNodeConverter<HalInterface> {
446    std::string elementName() const override { return "interface"; }
447    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    }
451    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
467const HalInterfaceConverter halInterfaceConverter{};
468
469struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
470    std::string elementName() const override { return "hal"; }
471    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    }
478    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
499const MatrixHalConverter matrixHalConverter{};
500
501struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
502    std::string elementName() const override { return "kernel"; }
503    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    }
507    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
516const MatrixKernelConverter matrixKernelConverter{};
517
518struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
519    std::string elementName() const override { return "hal"; }
520    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    }
529    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.
557const ManifestHalConverter manifestHalConverter{};
558
559const XmlTextConverter<KernelSepolicyVersion> kernelSepolicyVersionConverter{"kernel-sepolicy-version"};
560const XmlTextConverter<VersionRange> sepolicyVersionConverter{"sepolicy-version"};
561
562struct SepolicyConverter : public XmlNodeConverter<Sepolicy> {
563    std::string elementName() const override { return "sepolicy"; }
564    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    }
568    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};
576const SepolicyConverter sepolicyConverter{};
577
578const XmlTextConverter<VndkVersionRange> vndkVersionRangeConverter{"version"};
579const XmlTextConverter<std::string> vndkLibraryConverter{"library"};
580
581struct VndkConverter : public XmlNodeConverter<Vndk> {
582    std::string elementName() const override { return "vndk"; }
583    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    }
587    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
596const VndkConverter vndkConverter{};
597
598struct HalManifestSepolicyConverter : public XmlNodeConverter<Version> {
599    std::string elementName() const override { return "sepolicy"; }
600    void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
601        appendChild(root, versionConverter(m, d));
602    }
603    bool buildObject(Version *object, NodeType *root) const override {
604        return parseChild(root, versionConverter, object);
605    }
606};
607const HalManifestSepolicyConverter halManifestSepolicyConverter{};
608
609struct HalManifestConverter : public XmlNodeConverter<HalManifest> {
610    std::string elementName() const override { return "manifest"; }
611    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    }
621    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
664const HalManifestConverter halManifestConverter{};
665
666const XmlTextConverter<Version> avbVersionConverter{"vbmeta-version"};
667struct AvbConverter : public XmlNodeConverter<Version> {
668    std::string elementName() const override { return "avb"; }
669    void mutateNode(const Version &m, NodeType *root, DocType *d) const override {
670        appendChild(root, avbVersionConverter(m, d));
671    }
672    bool buildObject(Version *object, NodeType *root) const override {
673        return parseChild(root, avbVersionConverter, object);
674    }
675};
676const AvbConverter avbConverter{};
677
678struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> {
679    std::string elementName() const override { return "compatibility-matrix"; }
680    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    }
692    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
731const CompatibilityMatrixConverter compatibilityMatrixConverter{};
732
733// Publicly available as in parse_xml.h
734const XmlConverter<HalManifest> &gHalManifestConverter = halManifestConverter;
735const XmlConverter<CompatibilityMatrix> &gCompatibilityMatrixConverter
736        = compatibilityMatrixConverter;
737
738// For testing in LibVintfTest
739const XmlConverter<Version> &gVersionConverter = versionConverter;
740const XmlConverter<KernelConfigTypedValue> &gKernelConfigTypedValueConverter
741        = kernelConfigTypedValueConverter;
742const XmlConverter<MatrixHal> &gMatrixHalConverter = matrixHalConverter;
743const XmlConverter<ManifestHal> &gManifestHalConverter = manifestHalConverter;
744
745} // namespace vintf
746} // namespace android
747