blob: bacae6cf41bb7f3aff2970048925ca9d07bcab1a [file] [log] [blame]
Yifan Hong676447a2016-11-15 12:57:23 -08001/*
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
78// text -> <name>text</name>
79inline void appendTextElement(NodeType *parent, const std::string &name,
80 const std::string &text, DocType *d) {
81 NodeType *c = createNode(name, d);
82 appendText(c, text, d);
83 appendChild(parent, c);
84}
85
86inline std::string nameOf(NodeType *root) {
Yifan Hongcd41ffc2017-01-20 13:46:32 -080087 return root->Name() == NULL ? "" : root->Name();
Yifan Hong676447a2016-11-15 12:57:23 -080088}
89
90inline std::string getText(NodeType *root) {
Yifan Hongcd41ffc2017-01-20 13:46:32 -080091 return root->GetText() == NULL ? "" : root->GetText();
Yifan Hong676447a2016-11-15 12:57:23 -080092}
93
94inline NodeType *getChild(NodeType *parent, const std::string &name) {
95 return parent->FirstChildElement(name.c_str());
96}
97
98inline NodeType *getRootChild(DocType *parent) {
99 return parent->FirstChildElement();
100}
101
102inline std::vector<NodeType *> getChildren(NodeType *parent, const std::string &name) {
103 std::vector<NodeType *> v;
104 for (NodeType *child = parent->FirstChildElement(name.c_str());
105 child != nullptr;
106 child = child->NextSiblingElement(name.c_str())) {
107 v.push_back(child);
108 }
109 return v;
110}
111
112inline bool getAttr(NodeType *root, const std::string &attrName, std::string *s) {
113 const char *c = root->Attribute(attrName.c_str());
114 if (c == NULL)
115 return false;
116 *s = c;
117 return true;
118}
119
120// --------------- tinyxml2 details end.
121
122// ---------------------- XmlNodeConverter definitions
123
124template<typename Object>
125struct XmlNodeConverter : public XmlConverter<Object> {
126 XmlNodeConverter() {}
127 virtual ~XmlNodeConverter() {}
128
129 // sub-types should implement these.
130 virtual void mutateNode(const Object &o, NodeType *n, DocType *d) const = 0;
131 virtual bool buildObject(Object *o, NodeType *n) const = 0;
132 virtual std::string elementName() const = 0;
133
134 // convenience methods for user
135 inline const std::string &lastError() const { return mLastError; }
136 inline NodeType *serialize(const Object &o, DocType *d) const {
137 NodeType *root = createNode(this->elementName(), d);
138 this->mutateNode(o, root, d);
139 return root;
140 }
141 inline std::string serialize(const Object &o) const {
142 DocType *doc = createDocument();
143 appendChild(doc, serialize(o, doc));
144 std::string s = printDocument(doc);
145 deleteDocument(doc);
146 return s;
147 }
148 inline bool deserialize(Object *object, NodeType *root) const {
149 if (nameOf(root) != this->elementName()) {
150 return false;
151 }
152 return this->buildObject(object, root);
153 }
154 inline bool deserialize(Object *o, const std::string &xml) const {
155 DocType *doc = createDocument(xml);
156 bool ret = doc != nullptr
157 && deserialize(o, getRootChild(doc));
158 deleteDocument(doc);
159 return ret;
160 }
161 inline NodeType *operator()(const Object &o, DocType *d) const {
162 return serialize(o, d);
163 }
164 inline std::string operator()(const Object &o) const {
165 return serialize(o);
166 }
167 inline bool operator()(Object *o, NodeType *node) const {
168 return deserialize(o, node);
169 }
170 inline bool operator()(Object *o, const std::string &xml) const {
171 return deserialize(o, xml);
172 }
173
174 // convenience methods for implementor.
175 template <typename T>
176 inline void appendAttr(NodeType *e, const std::string &attrName, const T &attr) const {
177 return appendStrAttr(e, attrName, ::android::vintf::to_string(attr));
178 }
179
180 inline void appendAttr(NodeType *e, const std::string &attrName, bool attr) const {
181 return appendStrAttr(e, attrName, attr ? "true" : "false");
182 }
183
184 template <typename T>
185 inline bool parseAttr(NodeType *root, const std::string &attrName, T *attr) const {
186 std::string attrText;
187 bool ret = getAttr(root, attrName, &attrText) && ::android::vintf::parse(attrText, attr);
188 if (!ret) {
189 mLastError = "Could not parse attr with name " + attrName;
190 }
191 return ret;
192 }
193
194 inline bool parseAttr(NodeType *root, const std::string &attrName, std::string *attr) const {
195 bool ret = getAttr(root, attrName, attr);
196 if (!ret) {
197 mLastError = "Could not find attr with name " + attrName;
198 }
199 return ret;
200 }
201
202 inline bool parseAttr(NodeType *root, const std::string &attrName, bool *attr) const {
203 std::string attrText;
204 if (!getAttr(root, attrName, &attrText)) {
205 mLastError = "Could not find attr with name " + attrName;
206 return false;
207 }
208 if (attrText == "true" || attrText == "1") {
209 *attr = true;
210 return true;
211 }
212 if (attrText == "false" || attrText == "0") {
213 *attr = false;
214 return true;
215 }
216 mLastError = "Could not parse attr with name \"" + attrName
217 + "\" and value \"" + attrText + "\"";
218 return false;
219 }
220
221 inline bool parseTextElement(NodeType *root,
222 const std::string &elementName, std::string *s) const {
223 NodeType *child = getChild(root, elementName);
224 if (child == nullptr) {
225 mLastError = "Could not find element with name " + elementName;
226 return false;
227 }
228 *s = getText(child);
229 return true;
230 }
231
232 template <typename T>
233 inline bool parseChild(NodeType *root, const XmlNodeConverter<T> &conv, T *t) const {
234 NodeType *child = getChild(root, conv.elementName());
235 if (child == nullptr) {
236 mLastError = "Could not find element with name " + conv.elementName();
237 return false;
238 }
239 bool success = conv.deserialize(t, child);
240 if (!success) {
241 mLastError = conv.lastError();
242 }
243 return success;
244 }
245
246 template <typename T>
247 inline bool parseChildren(NodeType *root, const XmlNodeConverter<T> &conv, std::vector<T> *v) const {
248 auto nodes = getChildren(root, conv.elementName());
249 v->resize(nodes.size());
250 for (size_t i = 0; i < nodes.size(); ++i) {
251 if (!conv.deserialize(&v->at(i), nodes[i])) {
252 mLastError = "Could not parse element with name " + conv.elementName();
253 return false;
254 }
255 }
256 return true;
257 }
258
259 inline bool parseText(NodeType *node, std::string *s) const {
260 *s = getText(node);
261 return true;
262 }
263
264protected:
265 mutable std::string mLastError;
266};
267
268template<typename Object>
269struct XmlTextConverter : public XmlNodeConverter<Object> {
270 XmlTextConverter(const std::string &elementName)
271 : mElementName(elementName) {}
272
273 virtual void mutateNode(const Object &object, NodeType *root, DocType *d) const override {
274 appendText(root, ::android::vintf::to_string(object), d);
275 }
276 virtual bool buildObject(Object *object, NodeType *root) const override {
277 std::string text = getText(root);
278 bool ret = ::android::vintf::parse(text, object);
279 if (!ret) {
280 this->mLastError = "Could not parse " + text;
281 }
282 return ret;
283 }
284 virtual std::string elementName() const { return mElementName; };
285private:
286 std::string mElementName;
287};
288
289// ---------------------- XmlNodeConverter definitions end
290
291const XmlTextConverter<Version> versionConverter{"version"};
292const XmlConverter<Version> &gVersionConverter = versionConverter;
293
294const XmlTextConverter<VersionRange> versionRangeConverter{"version"};
295const XmlConverter<VersionRange> &gVersionRangeConverter = versionRangeConverter;
296
Yifan Hong676447a2016-11-15 12:57:23 -0800297const XmlTextConverter<Transport> transportConverter{"transport"};
298const XmlConverter<Transport> &gTransportConverter = transportConverter;
299
Yifan Hong3f5489a2017-02-08 11:14:21 -0800300const XmlTextConverter<KernelConfigKey> kernelConfigKeyConverter{"key"};
301
302struct KernelConfigTypedValueConverter : public XmlNodeConverter<KernelConfigTypedValue> {
303 std::string elementName() const override { return "value"; }
304 void mutateNode(const KernelConfigTypedValue &object, NodeType *root, DocType *d) const override {
305 appendAttr(root, "type", object.mType);
306 appendText(root, ::android::vintf::to_string(object), d);
307 }
308 bool buildObject(KernelConfigTypedValue *object, NodeType *root) const override {
309 std::string stringValue;
310 if (!parseAttr(root, "type", &object->mType) ||
311 !parseText(root, &stringValue)) {
312 return false;
313 }
314 if (!::android::vintf::parseKernelConfigValue(stringValue, object)) {
315 return false;
316 }
317 return true;
318 }
319};
320
321const KernelConfigTypedValueConverter kernelConfigTypedValueConverter{};
322const XmlConverter<KernelConfigTypedValue> &gKernelConfigTypedValueConverter = kernelConfigTypedValueConverter;
323
324struct KernelConfigConverter : public XmlNodeConverter<KernelConfig> {
325 std::string elementName() const override { return "config"; }
326 void mutateNode(const KernelConfig &object, NodeType *root, DocType *d) const override {
327 appendChild(root, kernelConfigKeyConverter(object.first, d));
328 appendChild(root, kernelConfigTypedValueConverter(object.second, d));
329 }
330 bool buildObject(KernelConfig *object, NodeType *root) const override {
331 if ( !parseChild(root, kernelConfigKeyConverter, &object->first)
332 || !parseChild(root, kernelConfigTypedValueConverter, &object->second)) {
333 return false;
334 }
335 return true;
336 }
337};
338
339const KernelConfigConverter kernelConfigConverter{};
340
Yifan Honga9993572017-01-24 19:33:15 -0800341struct MatrixHalConverter : public XmlNodeConverter<MatrixHal> {
Yifan Hong676447a2016-11-15 12:57:23 -0800342 std::string elementName() const override { return "hal"; }
343 void mutateNode(const MatrixHal &hal, NodeType *root, DocType *d) const override {
344 appendAttr(root, "format", hal.format);
345 appendAttr(root, "optional", hal.optional);
346 appendTextElement(root, "name", hal.name, d);
347 for (const auto &version : hal.versionRanges) {
348 appendChild(root, versionRangeConverter(version, d));
349 }
350 }
351 bool buildObject(MatrixHal *object, NodeType *root) const override {
Yifan Honga70b2742017-02-16 17:43:04 -0800352 if (!parseAttr(root, "format", &object->format) ||
353 !parseAttr(root, "optional", &object->optional) ||
354 !parseTextElement(root, "name", &object->name) ||
355 !parseChildren(root, versionRangeConverter, &object->versionRanges)) {
Yifan Hong676447a2016-11-15 12:57:23 -0800356 return false;
357 }
358 return true;
359 }
360};
361
362const MatrixHalConverter matrixHalConverter{};
363const XmlConverter<MatrixHal> &gMatrixHalConverter = matrixHalConverter;
364
Yifan Honga9993572017-01-24 19:33:15 -0800365struct MatrixKernelConverter : public XmlNodeConverter<MatrixKernel> {
Yifan Hong676447a2016-11-15 12:57:23 -0800366 std::string elementName() const override { return "kernel"; }
367 void mutateNode(const MatrixKernel &kernel, NodeType *root, DocType *d) const override {
Yifan Hong3f5489a2017-02-08 11:14:21 -0800368 appendAttr(root, "version", Version{kernel.mMinLts.version, kernel.mMinLts.majorRev});
369 appendAttr(root, "minlts", kernel.mMinLts);
370 for (const KernelConfig &config : kernel.mConfigs) {
Yifan Hong676447a2016-11-15 12:57:23 -0800371 appendChild(root, kernelConfigConverter(config, d));
372 }
373 }
374 bool buildObject(MatrixKernel *object, NodeType *root) const override {
Yifan Hong3f5489a2017-02-08 11:14:21 -0800375 Version v;
Yifan Honga70b2742017-02-16 17:43:04 -0800376 if (!parseAttr(root, "minlts", &object->mMinLts) ||
377 !parseAttr(root, "version", &v) ||
378 !parseChildren(root, kernelConfigConverter, &object->mConfigs)) {
Yifan Hong3f5489a2017-02-08 11:14:21 -0800379 return false;
380 }
381 if (v != Version{object->mMinLts.version, object->mMinLts.majorRev}) {
Yifan Hong676447a2016-11-15 12:57:23 -0800382 return false;
383 }
384 return true;
385 }
386};
387
388const MatrixKernelConverter matrixKernelConverter{};
389const XmlConverter<MatrixKernel> &gMatrixKernelConverter = matrixKernelConverter;
390
Yifan Honga9993572017-01-24 19:33:15 -0800391struct HalImplementationConverter : public XmlNodeConverter<HalImplementation> {
Yifan Hong676447a2016-11-15 12:57:23 -0800392 std::string elementName() const override { return "impl"; }
393 void mutateNode(const HalImplementation &impl, NodeType *root, DocType *d) const override {
394 appendAttr(root, "level", impl.implLevel);
395 appendText(root, impl.impl, d);
396 }
397 bool buildObject(HalImplementation *object, NodeType *root) const override {
Yifan Honga70b2742017-02-16 17:43:04 -0800398 if (!parseAttr(root, "level", &object->implLevel) ||
399 !parseText(root, &object->impl)) {
Yifan Hong676447a2016-11-15 12:57:23 -0800400 return false;
401 }
402 return true;
403 }
404};
405
406const HalImplementationConverter halImplementationConverter{};
407const XmlConverter<HalImplementation> &gHalImplementationConverter = halImplementationConverter;
408
Yifan Honga9993572017-01-24 19:33:15 -0800409struct ManifestHalConverter : public XmlNodeConverter<ManifestHal> {
Yifan Hong676447a2016-11-15 12:57:23 -0800410 std::string elementName() const override { return "hal"; }
411 void mutateNode(const ManifestHal &hal, NodeType *root, DocType *d) const override {
412 appendAttr(root, "format", hal.format);
413 appendTextElement(root, "name", hal.name, d);
414 appendChild(root, transportConverter(hal.transport, d));
415 appendChild(root,
416 halImplementationConverter(hal.impl, d));
417 for (const auto &version : hal.versions) {
418 appendChild(root, versionConverter(version, d));
419 }
420 }
421 bool buildObject(ManifestHal *object, NodeType *root) const override {
Yifan Honga70b2742017-02-16 17:43:04 -0800422 if (!parseAttr(root, "format", &object->format) ||
423 !parseTextElement(root, "name", &object->name) ||
424 !parseChild(root, transportConverter, &object->transport) ||
425 !parseChild(root, halImplementationConverter, &object->impl) ||
426 !parseChildren(root, versionConverter, &object->versions)) {
Yifan Hong676447a2016-11-15 12:57:23 -0800427 return false;
428 }
Yifan Hong5a06ef72017-01-24 19:54:24 -0800429 return object->isValid();
Yifan Hong676447a2016-11-15 12:57:23 -0800430 }
431};
432
433const ManifestHalConverter manifestHalConverter{};
434const XmlConverter<ManifestHal> &gManifestHalConverter = manifestHalConverter;
435
Yifan Hong558380a2017-02-09 15:37:32 -0800436const XmlTextConverter<KernelSepolicyVersion> kernelSepolicyVersionConverter{"kernel-sepolicy-version"};
437const XmlTextConverter<SepolicyVersion> sepolicyVersionConverter{"sepolicy-version"};
438
Yifan Honga9993572017-01-24 19:33:15 -0800439struct SepolicyConverter : public XmlNodeConverter<Sepolicy> {
Yifan Hong676447a2016-11-15 12:57:23 -0800440 std::string elementName() const override { return "sepolicy"; }
Yifan Hong558380a2017-02-09 15:37:32 -0800441 void mutateNode(const Sepolicy &object, NodeType *root, DocType *d) const override {
442 appendChild(root, kernelSepolicyVersionConverter(object.kernelSepolicyVersion(), d));
443 appendChild(root, sepolicyVersionConverter(object.sepolicyVersion(), d));
Yifan Hong676447a2016-11-15 12:57:23 -0800444 }
Yifan Hong558380a2017-02-09 15:37:32 -0800445 bool buildObject(Sepolicy *object, NodeType *root) const override {
446 if (!parseChild(root, kernelSepolicyVersionConverter, &object->mKernelSepolicyVersion) ||
447 !parseChild(root, sepolicyVersionConverter, &object->mSepolicyVersion)) {
448 return false;
449 }
Yifan Hong676447a2016-11-15 12:57:23 -0800450 return true;
451 }
452};
453const SepolicyConverter sepolicyConverter{};
454const XmlConverter<Sepolicy> &gSepolicyConverter = sepolicyConverter;
455
Yifan Honga9993572017-01-24 19:33:15 -0800456struct VendorManifestConverter : public XmlNodeConverter<VendorManifest> {
Yifan Hong676447a2016-11-15 12:57:23 -0800457 std::string elementName() const override { return "manifest"; }
458 void mutateNode(const VendorManifest &m, NodeType *root, DocType *d) const override {
459 appendAttr(root, "version", VendorManifest::kVersion);
Yifan Hongef6d4d32017-01-23 14:12:28 -0800460 for (const auto &hal : m.getHals()) {
461 appendChild(root, manifestHalConverter(hal, d));
Yifan Hong676447a2016-11-15 12:57:23 -0800462 }
463 }
464 bool buildObject(VendorManifest *object, NodeType *root) const override {
465 std::vector<ManifestHal> hals;
466 if (!parseChildren(root, manifestHalConverter, &hals)) {
467 return false;
468 }
469 for (auto &&hal : hals) {
470 object->add(std::move(hal));
471 }
472 return true;
473 }
474};
475
476const VendorManifestConverter vendorManifestConverter{};
477const XmlConverter<VendorManifest> &gVendorManifestConverter = vendorManifestConverter;
478
Yifan Honga9993572017-01-24 19:33:15 -0800479struct CompatibilityMatrixConverter : public XmlNodeConverter<CompatibilityMatrix> {
Yifan Hong676447a2016-11-15 12:57:23 -0800480 std::string elementName() const override { return "compatibility-matrix"; }
481 void mutateNode(const CompatibilityMatrix &m, NodeType *root, DocType *d) const override {
482 appendAttr(root, "version", CompatibilityMatrix::kVersion);
Yifan Hongec342862017-02-16 17:57:06 -0800483 for (const auto &pair : m.mHals) {
Yifan Hong676447a2016-11-15 12:57:23 -0800484 appendChild(root, matrixHalConverter(pair.second, d));
485 }
Yifan Hongec342862017-02-16 17:57:06 -0800486 for (const auto &kernel : m.mKernels) {
Yifan Hong676447a2016-11-15 12:57:23 -0800487 appendChild(root, matrixKernelConverter(kernel, d));
488 }
Yifan Hongec342862017-02-16 17:57:06 -0800489 appendChild(root, sepolicyConverter(m.mSepolicy, d));
Yifan Hong676447a2016-11-15 12:57:23 -0800490 }
491 bool buildObject(CompatibilityMatrix *object, NodeType *root) const override {
492 std::vector<MatrixHal> hals;
Yifan Honga70b2742017-02-16 17:43:04 -0800493 if (!parseChildren(root, matrixHalConverter, &hals) ||
Yifan Hongec342862017-02-16 17:57:06 -0800494 !parseChildren(root, matrixKernelConverter, &object->mKernels) ||
495 !parseChild(root, sepolicyConverter, &object->mSepolicy)) {
Yifan Hong676447a2016-11-15 12:57:23 -0800496 return false;
497 }
498 for (auto &&hal : hals) {
499 object->add(std::move(hal));
500 }
501 return true;
502 }
503};
504
505const CompatibilityMatrixConverter compatibilityMatrixConverter{};
506const XmlConverter<CompatibilityMatrix> &gCompatibilityMatrixConverter
507 = compatibilityMatrixConverter;
508
509} // namespace vintf
510} // namespace android