blob: b769c76206587de8ff094ad80abe19e44f89ab17 [file] [log] [blame]
Adam Lesinski75f3a552015-06-03 14:54:23 -07001/*
2 * Copyright (C) 2015 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
Adam Lesinski1ab598f2015-08-14 14:26:04 -070017#include "util/Util.h"
Adam Lesinski75f3a552015-06-03 14:54:23 -070018#include "XmlDom.h"
19#include "XmlPullParser.h"
20
21#include <cassert>
22#include <memory>
23#include <stack>
24#include <string>
25#include <tuple>
26
27namespace aapt {
28namespace xml {
29
30constexpr char kXmlNamespaceSep = 1;
31
32struct Stack {
33 std::unique_ptr<xml::Node> root;
34 std::stack<xml::Node*> nodeStack;
35 std::u16string pendingComment;
36};
37
38/**
39 * Extracts the namespace and name of an expanded element or attribute name.
40 */
41static void splitName(const char* name, std::u16string* outNs, std::u16string* outName) {
42 const char* p = name;
43 while (*p != 0 && *p != kXmlNamespaceSep) {
44 p++;
45 }
46
47 if (*p == 0) {
48 outNs->clear();
49 *outName = util::utf8ToUtf16(name);
50 } else {
51 *outNs = util::utf8ToUtf16(StringPiece(name, (p - name)));
52 *outName = util::utf8ToUtf16(p + 1);
53 }
54}
55
56static void addToStack(Stack* stack, XML_Parser parser, std::unique_ptr<Node> node) {
57 node->lineNumber = XML_GetCurrentLineNumber(parser);
58 node->columnNumber = XML_GetCurrentColumnNumber(parser);
59
60 Node* thisNode = node.get();
61 if (!stack->nodeStack.empty()) {
62 stack->nodeStack.top()->addChild(std::move(node));
63 } else {
64 stack->root = std::move(node);
65 }
66
Adam Lesinski1ab598f2015-08-14 14:26:04 -070067 if (!nodeCast<Text>(thisNode)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -070068 stack->nodeStack.push(thisNode);
69 }
70}
71
72static void XMLCALL startNamespaceHandler(void* userData, const char* prefix, const char* uri) {
73 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
74 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
75
76 std::unique_ptr<Namespace> ns = util::make_unique<Namespace>();
77 if (prefix) {
78 ns->namespacePrefix = util::utf8ToUtf16(prefix);
79 }
80
81 if (uri) {
82 ns->namespaceUri = util::utf8ToUtf16(uri);
83 }
84
85 addToStack(stack, parser, std::move(ns));
86}
87
88static void XMLCALL endNamespaceHandler(void* userData, const char* prefix) {
89 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
90 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
91
92 assert(!stack->nodeStack.empty());
93 stack->nodeStack.pop();
94}
95
96static bool lessAttribute(const Attribute& lhs, const Attribute& rhs) {
97 return std::tie(lhs.namespaceUri, lhs.name, lhs.value) <
98 std::tie(rhs.namespaceUri, rhs.name, rhs.value);
99}
100
101static void XMLCALL startElementHandler(void* userData, const char* name, const char** attrs) {
102 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
103 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
104
105 std::unique_ptr<Element> el = util::make_unique<Element>();
106 splitName(name, &el->namespaceUri, &el->name);
107
108 while (*attrs) {
109 Attribute attribute;
110 splitName(*attrs++, &attribute.namespaceUri, &attribute.name);
111 attribute.value = util::utf8ToUtf16(*attrs++);
112
113 // Insert in sorted order.
114 auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(), attribute,
115 lessAttribute);
116 el->attributes.insert(iter, std::move(attribute));
117 }
118
119 el->comment = std::move(stack->pendingComment);
120 addToStack(stack, parser, std::move(el));
121}
122
123static void XMLCALL endElementHandler(void* userData, const char* name) {
124 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
125 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
126
127 assert(!stack->nodeStack.empty());
Adam Lesinskica5638f2015-10-21 14:42:43 -0700128 //stack->nodeStack.top()->comment = std::move(stack->pendingComment);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700129 stack->nodeStack.pop();
130}
131
132static void XMLCALL characterDataHandler(void* userData, const char* s, int len) {
133 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
134 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
135
136 if (!s || len <= 0) {
137 return;
138 }
139
140 // See if we can just append the text to a previous text node.
141 if (!stack->nodeStack.empty()) {
142 Node* currentParent = stack->nodeStack.top();
143 if (!currentParent->children.empty()) {
144 Node* lastChild = currentParent->children.back().get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700145 if (Text* text = nodeCast<Text>(lastChild)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700146 text->text += util::utf8ToUtf16(StringPiece(s, len));
147 return;
148 }
149 }
150 }
151
152 std::unique_ptr<Text> text = util::make_unique<Text>();
153 text->text = util::utf8ToUtf16(StringPiece(s, len));
154 addToStack(stack, parser, std::move(text));
155}
156
157static void XMLCALL commentDataHandler(void* userData, const char* comment) {
158 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
159 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
160
161 if (!stack->pendingComment.empty()) {
162 stack->pendingComment += '\n';
163 }
164 stack->pendingComment += util::utf8ToUtf16(comment);
165}
166
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700167std::unique_ptr<XmlResource> inflate(std::istream* in, IDiagnostics* diag, const Source& source) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700168 Stack stack;
169
170 XML_Parser parser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
171 XML_SetUserData(parser, &stack);
172 XML_UseParserAsHandlerArg(parser);
173 XML_SetElementHandler(parser, startElementHandler, endElementHandler);
174 XML_SetNamespaceDeclHandler(parser, startNamespaceHandler, endNamespaceHandler);
175 XML_SetCharacterDataHandler(parser, characterDataHandler);
176 XML_SetCommentHandler(parser, commentDataHandler);
177
178 char buffer[1024];
179 while (!in->eof()) {
180 in->read(buffer, sizeof(buffer) / sizeof(buffer[0]));
181 if (in->bad() && !in->eof()) {
182 stack.root = {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700183 diag->error(DiagMessage(source) << strerror(errno));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700184 break;
185 }
186
187 if (XML_Parse(parser, buffer, in->gcount(), in->eof()) == XML_STATUS_ERROR) {
188 stack.root = {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700189 diag->error(DiagMessage(source.withLine(XML_GetCurrentLineNumber(parser)))
190 << XML_ErrorString(XML_GetErrorCode(parser)));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700191 break;
192 }
193 }
194
195 XML_ParserFree(parser);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700196 if (stack.root) {
Adam Lesinskica5638f2015-10-21 14:42:43 -0700197 return util::make_unique<XmlResource>(ResourceFile{ {}, {}, source }, std::move(stack.root));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700198 }
199 return {};
Adam Lesinski75f3a552015-06-03 14:54:23 -0700200}
201
202static void copyAttributes(Element* el, android::ResXMLParser* parser) {
203 const size_t attrCount = parser->getAttributeCount();
204 if (attrCount > 0) {
205 el->attributes.reserve(attrCount);
206 for (size_t i = 0; i < attrCount; i++) {
207 Attribute attr;
208 size_t len;
209 const char16_t* str16 = parser->getAttributeNamespace(i, &len);
210 if (str16) {
211 attr.namespaceUri.assign(str16, len);
212 }
213
214 str16 = parser->getAttributeName(i, &len);
215 if (str16) {
216 attr.name.assign(str16, len);
217 }
218
219 str16 = parser->getAttributeStringValue(i, &len);
220 if (str16) {
221 attr.value.assign(str16, len);
222 }
223 el->attributes.push_back(std::move(attr));
224 }
225 }
226}
227
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700228std::unique_ptr<XmlResource> inflate(const void* data, size_t dataLen, IDiagnostics* diag,
229 const Source& source) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700230 std::unique_ptr<Node> root;
231 std::stack<Node*> nodeStack;
232
233 android::ResXMLTree tree;
234 if (tree.setTo(data, dataLen) != android::NO_ERROR) {
235 return {};
236 }
237
238 android::ResXMLParser::event_code_t code;
239 while ((code = tree.next()) != android::ResXMLParser::BAD_DOCUMENT &&
240 code != android::ResXMLParser::END_DOCUMENT) {
241 std::unique_ptr<Node> newNode;
242 switch (code) {
243 case android::ResXMLParser::START_NAMESPACE: {
244 std::unique_ptr<Namespace> node = util::make_unique<Namespace>();
245 size_t len;
246 const char16_t* str16 = tree.getNamespacePrefix(&len);
247 if (str16) {
248 node->namespacePrefix.assign(str16, len);
249 }
250
251 str16 = tree.getNamespaceUri(&len);
252 if (str16) {
253 node->namespaceUri.assign(str16, len);
254 }
255 newNode = std::move(node);
256 break;
257 }
258
259 case android::ResXMLParser::START_TAG: {
260 std::unique_ptr<Element> node = util::make_unique<Element>();
261 size_t len;
262 const char16_t* str16 = tree.getElementNamespace(&len);
263 if (str16) {
264 node->namespaceUri.assign(str16, len);
265 }
266
267 str16 = tree.getElementName(&len);
268 if (str16) {
269 node->name.assign(str16, len);
270 }
271
272 copyAttributes(node.get(), &tree);
273
274 newNode = std::move(node);
275 break;
276 }
277
278 case android::ResXMLParser::TEXT: {
279 std::unique_ptr<Text> node = util::make_unique<Text>();
280 size_t len;
281 const char16_t* str16 = tree.getText(&len);
282 if (str16) {
283 node->text.assign(str16, len);
284 }
285 newNode = std::move(node);
286 break;
287 }
288
289 case android::ResXMLParser::END_NAMESPACE:
290 case android::ResXMLParser::END_TAG:
291 assert(!nodeStack.empty());
292 nodeStack.pop();
293 break;
294
295 default:
296 assert(false);
297 break;
298 }
299
300 if (newNode) {
301 newNode->lineNumber = tree.getLineNumber();
302
303 Node* thisNode = newNode.get();
304 if (!root) {
305 assert(nodeStack.empty());
306 root = std::move(newNode);
307 } else {
308 assert(!nodeStack.empty());
309 nodeStack.top()->addChild(std::move(newNode));
310 }
311
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700312 if (!nodeCast<Text>(thisNode)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700313 nodeStack.push(thisNode);
314 }
315 }
316 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700317 return util::make_unique<XmlResource>(ResourceFile{}, std::move(root));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700318}
319
Adam Lesinskica5638f2015-10-21 14:42:43 -0700320Element* findRootElement(Node* node) {
321 if (!node) {
322 return nullptr;
323 }
324
325 Element* el = nullptr;
326 while ((el = nodeCast<Element>(node)) == nullptr) {
327 if (node->children.empty()) {
328 return nullptr;
329 }
330 // We are looking for the first element, and namespaces can only have one child.
331 node = node->children.front().get();
332 }
333 return el;
334}
335
Adam Lesinski75f3a552015-06-03 14:54:23 -0700336void Node::addChild(std::unique_ptr<Node> child) {
337 child->parent = this;
338 children.push_back(std::move(child));
339}
340
Adam Lesinski75f3a552015-06-03 14:54:23 -0700341Attribute* Element::findAttribute(const StringPiece16& ns, const StringPiece16& name) {
342 for (auto& attr : attributes) {
343 if (ns == attr.namespaceUri && name == attr.name) {
344 return &attr;
345 }
346 }
347 return nullptr;
348}
349
350Element* Element::findChild(const StringPiece16& ns, const StringPiece16& name) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700351 return findChildWithAttribute(ns, name, {}, {}, {});
Adam Lesinski75f3a552015-06-03 14:54:23 -0700352}
353
354Element* Element::findChildWithAttribute(const StringPiece16& ns, const StringPiece16& name,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700355 const StringPiece16& attrNs, const StringPiece16& attrName,
356 const StringPiece16& attrValue) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700357 for (auto& childNode : children) {
358 Node* child = childNode.get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700359 while (nodeCast<Namespace>(child)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700360 if (child->children.empty()) {
361 break;
362 }
363 child = child->children[0].get();
364 }
365
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700366 if (Element* el = nodeCast<Element>(child)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700367 if (ns == el->namespaceUri && name == el->name) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700368 if (attrNs.empty() && attrName.empty()) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700369 return el;
370 }
371
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700372 Attribute* attr = el->findAttribute(attrNs, attrName);
373 if (attr && attrValue == attr->value) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700374 return el;
375 }
376 }
377 }
378 }
379 return nullptr;
380}
381
382std::vector<Element*> Element::getChildElements() {
383 std::vector<Element*> elements;
384 for (auto& childNode : children) {
385 Node* child = childNode.get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700386 while (nodeCast<Namespace>(child)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700387 if (child->children.empty()) {
388 break;
389 }
390 child = child->children[0].get();
391 }
392
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700393 if (Element* el = nodeCast<Element>(child)) {
394 elements.push_back(el);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700395 }
396 }
397 return elements;
398}
399
Adam Lesinski75f3a552015-06-03 14:54:23 -0700400} // namespace xml
401} // namespace aapt