blob: 0ce333af31155c0e16bdcf4f2dd4bfbf72a70778 [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 Lesinski75f3a552015-06-03 14:54:23 -070017#include "XmlDom.h"
18#include "XmlPullParser.h"
Adam Lesinski467f1712015-11-16 17:35:44 -080019#include "util/Util.h"
Adam Lesinski75f3a552015-06-03 14:54:23 -070020
21#include <cassert>
Adam Lesinski467f1712015-11-16 17:35:44 -080022#include <expat.h>
Adam Lesinski75f3a552015-06-03 14:54:23 -070023#include <memory>
24#include <stack>
25#include <string>
26#include <tuple>
27
28namespace aapt {
29namespace xml {
30
31constexpr char kXmlNamespaceSep = 1;
32
33struct Stack {
34 std::unique_ptr<xml::Node> root;
35 std::stack<xml::Node*> nodeStack;
36 std::u16string pendingComment;
37};
38
39/**
40 * Extracts the namespace and name of an expanded element or attribute name.
41 */
42static void splitName(const char* name, std::u16string* outNs, std::u16string* outName) {
43 const char* p = name;
44 while (*p != 0 && *p != kXmlNamespaceSep) {
45 p++;
46 }
47
48 if (*p == 0) {
49 outNs->clear();
50 *outName = util::utf8ToUtf16(name);
51 } else {
52 *outNs = util::utf8ToUtf16(StringPiece(name, (p - name)));
53 *outName = util::utf8ToUtf16(p + 1);
54 }
55}
56
57static void addToStack(Stack* stack, XML_Parser parser, std::unique_ptr<Node> node) {
58 node->lineNumber = XML_GetCurrentLineNumber(parser);
59 node->columnNumber = XML_GetCurrentColumnNumber(parser);
60
61 Node* thisNode = node.get();
62 if (!stack->nodeStack.empty()) {
63 stack->nodeStack.top()->addChild(std::move(node));
64 } else {
65 stack->root = std::move(node);
66 }
67
Adam Lesinski1ab598f2015-08-14 14:26:04 -070068 if (!nodeCast<Text>(thisNode)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -070069 stack->nodeStack.push(thisNode);
70 }
71}
72
73static void XMLCALL startNamespaceHandler(void* userData, const char* prefix, const char* uri) {
74 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
75 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
76
77 std::unique_ptr<Namespace> ns = util::make_unique<Namespace>();
78 if (prefix) {
79 ns->namespacePrefix = util::utf8ToUtf16(prefix);
80 }
81
82 if (uri) {
83 ns->namespaceUri = util::utf8ToUtf16(uri);
84 }
85
86 addToStack(stack, parser, std::move(ns));
87}
88
89static void XMLCALL endNamespaceHandler(void* userData, const char* prefix) {
90 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
91 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
92
93 assert(!stack->nodeStack.empty());
94 stack->nodeStack.pop();
95}
96
97static bool lessAttribute(const Attribute& lhs, const Attribute& rhs) {
98 return std::tie(lhs.namespaceUri, lhs.name, lhs.value) <
99 std::tie(rhs.namespaceUri, rhs.name, rhs.value);
100}
101
102static void XMLCALL startElementHandler(void* userData, const char* name, const char** attrs) {
103 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
104 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
105
106 std::unique_ptr<Element> el = util::make_unique<Element>();
107 splitName(name, &el->namespaceUri, &el->name);
108
109 while (*attrs) {
110 Attribute attribute;
111 splitName(*attrs++, &attribute.namespaceUri, &attribute.name);
112 attribute.value = util::utf8ToUtf16(*attrs++);
113
114 // Insert in sorted order.
115 auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(), attribute,
116 lessAttribute);
117 el->attributes.insert(iter, std::move(attribute));
118 }
119
120 el->comment = std::move(stack->pendingComment);
121 addToStack(stack, parser, std::move(el));
122}
123
124static void XMLCALL endElementHandler(void* userData, const char* name) {
125 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
126 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
127
128 assert(!stack->nodeStack.empty());
Adam Lesinskica5638f2015-10-21 14:42:43 -0700129 //stack->nodeStack.top()->comment = std::move(stack->pendingComment);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700130 stack->nodeStack.pop();
131}
132
133static void XMLCALL characterDataHandler(void* userData, const char* s, int len) {
134 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
135 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
136
137 if (!s || len <= 0) {
138 return;
139 }
140
141 // See if we can just append the text to a previous text node.
142 if (!stack->nodeStack.empty()) {
143 Node* currentParent = stack->nodeStack.top();
144 if (!currentParent->children.empty()) {
145 Node* lastChild = currentParent->children.back().get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700146 if (Text* text = nodeCast<Text>(lastChild)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700147 text->text += util::utf8ToUtf16(StringPiece(s, len));
148 return;
149 }
150 }
151 }
152
153 std::unique_ptr<Text> text = util::make_unique<Text>();
154 text->text = util::utf8ToUtf16(StringPiece(s, len));
155 addToStack(stack, parser, std::move(text));
156}
157
158static void XMLCALL commentDataHandler(void* userData, const char* comment) {
159 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
160 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
161
162 if (!stack->pendingComment.empty()) {
163 stack->pendingComment += '\n';
164 }
165 stack->pendingComment += util::utf8ToUtf16(comment);
166}
167
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700168std::unique_ptr<XmlResource> inflate(std::istream* in, IDiagnostics* diag, const Source& source) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700169 Stack stack;
170
171 XML_Parser parser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
172 XML_SetUserData(parser, &stack);
173 XML_UseParserAsHandlerArg(parser);
174 XML_SetElementHandler(parser, startElementHandler, endElementHandler);
175 XML_SetNamespaceDeclHandler(parser, startNamespaceHandler, endNamespaceHandler);
176 XML_SetCharacterDataHandler(parser, characterDataHandler);
177 XML_SetCommentHandler(parser, commentDataHandler);
178
179 char buffer[1024];
180 while (!in->eof()) {
181 in->read(buffer, sizeof(buffer) / sizeof(buffer[0]));
182 if (in->bad() && !in->eof()) {
183 stack.root = {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700184 diag->error(DiagMessage(source) << strerror(errno));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700185 break;
186 }
187
188 if (XML_Parse(parser, buffer, in->gcount(), in->eof()) == XML_STATUS_ERROR) {
189 stack.root = {};
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700190 diag->error(DiagMessage(source.withLine(XML_GetCurrentLineNumber(parser)))
191 << XML_ErrorString(XML_GetErrorCode(parser)));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700192 break;
193 }
194 }
195
196 XML_ParserFree(parser);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700197 if (stack.root) {
Adam Lesinskica5638f2015-10-21 14:42:43 -0700198 return util::make_unique<XmlResource>(ResourceFile{ {}, {}, source }, std::move(stack.root));
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700199 }
200 return {};
Adam Lesinski75f3a552015-06-03 14:54:23 -0700201}
202
203static void copyAttributes(Element* el, android::ResXMLParser* parser) {
204 const size_t attrCount = parser->getAttributeCount();
205 if (attrCount > 0) {
206 el->attributes.reserve(attrCount);
207 for (size_t i = 0; i < attrCount; i++) {
208 Attribute attr;
209 size_t len;
210 const char16_t* str16 = parser->getAttributeNamespace(i, &len);
211 if (str16) {
212 attr.namespaceUri.assign(str16, len);
213 }
214
215 str16 = parser->getAttributeName(i, &len);
216 if (str16) {
217 attr.name.assign(str16, len);
218 }
219
220 str16 = parser->getAttributeStringValue(i, &len);
221 if (str16) {
222 attr.value.assign(str16, len);
223 }
224 el->attributes.push_back(std::move(attr));
225 }
226 }
227}
228
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700229std::unique_ptr<XmlResource> inflate(const void* data, size_t dataLen, IDiagnostics* diag,
230 const Source& source) {
Adam Lesinski803c7c82016-04-06 16:09:43 -0700231 // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which
232 // causes errors when qualifying it with android::
233 using namespace android;
234
Adam Lesinski75f3a552015-06-03 14:54:23 -0700235 std::unique_ptr<Node> root;
236 std::stack<Node*> nodeStack;
237
Adam Lesinski803c7c82016-04-06 16:09:43 -0700238 ResXMLTree tree;
239 if (tree.setTo(data, dataLen) != NO_ERROR) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700240 return {};
241 }
242
Adam Lesinski803c7c82016-04-06 16:09:43 -0700243 ResXMLParser::event_code_t code;
244 while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT &&
245 code != ResXMLParser::END_DOCUMENT) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700246 std::unique_ptr<Node> newNode;
247 switch (code) {
Adam Lesinski803c7c82016-04-06 16:09:43 -0700248 case ResXMLParser::START_NAMESPACE: {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700249 std::unique_ptr<Namespace> node = util::make_unique<Namespace>();
250 size_t len;
251 const char16_t* str16 = tree.getNamespacePrefix(&len);
252 if (str16) {
253 node->namespacePrefix.assign(str16, len);
254 }
255
256 str16 = tree.getNamespaceUri(&len);
257 if (str16) {
258 node->namespaceUri.assign(str16, len);
259 }
260 newNode = std::move(node);
261 break;
262 }
263
Adam Lesinski803c7c82016-04-06 16:09:43 -0700264 case ResXMLParser::START_TAG: {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700265 std::unique_ptr<Element> node = util::make_unique<Element>();
266 size_t len;
267 const char16_t* str16 = tree.getElementNamespace(&len);
268 if (str16) {
269 node->namespaceUri.assign(str16, len);
270 }
271
272 str16 = tree.getElementName(&len);
273 if (str16) {
274 node->name.assign(str16, len);
275 }
276
277 copyAttributes(node.get(), &tree);
278
279 newNode = std::move(node);
280 break;
281 }
282
Adam Lesinski803c7c82016-04-06 16:09:43 -0700283 case ResXMLParser::TEXT: {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700284 std::unique_ptr<Text> node = util::make_unique<Text>();
285 size_t len;
286 const char16_t* str16 = tree.getText(&len);
287 if (str16) {
288 node->text.assign(str16, len);
289 }
290 newNode = std::move(node);
291 break;
292 }
293
Adam Lesinski803c7c82016-04-06 16:09:43 -0700294 case ResXMLParser::END_NAMESPACE:
295 case ResXMLParser::END_TAG:
Adam Lesinski75f3a552015-06-03 14:54:23 -0700296 assert(!nodeStack.empty());
297 nodeStack.pop();
298 break;
299
300 default:
301 assert(false);
302 break;
303 }
304
305 if (newNode) {
306 newNode->lineNumber = tree.getLineNumber();
307
308 Node* thisNode = newNode.get();
309 if (!root) {
310 assert(nodeStack.empty());
311 root = std::move(newNode);
312 } else {
313 assert(!nodeStack.empty());
314 nodeStack.top()->addChild(std::move(newNode));
315 }
316
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700317 if (!nodeCast<Text>(thisNode)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700318 nodeStack.push(thisNode);
319 }
320 }
321 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700322 return util::make_unique<XmlResource>(ResourceFile{}, std::move(root));
Adam Lesinski75f3a552015-06-03 14:54:23 -0700323}
324
Adam Lesinski467f1712015-11-16 17:35:44 -0800325Element* findRootElement(XmlResource* doc) {
326 return findRootElement(doc->root.get());
327}
328
Adam Lesinskica5638f2015-10-21 14:42:43 -0700329Element* findRootElement(Node* node) {
330 if (!node) {
331 return nullptr;
332 }
333
334 Element* el = nullptr;
335 while ((el = nodeCast<Element>(node)) == nullptr) {
336 if (node->children.empty()) {
337 return nullptr;
338 }
339 // We are looking for the first element, and namespaces can only have one child.
340 node = node->children.front().get();
341 }
342 return el;
343}
344
Adam Lesinski75f3a552015-06-03 14:54:23 -0700345void Node::addChild(std::unique_ptr<Node> child) {
346 child->parent = this;
347 children.push_back(std::move(child));
348}
349
Adam Lesinski75f3a552015-06-03 14:54:23 -0700350Attribute* Element::findAttribute(const StringPiece16& ns, const StringPiece16& name) {
351 for (auto& attr : attributes) {
352 if (ns == attr.namespaceUri && name == attr.name) {
353 return &attr;
354 }
355 }
356 return nullptr;
357}
358
359Element* Element::findChild(const StringPiece16& ns, const StringPiece16& name) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700360 return findChildWithAttribute(ns, name, {}, {}, {});
Adam Lesinski75f3a552015-06-03 14:54:23 -0700361}
362
363Element* Element::findChildWithAttribute(const StringPiece16& ns, const StringPiece16& name,
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700364 const StringPiece16& attrNs, const StringPiece16& attrName,
365 const StringPiece16& attrValue) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700366 for (auto& childNode : children) {
367 Node* child = childNode.get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700368 while (nodeCast<Namespace>(child)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700369 if (child->children.empty()) {
370 break;
371 }
372 child = child->children[0].get();
373 }
374
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700375 if (Element* el = nodeCast<Element>(child)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700376 if (ns == el->namespaceUri && name == el->name) {
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700377 if (attrNs.empty() && attrName.empty()) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700378 return el;
379 }
380
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700381 Attribute* attr = el->findAttribute(attrNs, attrName);
382 if (attr && attrValue == attr->value) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700383 return el;
384 }
385 }
386 }
387 }
388 return nullptr;
389}
390
391std::vector<Element*> Element::getChildElements() {
392 std::vector<Element*> elements;
393 for (auto& childNode : children) {
394 Node* child = childNode.get();
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700395 while (nodeCast<Namespace>(child)) {
Adam Lesinski75f3a552015-06-03 14:54:23 -0700396 if (child->children.empty()) {
397 break;
398 }
399 child = child->children[0].get();
400 }
401
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700402 if (Element* el = nodeCast<Element>(child)) {
403 elements.push_back(el);
Adam Lesinski75f3a552015-06-03 14:54:23 -0700404 }
405 }
406 return elements;
407}
408
Adam Lesinski467f1712015-11-16 17:35:44 -0800409void PackageAwareVisitor::visit(Namespace* ns) {
410 bool added = false;
411 if (Maybe<ExtractedPackage> maybePackage = extractPackageFromNamespace(ns->namespaceUri)) {
412 ExtractedPackage& package = maybePackage.value();
413 mPackageDecls.push_back(PackageDecl{ ns->namespacePrefix, std::move(package) });
414 added = true;
415 }
416
417 Visitor::visit(ns);
418
419 if (added) {
420 mPackageDecls.pop_back();
421 }
422}
423
424Maybe<ExtractedPackage> PackageAwareVisitor::transformPackageAlias(
425 const StringPiece16& alias, const StringPiece16& localPackage) const {
426 if (alias.empty()) {
427 return ExtractedPackage{ localPackage.toString(), false /* private */ };
428 }
429
430 const auto rend = mPackageDecls.rend();
431 for (auto iter = mPackageDecls.rbegin(); iter != rend; ++iter) {
432 if (alias == iter->prefix) {
433 if (iter->package.package.empty()) {
434 return ExtractedPackage{ localPackage.toString(),
435 iter->package.privateNamespace };
436 }
437 return iter->package;
438 }
439 }
440 return {};
441}
442
Adam Lesinski75f3a552015-06-03 14:54:23 -0700443} // namespace xml
444} // namespace aapt