• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 is not nullptr
309         // NOLINTNEXTLINE(bugprone-use-after-move)
310         pending_element->namespace_decls.push_back(std::move(decl));
311         break;
312       }
313 
314       case ResXMLParser::START_TAG: {
315         std::unique_ptr<Element> el;
316         if (pending_element != nullptr) {
317           el = std::move(pending_element);
318         } else {
319           el = util::make_unique<Element>();
320         }
321         el->line_number = tree.getLineNumber();
322 
323         size_t len;
324         const char16_t* str16 = tree.getElementNamespace(&len);
325         if (str16) {
326           el->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
327         }
328 
329         str16 = tree.getElementName(&len);
330         if (str16) {
331           el->name = util::Utf16ToUtf8(StringPiece16(str16, len));
332         }
333 
334         Element* this_el = el.get();
335         CopyAttributes(el.get(), &tree, &xml_resource->string_pool);
336 
337         if (!node_stack.empty()) {
338           node_stack.top()->AppendChild(std::move(el));
339         } else {
340           xml_resource->root = std::move(el);
341         }
342         node_stack.push(this_el);
343         break;
344       }
345 
346       case ResXMLParser::TEXT: {
347         std::unique_ptr<Text> text = util::make_unique<Text>();
348         text->line_number = tree.getLineNumber();
349         size_t len;
350         const char16_t* str16 = tree.getText(&len);
351         if (str16) {
352           text->text = util::Utf16ToUtf8(StringPiece16(str16, len));
353         }
354         CHECK(!node_stack.empty());
355         node_stack.top()->AppendChild(std::move(text));
356         break;
357       }
358 
359       case ResXMLParser::END_NAMESPACE:
360         break;
361 
362       case ResXMLParser::END_TAG:
363         CHECK(!node_stack.empty());
364         node_stack.pop();
365         break;
366 
367       default:
368         LOG(FATAL) << "unhandled XML chunk type";
369         break;
370     }
371   }
372   return xml_resource;
373 }
374 
Clone() const375 std::unique_ptr<XmlResource> XmlResource::Clone() const {
376   std::unique_ptr<XmlResource> cloned = util::make_unique<XmlResource>(file);
377   CloningValueTransformer cloner(&cloned->string_pool);
378   if (root != nullptr) {
379     cloned->root = root->CloneElement([&](const xml::Element& src, xml::Element* dst) {
380       dst->attributes.reserve(src.attributes.size());
381       for (const xml::Attribute& attr : src.attributes) {
382         xml::Attribute cloned_attr;
383         cloned_attr.name = attr.name;
384         cloned_attr.namespace_uri = attr.namespace_uri;
385         cloned_attr.value = attr.value;
386         cloned_attr.compiled_attribute = attr.compiled_attribute;
387         if (attr.compiled_value != nullptr) {
388           cloned_attr.compiled_value = attr.compiled_value->Transform(cloner);
389         }
390         dst->attributes.push_back(std::move(cloned_attr));
391       }
392     });
393   }
394   return cloned;
395 }
396 
FindRootElement(Node * node)397 Element* FindRootElement(Node* node) {
398   if (node == nullptr) {
399     return nullptr;
400   }
401 
402   while (node->parent != nullptr) {
403     node = node->parent;
404   }
405   return NodeCast<Element>(node);
406 }
407 
AppendChild(std::unique_ptr<Node> child)408 void Element::AppendChild(std::unique_ptr<Node> child) {
409   child->parent = this;
410   children.push_back(std::move(child));
411 }
412 
InsertChild(size_t index,std::unique_ptr<Node> child)413 void Element::InsertChild(size_t index, std::unique_ptr<Node> child) {
414   child->parent = this;
415   children.insert(children.begin() + index, std::move(child));
416 }
417 
FindAttribute(const StringPiece & ns,const StringPiece & name)418 Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) {
419   return const_cast<Attribute*>(static_cast<const Element*>(this)->FindAttribute(ns, name));
420 }
421 
FindAttribute(const StringPiece & ns,const StringPiece & name) const422 const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
423   for (const auto& attr : attributes) {
424     if (ns == attr.namespace_uri && name == attr.name) {
425       return &attr;
426     }
427   }
428   return nullptr;
429 }
430 
RemoveAttribute(const StringPiece & ns,const StringPiece & name)431 void Element::RemoveAttribute(const StringPiece& ns, const StringPiece& name) {
432   auto new_attr_end = std::remove_if(attributes.begin(), attributes.end(),
433     [&](const Attribute& attr) -> bool {
434       return ns == attr.namespace_uri && name == attr.name;
435     });
436 
437   attributes.erase(new_attr_end, attributes.end());
438 }
439 
FindOrCreateAttribute(const StringPiece & ns,const StringPiece & name)440 Attribute* Element::FindOrCreateAttribute(const StringPiece& ns, const StringPiece& name) {
441   Attribute* attr = FindAttribute(ns, name);
442   if (attr == nullptr) {
443     attributes.push_back(Attribute{ns.to_string(), name.to_string()});
444     attr = &attributes.back();
445   }
446   return attr;
447 }
448 
FindChild(const StringPiece & ns,const StringPiece & name)449 Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
450   return FindChildWithAttribute(ns, name, {}, {}, {});
451 }
452 
FindChild(const StringPiece & ns,const StringPiece & name) const453 const Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) const {
454   return FindChildWithAttribute(ns, name, {}, {}, {});
455 }
456 
FindChildWithAttribute(const StringPiece & ns,const StringPiece & name,const StringPiece & attr_ns,const StringPiece & attr_name,const StringPiece & attr_value)457 Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
458                                          const StringPiece& attr_ns, const StringPiece& attr_name,
459                                          const StringPiece& attr_value) {
460   return const_cast<Element*>(static_cast<const Element*>(this)->FindChildWithAttribute(
461       ns, name, attr_ns, attr_name, attr_value));
462 }
463 
FindChildWithAttribute(const StringPiece & ns,const StringPiece & name,const StringPiece & attr_ns,const StringPiece & attr_name,const StringPiece & attr_value) const464 const Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
465                                                const StringPiece& attr_ns,
466                                                const StringPiece& attr_name,
467                                                const StringPiece& attr_value) const {
468   for (const auto& child : children) {
469     if (const Element* el = NodeCast<Element>(child.get())) {
470       if (ns == el->namespace_uri && name == el->name) {
471         if (attr_ns.empty() && attr_name.empty()) {
472           return el;
473         }
474 
475         const Attribute* attr = el->FindAttribute(attr_ns, attr_name);
476         if (attr && attr_value == attr->value) {
477           return el;
478         }
479       }
480     }
481   }
482   return nullptr;
483 }
484 
GetChildElements()485 std::vector<Element*> Element::GetChildElements() {
486   std::vector<Element*> elements;
487   for (auto& child_node : children) {
488     if (Element* child = NodeCast<Element>(child_node.get())) {
489       elements.push_back(child);
490     }
491   }
492   return elements;
493 }
494 
Clone(const ElementCloneFunc & el_cloner) const495 std::unique_ptr<Node> Element::Clone(const ElementCloneFunc& el_cloner) const {
496   auto el = util::make_unique<Element>();
497   el->namespace_decls = namespace_decls;
498   el->comment = comment;
499   el->line_number = line_number;
500   el->column_number = column_number;
501   el->name = name;
502   el->namespace_uri = namespace_uri;
503   el->attributes.reserve(attributes.size());
504   el_cloner(*this, el.get());
505   el->children.reserve(children.size());
506   for (const std::unique_ptr<xml::Node>& child : children) {
507     el->AppendChild(child->Clone(el_cloner));
508   }
509   return std::move(el);
510 }
511 
CloneElement(const ElementCloneFunc & el_cloner) const512 std::unique_ptr<Element> Element::CloneElement(const ElementCloneFunc& el_cloner) const {
513   return std::unique_ptr<Element>(static_cast<Element*>(Clone(el_cloner).release()));
514 }
515 
Accept(Visitor * visitor)516 void Element::Accept(Visitor* visitor) {
517   visitor->BeforeVisitElement(this);
518   visitor->Visit(this);
519   visitor->AfterVisitElement(this);
520 }
521 
Accept(ConstVisitor * visitor) const522 void Element::Accept(ConstVisitor* visitor) const {
523   visitor->BeforeVisitElement(this);
524   visitor->Visit(this);
525   visitor->AfterVisitElement(this);
526 }
527 
Clone(const ElementCloneFunc &) const528 std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) const {
529   auto t = util::make_unique<Text>();
530   t->comment = comment;
531   t->line_number = line_number;
532   t->column_number = column_number;
533   t->text = text;
534   return std::move(t);
535 }
536 
Accept(Visitor * visitor)537 void Text::Accept(Visitor* visitor) {
538   visitor->Visit(this);
539 }
540 
Accept(ConstVisitor * visitor) const541 void Text::Accept(ConstVisitor* visitor) const {
542   visitor->Visit(this);
543 }
544 
BeforeVisitElement(Element * el)545 void PackageAwareVisitor::BeforeVisitElement(Element* el) {
546   std::vector<PackageDecl> decls;
547   for (const NamespaceDecl& decl : el->namespace_decls) {
548     if (Maybe<ExtractedPackage> maybe_package = ExtractPackageFromNamespace(decl.uri)) {
549       decls.push_back(PackageDecl{decl.prefix, std::move(maybe_package.value())});
550     }
551   }
552   package_decls_.push_back(std::move(decls));
553 }
554 
AfterVisitElement(Element * el)555 void PackageAwareVisitor::AfterVisitElement(Element* el) {
556   package_decls_.pop_back();
557 }
558 
TransformPackageAlias(const StringPiece & alias) const559 Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(const StringPiece& alias) const {
560   if (alias.empty()) {
561     return ExtractedPackage{{}, false /*private*/};
562   }
563 
564   const auto rend = package_decls_.rend();
565   for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
566     const std::vector<PackageDecl>& decls = *iter;
567     const auto rend2 = decls.rend();
568     for (auto iter2 = decls.rbegin(); iter2 != rend2; ++iter2) {
569       const PackageDecl& decl = *iter2;
570       if (alias == decl.prefix) {
571         if (decl.package.package.empty()) {
572           return ExtractedPackage{{}, decl.package.private_namespace};
573         }
574         return decl.package;
575       }
576     }
577   }
578   return {};
579 }
580 
581 }  // namespace xml
582 }  // namespace aapt
583