1 /*
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 "XmlDom.h"
18
19 #include <expat.h>
20
21 #include <memory>
22 #include <stack>
23 #include <string>
24 #include <tuple>
25
26 #include "android-base/logging.h"
27
28 #include "ResourceUtils.h"
29 #include "trace/TraceBuffer.h"
30 #include "XmlPullParser.h"
31 #include "util/Util.h"
32
33 using ::aapt::io::InputStream;
34 using ::android::StringPiece;
35 using ::android::StringPiece16;
36
37 namespace aapt {
38 namespace xml {
39
40 constexpr char kXmlNamespaceSep = 1;
41
42 struct Stack {
43 std::unique_ptr<xml::Element> root;
44 std::stack<xml::Element*> node_stack;
45 std::unique_ptr<xml::Element> pending_element;
46 std::string pending_comment;
47 std::unique_ptr<xml::Text> last_text_node;
48 };
49
50 // Extracts the namespace and name of an expanded element or attribute name.
SplitName(const char * name,std::string * out_ns,std::string * out_name)51 static void SplitName(const char* name, std::string* out_ns, std::string* out_name) {
52 const char* p = name;
53 while (*p != 0 && *p != kXmlNamespaceSep) {
54 p++;
55 }
56
57 if (*p == 0) {
58 out_ns->clear();
59 out_name->assign(name);
60 } else {
61 out_ns->assign(name, (p - name));
62 out_name->assign(p + 1);
63 }
64 }
65
FinishPendingText(Stack * stack)66 static void FinishPendingText(Stack* stack) {
67 if (stack->last_text_node != nullptr) {
68 if (!stack->last_text_node->text.empty()) {
69 CHECK(!stack->node_stack.empty());
70 stack->node_stack.top()->AppendChild(std::move(stack->last_text_node));
71 } else {
72 // Drop an empty text node.
73 }
74 stack->last_text_node = nullptr;
75 }
76 }
77
StartNamespaceHandler(void * user_data,const char * prefix,const char * uri)78 static void XMLCALL StartNamespaceHandler(void* user_data, const char* prefix, const char* uri) {
79 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
80 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
81 FinishPendingText(stack);
82
83 NamespaceDecl decl;
84 decl.line_number = XML_GetCurrentLineNumber(parser);
85 decl.column_number = XML_GetCurrentColumnNumber(parser);
86 decl.prefix = prefix ? prefix : "";
87 decl.uri = uri ? uri : "";
88
89 if (stack->pending_element == nullptr) {
90 stack->pending_element = util::make_unique<Element>();
91 }
92 stack->pending_element->namespace_decls.push_back(std::move(decl));
93 }
94
EndNamespaceHandler(void * user_data,const char *)95 static void XMLCALL EndNamespaceHandler(void* user_data, const char* /*prefix*/) {
96 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
97 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
98 FinishPendingText(stack);
99 }
100
less_attribute(const Attribute & lhs,const Attribute & rhs)101 static bool less_attribute(const Attribute& lhs, const Attribute& rhs) {
102 return std::tie(lhs.namespace_uri, lhs.name, lhs.value) <
103 std::tie(rhs.namespace_uri, rhs.name, rhs.value);
104 }
105
StartElementHandler(void * user_data,const char * name,const char ** attrs)106 static void XMLCALL StartElementHandler(void* user_data, const char* name, const char** attrs) {
107 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
108 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
109 FinishPendingText(stack);
110
111 std::unique_ptr<Element> el;
112 if (stack->pending_element != nullptr) {
113 el = std::move(stack->pending_element);
114 } else {
115 el = util::make_unique<Element>();
116 }
117
118 el->line_number = XML_GetCurrentLineNumber(parser);
119 el->column_number = XML_GetCurrentColumnNumber(parser);
120 el->comment = std::move(stack->pending_comment);
121
122 SplitName(name, &el->namespace_uri, &el->name);
123
124 while (*attrs) {
125 Attribute attribute;
126 SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
127 attribute.value = *attrs++;
128 el->attributes.push_back(std::move(attribute));
129 }
130
131 // Sort the attributes.
132 std::sort(el->attributes.begin(), el->attributes.end(), less_attribute);
133
134 // Add to the stack.
135 Element* this_el = el.get();
136 if (!stack->node_stack.empty()) {
137 stack->node_stack.top()->AppendChild(std::move(el));
138 } else {
139 stack->root = std::move(el);
140 }
141 stack->node_stack.push(this_el);
142 }
143
EndElementHandler(void * user_data,const char * name)144 static void XMLCALL EndElementHandler(void* user_data, const char* name) {
145 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
146 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
147 FinishPendingText(stack);
148
149 CHECK(!stack->node_stack.empty());
150 // stack->nodeStack.top()->comment = std::move(stack->pendingComment);
151 stack->node_stack.pop();
152 }
153
CharacterDataHandler(void * user_data,const char * s,int len)154 static void XMLCALL CharacterDataHandler(void* user_data, const char* s, int len) {
155 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
156 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
157
158 const StringPiece str(s, len);
159 if (str.empty()) {
160 return;
161 }
162
163 // See if we can just append the text to a previous text node.
164 if (stack->last_text_node != nullptr) {
165 stack->last_text_node->text.append(str.data(), str.size());
166 return;
167 }
168
169 stack->last_text_node = util::make_unique<Text>();
170 stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
171 stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
172 stack->last_text_node->text = str.to_string();
173 }
174
CommentDataHandler(void * user_data,const char * comment)175 static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
176 XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
177 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
178 FinishPendingText(stack);
179
180 if (!stack->pending_comment.empty()) {
181 stack->pending_comment += '\n';
182 }
183 stack->pending_comment += comment;
184 }
185
Inflate(InputStream * in,IDiagnostics * diag,const Source & source)186 std::unique_ptr<XmlResource> Inflate(InputStream* in, IDiagnostics* diag, const Source& source) {
187 Stack stack;
188
189 std::unique_ptr<std::remove_pointer<XML_Parser>::type, decltype(XML_ParserFree)*> parser = {
190 XML_ParserCreateNS(nullptr, kXmlNamespaceSep), XML_ParserFree};
191 XML_SetUserData(parser.get(), &stack);
192 XML_UseParserAsHandlerArg(parser.get());
193 XML_SetElementHandler(parser.get(), StartElementHandler, EndElementHandler);
194 XML_SetNamespaceDeclHandler(parser.get(), StartNamespaceHandler, EndNamespaceHandler);
195 XML_SetCharacterDataHandler(parser.get(), CharacterDataHandler);
196 XML_SetCommentHandler(parser.get(), CommentDataHandler);
197
198 const char* buffer = nullptr;
199 size_t buffer_size = 0;
200 while (in->Next(reinterpret_cast<const void**>(&buffer), &buffer_size)) {
201 if (XML_Parse(parser.get(), buffer, buffer_size, false) == XML_STATUS_ERROR) {
202 diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
203 << XML_ErrorString(XML_GetErrorCode(parser.get())));
204 return {};
205 }
206 }
207
208 if (in->HadError()) {
209 diag->Error(DiagMessage(source) << in->GetError());
210 return {};
211 } else {
212 // Finish off the parsing.
213 if (XML_Parse(parser.get(), nullptr, 0u, true) == XML_STATUS_ERROR) {
214 diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
215 << XML_ErrorString(XML_GetErrorCode(parser.get())));
216 return {};
217 }
218 }
219 return util::make_unique<XmlResource>(ResourceFile{{}, {}, ResourceFile::Type::kUnknown, source},
220 StringPool{}, std::move(stack.root));
221 }
222
CopyAttributes(Element * el,android::ResXMLParser * parser,StringPool * out_pool)223 static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
224 const size_t attr_count = parser->getAttributeCount();
225 if (attr_count > 0) {
226 el->attributes.reserve(attr_count);
227 for (size_t i = 0; i < attr_count; i++) {
228 Attribute attr;
229 size_t len;
230 const char16_t* str16 = parser->getAttributeNamespace(i, &len);
231 if (str16) {
232 attr.namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
233 }
234
235 str16 = parser->getAttributeName(i, &len);
236 if (str16) {
237 attr.name = util::Utf16ToUtf8(StringPiece16(str16, len));
238 }
239
240 uint32_t res_id = parser->getAttributeNameResID(i);
241 if (res_id > 0) {
242 attr.compiled_attribute = AaptAttribute(::aapt::Attribute(), {res_id});
243 }
244
245 str16 = parser->getAttributeStringValue(i, &len);
246 if (str16) {
247 attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
248 }
249
250 android::Res_value res_value;
251 if (parser->getAttributeValue(i, &res_value) > 0) {
252 // Only compile the value if it is not a string, or it is a string that differs from
253 // the raw attribute value.
254 int32_t raw_value_idx = parser->getAttributeValueStringID(i);
255 if (res_value.dataType != android::Res_value::TYPE_STRING || raw_value_idx < 0 ||
256 static_cast<uint32_t>(raw_value_idx) != res_value.data) {
257 attr.compiled_value = ResourceUtils::ParseBinaryResValue(
258 ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
259 }
260 }
261
262 el->attributes.push_back(std::move(attr));
263 }
264 }
265 }
266
Inflate(const void * data,size_t len,std::string * out_error)267 std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string* out_error) {
268 TRACE_CALL();
269 // We import the android namespace because on Windows NO_ERROR is a macro, not
270 // an enum, which causes errors when qualifying it with android::
271 using namespace android;
272
273 std::unique_ptr<XmlResource> xml_resource = util::make_unique<XmlResource>();
274
275 std::stack<Element*> node_stack;
276 std::unique_ptr<Element> pending_element;
277
278 ResXMLTree tree;
279 if (tree.setTo(data, len) != NO_ERROR) {
280 if (out_error != nullptr) {
281 *out_error = "failed to initialize ResXMLTree";
282 }
283 return {};
284 }
285
286 ResXMLParser::event_code_t code;
287 while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT && code != ResXMLParser::END_DOCUMENT) {
288 std::unique_ptr<Node> new_node;
289 switch (code) {
290 case ResXMLParser::START_NAMESPACE: {
291 NamespaceDecl decl;
292 decl.line_number = tree.getLineNumber();
293
294 size_t len;
295 const char16_t* str16 = tree.getNamespacePrefix(&len);
296 if (str16) {
297 decl.prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
298 }
299
300 str16 = tree.getNamespaceUri(&len);
301 if (str16) {
302 decl.uri = util::Utf16ToUtf8(StringPiece16(str16, len));
303 }
304
305 if (pending_element == nullptr) {
306 pending_element = util::make_unique<Element>();
307 }
308 pending_element->namespace_decls.push_back(std::move(decl));
309 break;
310 }
311
312 case ResXMLParser::START_TAG: {
313 std::unique_ptr<Element> el;
314 if (pending_element != nullptr) {
315 el = std::move(pending_element);
316 } else {
317 el = util::make_unique<Element>();
318 }
319 el->line_number = tree.getLineNumber();
320
321 size_t len;
322 const char16_t* str16 = tree.getElementNamespace(&len);
323 if (str16) {
324 el->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
325 }
326
327 str16 = tree.getElementName(&len);
328 if (str16) {
329 el->name = util::Utf16ToUtf8(StringPiece16(str16, len));
330 }
331
332 Element* this_el = el.get();
333 CopyAttributes(el.get(), &tree, &xml_resource->string_pool);
334
335 if (!node_stack.empty()) {
336 node_stack.top()->AppendChild(std::move(el));
337 } else {
338 xml_resource->root = std::move(el);
339 }
340 node_stack.push(this_el);
341 break;
342 }
343
344 case ResXMLParser::TEXT: {
345 std::unique_ptr<Text> text = util::make_unique<Text>();
346 text->line_number = tree.getLineNumber();
347 size_t len;
348 const char16_t* str16 = tree.getText(&len);
349 if (str16) {
350 text->text = util::Utf16ToUtf8(StringPiece16(str16, len));
351 }
352 CHECK(!node_stack.empty());
353 node_stack.top()->AppendChild(std::move(text));
354 break;
355 }
356
357 case ResXMLParser::END_NAMESPACE:
358 break;
359
360 case ResXMLParser::END_TAG:
361 CHECK(!node_stack.empty());
362 node_stack.pop();
363 break;
364
365 default:
366 LOG(FATAL) << "unhandled XML chunk type";
367 break;
368 }
369 }
370 return xml_resource;
371 }
372
Clone() const373 std::unique_ptr<XmlResource> XmlResource::Clone() const {
374 std::unique_ptr<XmlResource> cloned = util::make_unique<XmlResource>(file);
375 if (root != nullptr) {
376 cloned->root = root->CloneElement([&](const xml::Element& src, xml::Element* dst) {
377 dst->attributes.reserve(src.attributes.size());
378 for (const xml::Attribute& attr : src.attributes) {
379 xml::Attribute cloned_attr;
380 cloned_attr.name = attr.name;
381 cloned_attr.namespace_uri = attr.namespace_uri;
382 cloned_attr.value = attr.value;
383 cloned_attr.compiled_attribute = attr.compiled_attribute;
384 if (attr.compiled_value != nullptr) {
385 cloned_attr.compiled_value.reset(attr.compiled_value->Clone(&cloned->string_pool));
386 }
387 dst->attributes.push_back(std::move(cloned_attr));
388 }
389 });
390 }
391 return cloned;
392 }
393
FindRootElement(Node * node)394 Element* FindRootElement(Node* node) {
395 if (node == nullptr) {
396 return nullptr;
397 }
398
399 while (node->parent != nullptr) {
400 node = node->parent;
401 }
402 return NodeCast<Element>(node);
403 }
404
AppendChild(std::unique_ptr<Node> child)405 void Element::AppendChild(std::unique_ptr<Node> child) {
406 child->parent = this;
407 children.push_back(std::move(child));
408 }
409
InsertChild(size_t index,std::unique_ptr<Node> child)410 void Element::InsertChild(size_t index, std::unique_ptr<Node> child) {
411 child->parent = this;
412 children.insert(children.begin() + index, std::move(child));
413 }
414
FindAttribute(const StringPiece & ns,const StringPiece & name)415 Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) {
416 return const_cast<Attribute*>(static_cast<const Element*>(this)->FindAttribute(ns, name));
417 }
418
FindAttribute(const StringPiece & ns,const StringPiece & name) const419 const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
420 for (const auto& attr : attributes) {
421 if (ns == attr.namespace_uri && name == attr.name) {
422 return &attr;
423 }
424 }
425 return nullptr;
426 }
427
RemoveAttribute(const StringPiece & ns,const StringPiece & name)428 void Element::RemoveAttribute(const StringPiece& ns, const StringPiece& name) {
429 auto new_attr_end = std::remove_if(attributes.begin(), attributes.end(),
430 [&](const Attribute& attr) -> bool {
431 return ns == attr.namespace_uri && name == attr.name;
432 });
433
434 attributes.erase(new_attr_end, attributes.end());
435 }
436
FindOrCreateAttribute(const StringPiece & ns,const StringPiece & name)437 Attribute* Element::FindOrCreateAttribute(const StringPiece& ns, const StringPiece& name) {
438 Attribute* attr = FindAttribute(ns, name);
439 if (attr == nullptr) {
440 attributes.push_back(Attribute{ns.to_string(), name.to_string()});
441 attr = &attributes.back();
442 }
443 return attr;
444 }
445
FindChild(const StringPiece & ns,const StringPiece & name)446 Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
447 return FindChildWithAttribute(ns, name, {}, {}, {});
448 }
449
FindChild(const StringPiece & ns,const StringPiece & name) const450 const Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) const {
451 return FindChildWithAttribute(ns, name, {}, {}, {});
452 }
453
FindChildWithAttribute(const StringPiece & ns,const StringPiece & name,const StringPiece & attr_ns,const StringPiece & attr_name,const StringPiece & attr_value)454 Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
455 const StringPiece& attr_ns, const StringPiece& attr_name,
456 const StringPiece& attr_value) {
457 return const_cast<Element*>(static_cast<const Element*>(this)->FindChildWithAttribute(
458 ns, name, attr_ns, attr_name, attr_value));
459 }
460
FindChildWithAttribute(const StringPiece & ns,const StringPiece & name,const StringPiece & attr_ns,const StringPiece & attr_name,const StringPiece & attr_value) const461 const Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
462 const StringPiece& attr_ns,
463 const StringPiece& attr_name,
464 const StringPiece& attr_value) const {
465 for (const auto& child : children) {
466 if (const Element* el = NodeCast<Element>(child.get())) {
467 if (ns == el->namespace_uri && name == el->name) {
468 if (attr_ns.empty() && attr_name.empty()) {
469 return el;
470 }
471
472 const Attribute* attr = el->FindAttribute(attr_ns, attr_name);
473 if (attr && attr_value == attr->value) {
474 return el;
475 }
476 }
477 }
478 }
479 return nullptr;
480 }
481
GetChildElements()482 std::vector<Element*> Element::GetChildElements() {
483 std::vector<Element*> elements;
484 for (auto& child_node : children) {
485 if (Element* child = NodeCast<Element>(child_node.get())) {
486 elements.push_back(child);
487 }
488 }
489 return elements;
490 }
491
Clone(const ElementCloneFunc & el_cloner) const492 std::unique_ptr<Node> Element::Clone(const ElementCloneFunc& el_cloner) const {
493 auto el = util::make_unique<Element>();
494 el->namespace_decls = namespace_decls;
495 el->comment = comment;
496 el->line_number = line_number;
497 el->column_number = column_number;
498 el->name = name;
499 el->namespace_uri = namespace_uri;
500 el->attributes.reserve(attributes.size());
501 el_cloner(*this, el.get());
502 el->children.reserve(children.size());
503 for (const std::unique_ptr<xml::Node>& child : children) {
504 el->AppendChild(child->Clone(el_cloner));
505 }
506 return std::move(el);
507 }
508
CloneElement(const ElementCloneFunc & el_cloner) const509 std::unique_ptr<Element> Element::CloneElement(const ElementCloneFunc& el_cloner) const {
510 return std::unique_ptr<Element>(static_cast<Element*>(Clone(el_cloner).release()));
511 }
512
Accept(Visitor * visitor)513 void Element::Accept(Visitor* visitor) {
514 visitor->BeforeVisitElement(this);
515 visitor->Visit(this);
516 visitor->AfterVisitElement(this);
517 }
518
Accept(ConstVisitor * visitor) const519 void Element::Accept(ConstVisitor* visitor) const {
520 visitor->BeforeVisitElement(this);
521 visitor->Visit(this);
522 visitor->AfterVisitElement(this);
523 }
524
Clone(const ElementCloneFunc &) const525 std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) const {
526 auto t = util::make_unique<Text>();
527 t->comment = comment;
528 t->line_number = line_number;
529 t->column_number = column_number;
530 t->text = text;
531 return std::move(t);
532 }
533
Accept(Visitor * visitor)534 void Text::Accept(Visitor* visitor) {
535 visitor->Visit(this);
536 }
537
Accept(ConstVisitor * visitor) const538 void Text::Accept(ConstVisitor* visitor) const {
539 visitor->Visit(this);
540 }
541
BeforeVisitElement(Element * el)542 void PackageAwareVisitor::BeforeVisitElement(Element* el) {
543 std::vector<PackageDecl> decls;
544 for (const NamespaceDecl& decl : el->namespace_decls) {
545 if (Maybe<ExtractedPackage> maybe_package = ExtractPackageFromNamespace(decl.uri)) {
546 decls.push_back(PackageDecl{decl.prefix, std::move(maybe_package.value())});
547 }
548 }
549 package_decls_.push_back(std::move(decls));
550 }
551
AfterVisitElement(Element * el)552 void PackageAwareVisitor::AfterVisitElement(Element* el) {
553 package_decls_.pop_back();
554 }
555
TransformPackageAlias(const StringPiece & alias) const556 Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(const StringPiece& alias) const {
557 if (alias.empty()) {
558 return ExtractedPackage{{}, false /*private*/};
559 }
560
561 const auto rend = package_decls_.rend();
562 for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
563 const std::vector<PackageDecl>& decls = *iter;
564 const auto rend2 = decls.rend();
565 for (auto iter2 = decls.rbegin(); iter2 != rend2; ++iter2) {
566 const PackageDecl& decl = *iter2;
567 if (alias == decl.prefix) {
568 if (decl.package.package.empty()) {
569 return ExtractedPackage{{}, decl.package.private_namespace};
570 }
571 return decl.package;
572 }
573 }
574 }
575 return {};
576 }
577
578 } // namespace xml
579 } // namespace aapt
580