1 /*
2 * Copyright (C) 2019 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 #include "idmap2/XmlParser.h"
18
19 #include <iostream>
20 #include <map>
21 #include <memory>
22 #include <string>
23 #include <utility>
24
25 namespace android::idmap2 {
26
27 template <typename T>
get_tree_position(const T & tree)28 ResXMLParser::ResXMLPosition get_tree_position(const T& tree) {
29 ResXMLParser::ResXMLPosition pos{};
30 tree.getPosition(&pos);
31 return pos;
32 }
33
Node(const ResXMLTree & tree)34 XmlParser::Node::Node(const ResXMLTree& tree) : Node(tree, get_tree_position(tree)) {
35 }
Node(const ResXMLTree & tree,const ResXMLParser::ResXMLPosition & pos)36 XmlParser::Node::Node(const ResXMLTree& tree, const ResXMLParser::ResXMLPosition& pos)
37 : parser_(tree) {
38 set_position(pos);
39 }
40
operator ==(const XmlParser::Node & rhs) const41 bool XmlParser::Node::operator==(const XmlParser::Node& rhs) const {
42 ResXMLParser::ResXMLPosition pos = get_position();
43 ResXMLParser::ResXMLPosition rhs_pos = rhs.get_position();
44 return pos.curExt == rhs_pos.curExt && pos.curNode == rhs_pos.curNode &&
45 pos.eventCode == rhs_pos.eventCode;
46 }
47
operator !=(const XmlParser::Node & rhs) const48 bool XmlParser::Node::operator!=(const XmlParser::Node& rhs) const {
49 return !(*this == rhs);
50 }
51
get_position() const52 ResXMLParser::ResXMLPosition XmlParser::Node::get_position() const {
53 return get_tree_position(parser_);
54 }
55
set_position(const ResXMLParser::ResXMLPosition & pos)56 void XmlParser::Node::set_position(const ResXMLParser::ResXMLPosition& pos) {
57 parser_.setPosition(pos);
58 }
59
Seek(bool inner_child)60 bool XmlParser::Node::Seek(bool inner_child) {
61 if (parser_.getEventType() == XmlParser::Event::END_TAG) {
62 return false;
63 }
64
65 ssize_t depth = 0;
66 XmlParser::Event code;
67 while ((code = parser_.next()) != XmlParser::Event::BAD_DOCUMENT &&
68 code != XmlParser::Event::END_DOCUMENT) {
69 if (code == XmlParser::Event::START_TAG) {
70 if (++depth == (inner_child ? 1 : 0)) {
71 return true;
72 }
73 } else if (code == XmlParser::Event::END_TAG) {
74 if (--depth == (inner_child ? -1 : -2)) {
75 return false;
76 }
77 }
78 }
79
80 return false;
81 }
82
event() const83 XmlParser::Event XmlParser::Node::event() const {
84 return parser_.getEventType();
85 }
86
name() const87 std::string XmlParser::Node::name() const {
88 size_t len;
89 const String16 key16(parser_.getElementName(&len));
90 return String8(key16).c_str();
91 }
92
GetAttributeStringValue(const std::string & name) const93 Result<std::string> XmlParser::Node::GetAttributeStringValue(const std::string& name) const {
94 auto value = GetAttributeValue(name);
95 if (!value) {
96 return value.GetError();
97 }
98
99 switch ((*value).dataType) {
100 case Res_value::TYPE_STRING: {
101 size_t len;
102 const String16 value16(parser_.getStrings().stringAt((*value).data, &len));
103 return std::string(String8(value16).c_str());
104 }
105 case Res_value::TYPE_INT_DEC:
106 case Res_value::TYPE_INT_HEX:
107 case Res_value::TYPE_INT_BOOLEAN: {
108 return std::to_string((*value).data);
109 }
110 default:
111 return Error(R"(Failed to convert attribute "%s" value to a string)", name.c_str());
112 }
113 }
114
GetAttributeValue(const std::string & name) const115 Result<Res_value> XmlParser::Node::GetAttributeValue(const std::string& name) const {
116 size_t len;
117 for (size_t i = 0; i < parser_.getAttributeCount(); i++) {
118 const String16 key16(parser_.getAttributeName(i, &len));
119 std::string key = String8(key16).c_str();
120 if (key != name) {
121 continue;
122 }
123
124 Res_value res_value{};
125 if (parser_.getAttributeValue(i, &res_value) == BAD_TYPE) {
126 return Error(R"(Bad value for attribute "%s")", name.c_str());
127 }
128
129 return res_value;
130 }
131
132 return Error(R"(Failed to find attribute "%s")", name.c_str());
133 }
134
Create(const void * data,size_t size,bool copy_data)135 Result<std::unique_ptr<const XmlParser>> XmlParser::Create(const void* data, size_t size,
136 bool copy_data) {
137 auto parser = std::unique_ptr<const XmlParser>(new XmlParser());
138 if (parser->tree_.setTo(data, size, copy_data) != NO_ERROR) {
139 return Error("Malformed xml block");
140 }
141
142 // Find the beginning of the first tag.
143 XmlParser::Event event;
144 while ((event = parser->tree_.next()) != XmlParser::Event::BAD_DOCUMENT &&
145 event != XmlParser::Event::END_DOCUMENT && event != XmlParser::Event::START_TAG) {
146 }
147
148 if (event == XmlParser::Event::END_DOCUMENT) {
149 return Error("Root tag was not be found");
150 }
151
152 if (event == XmlParser::Event::BAD_DOCUMENT) {
153 return Error("Bad xml document");
154 }
155
156 return parser;
157 }
158
~XmlParser()159 XmlParser::~XmlParser() {
160 tree_.uninit();
161 }
162
163 } // namespace android::idmap2
164