blob: b8b2d1295067d611187982467ffea1c9deb4717a [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
17#include "Logger.h"
18#include "Util.h"
19#include "XmlDom.h"
20#include "XmlPullParser.h"
21
22#include <cassert>
23#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
68 if (thisNode->type != NodeType::kText) {
69 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());
129 stack->nodeStack.top()->comment = std::move(stack->pendingComment);
130 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();
146 if (lastChild->type == NodeType::kText) {
147 Text* text = static_cast<Text*>(lastChild);
148 text->text += util::utf8ToUtf16(StringPiece(s, len));
149 return;
150 }
151 }
152 }
153
154 std::unique_ptr<Text> text = util::make_unique<Text>();
155 text->text = util::utf8ToUtf16(StringPiece(s, len));
156 addToStack(stack, parser, std::move(text));
157}
158
159static void XMLCALL commentDataHandler(void* userData, const char* comment) {
160 XML_Parser parser = reinterpret_cast<XML_Parser>(userData);
161 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
162
163 if (!stack->pendingComment.empty()) {
164 stack->pendingComment += '\n';
165 }
166 stack->pendingComment += util::utf8ToUtf16(comment);
167}
168
169std::unique_ptr<Node> inflate(std::istream* in, SourceLogger* logger) {
170 Stack stack;
171
172 XML_Parser parser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
173 XML_SetUserData(parser, &stack);
174 XML_UseParserAsHandlerArg(parser);
175 XML_SetElementHandler(parser, startElementHandler, endElementHandler);
176 XML_SetNamespaceDeclHandler(parser, startNamespaceHandler, endNamespaceHandler);
177 XML_SetCharacterDataHandler(parser, characterDataHandler);
178 XML_SetCommentHandler(parser, commentDataHandler);
179
180 char buffer[1024];
181 while (!in->eof()) {
182 in->read(buffer, sizeof(buffer) / sizeof(buffer[0]));
183 if (in->bad() && !in->eof()) {
184 stack.root = {};
185 logger->error() << strerror(errno) << std::endl;
186 break;
187 }
188
189 if (XML_Parse(parser, buffer, in->gcount(), in->eof()) == XML_STATUS_ERROR) {
190 stack.root = {};
191 logger->error(XML_GetCurrentLineNumber(parser))
192 << XML_ErrorString(XML_GetErrorCode(parser)) << std::endl;
193 break;
194 }
195 }
196
197 XML_ParserFree(parser);
198 return std::move(stack.root);
199}
200
201static void copyAttributes(Element* el, android::ResXMLParser* parser) {
202 const size_t attrCount = parser->getAttributeCount();
203 if (attrCount > 0) {
204 el->attributes.reserve(attrCount);
205 for (size_t i = 0; i < attrCount; i++) {
206 Attribute attr;
207 size_t len;
208 const char16_t* str16 = parser->getAttributeNamespace(i, &len);
209 if (str16) {
210 attr.namespaceUri.assign(str16, len);
211 }
212
213 str16 = parser->getAttributeName(i, &len);
214 if (str16) {
215 attr.name.assign(str16, len);
216 }
217
218 str16 = parser->getAttributeStringValue(i, &len);
219 if (str16) {
220 attr.value.assign(str16, len);
221 }
222 el->attributes.push_back(std::move(attr));
223 }
224 }
225}
226
227std::unique_ptr<Node> inflate(const void* data, size_t dataLen, SourceLogger* logger) {
228 std::unique_ptr<Node> root;
229 std::stack<Node*> nodeStack;
230
231 android::ResXMLTree tree;
232 if (tree.setTo(data, dataLen) != android::NO_ERROR) {
233 return {};
234 }
235
236 android::ResXMLParser::event_code_t code;
237 while ((code = tree.next()) != android::ResXMLParser::BAD_DOCUMENT &&
238 code != android::ResXMLParser::END_DOCUMENT) {
239 std::unique_ptr<Node> newNode;
240 switch (code) {
241 case android::ResXMLParser::START_NAMESPACE: {
242 std::unique_ptr<Namespace> node = util::make_unique<Namespace>();
243 size_t len;
244 const char16_t* str16 = tree.getNamespacePrefix(&len);
245 if (str16) {
246 node->namespacePrefix.assign(str16, len);
247 }
248
249 str16 = tree.getNamespaceUri(&len);
250 if (str16) {
251 node->namespaceUri.assign(str16, len);
252 }
253 newNode = std::move(node);
254 break;
255 }
256
257 case android::ResXMLParser::START_TAG: {
258 std::unique_ptr<Element> node = util::make_unique<Element>();
259 size_t len;
260 const char16_t* str16 = tree.getElementNamespace(&len);
261 if (str16) {
262 node->namespaceUri.assign(str16, len);
263 }
264
265 str16 = tree.getElementName(&len);
266 if (str16) {
267 node->name.assign(str16, len);
268 }
269
270 copyAttributes(node.get(), &tree);
271
272 newNode = std::move(node);
273 break;
274 }
275
276 case android::ResXMLParser::TEXT: {
277 std::unique_ptr<Text> node = util::make_unique<Text>();
278 size_t len;
279 const char16_t* str16 = tree.getText(&len);
280 if (str16) {
281 node->text.assign(str16, len);
282 }
283 newNode = std::move(node);
284 break;
285 }
286
287 case android::ResXMLParser::END_NAMESPACE:
288 case android::ResXMLParser::END_TAG:
289 assert(!nodeStack.empty());
290 nodeStack.pop();
291 break;
292
293 default:
294 assert(false);
295 break;
296 }
297
298 if (newNode) {
299 newNode->lineNumber = tree.getLineNumber();
300
301 Node* thisNode = newNode.get();
302 if (!root) {
303 assert(nodeStack.empty());
304 root = std::move(newNode);
305 } else {
306 assert(!nodeStack.empty());
307 nodeStack.top()->addChild(std::move(newNode));
308 }
309
310 if (thisNode->type != NodeType::kText) {
311 nodeStack.push(thisNode);
312 }
313 }
314 }
Dan Albert986d3f22015-08-13 20:21:17 -0700315 return root;
Adam Lesinski75f3a552015-06-03 14:54:23 -0700316}
317
318Node::Node(NodeType type) : type(type), parent(nullptr), lineNumber(0), columnNumber(0) {
319}
320
321void Node::addChild(std::unique_ptr<Node> child) {
322 child->parent = this;
323 children.push_back(std::move(child));
324}
325
326Namespace::Namespace() : BaseNode(NodeType::kNamespace) {
327}
328
329std::unique_ptr<Node> Namespace::clone() const {
330 Namespace* ns = new Namespace();
331 ns->lineNumber = lineNumber;
332 ns->columnNumber = columnNumber;
333 ns->comment = comment;
334 ns->namespacePrefix = namespacePrefix;
335 ns->namespaceUri = namespaceUri;
336 for (auto& child : children) {
337 ns->addChild(child->clone());
338 }
339 return std::unique_ptr<Node>(ns);
340}
341
342Element::Element() : BaseNode(NodeType::kElement) {
343}
344
345std::unique_ptr<Node> Element::clone() const {
346 Element* el = new Element();
347 el->lineNumber = lineNumber;
348 el->columnNumber = columnNumber;
349 el->comment = comment;
350 el->namespaceUri = namespaceUri;
351 el->name = name;
352 el->attributes = attributes;
353 for (auto& child : children) {
354 el->addChild(child->clone());
355 }
356 return std::unique_ptr<Node>(el);
357}
358
359Attribute* Element::findAttribute(const StringPiece16& ns, const StringPiece16& name) {
360 for (auto& attr : attributes) {
361 if (ns == attr.namespaceUri && name == attr.name) {
362 return &attr;
363 }
364 }
365 return nullptr;
366}
367
368Element* Element::findChild(const StringPiece16& ns, const StringPiece16& name) {
369 return findChildWithAttribute(ns, name, nullptr);
370}
371
372Element* Element::findChildWithAttribute(const StringPiece16& ns, const StringPiece16& name,
373 const Attribute* reqAttr) {
374 for (auto& childNode : children) {
375 Node* child = childNode.get();
376 while (child->type == NodeType::kNamespace) {
377 if (child->children.empty()) {
378 break;
379 }
380 child = child->children[0].get();
381 }
382
383 if (child->type == NodeType::kElement) {
384 Element* el = static_cast<Element*>(child);
385 if (ns == el->namespaceUri && name == el->name) {
386 if (!reqAttr) {
387 return el;
388 }
389
390 Attribute* attrName = el->findAttribute(reqAttr->namespaceUri, reqAttr->name);
391 if (attrName && attrName->value == reqAttr->value) {
392 return el;
393 }
394 }
395 }
396 }
397 return nullptr;
398}
399
400std::vector<Element*> Element::getChildElements() {
401 std::vector<Element*> elements;
402 for (auto& childNode : children) {
403 Node* child = childNode.get();
404 while (child->type == NodeType::kNamespace) {
405 if (child->children.empty()) {
406 break;
407 }
408 child = child->children[0].get();
409 }
410
411 if (child->type == NodeType::kElement) {
412 elements.push_back(static_cast<Element*>(child));
413 }
414 }
415 return elements;
416}
417
418Text::Text() : BaseNode(NodeType::kText) {
419}
420
421std::unique_ptr<Node> Text::clone() const {
422 Text* el = new Text();
423 el->lineNumber = lineNumber;
424 el->columnNumber = columnNumber;
425 el->comment = comment;
426 el->text = text;
427 return std::unique_ptr<Node>(el);
428}
429
430} // namespace xml
431} // namespace aapt