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.assign(str);
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,android::IDiagnostics * diag,const android::Source & source)186  std::unique_ptr<XmlResource> Inflate(InputStream* in, android::IDiagnostics* diag,
187                                       const android::Source& source) {
188    Stack stack;
189  
190    std::unique_ptr<std::remove_pointer<XML_Parser>::type, decltype(XML_ParserFree)*> parser = {
191        XML_ParserCreateNS(nullptr, kXmlNamespaceSep), XML_ParserFree};
192    XML_SetUserData(parser.get(), &stack);
193    XML_UseParserAsHandlerArg(parser.get());
194    XML_SetElementHandler(parser.get(), StartElementHandler, EndElementHandler);
195    XML_SetNamespaceDeclHandler(parser.get(), StartNamespaceHandler, EndNamespaceHandler);
196    XML_SetCharacterDataHandler(parser.get(), CharacterDataHandler);
197    XML_SetCommentHandler(parser.get(), CommentDataHandler);
198  
199    const char* buffer = nullptr;
200    size_t buffer_size = 0;
201    while (in->Next(reinterpret_cast<const void**>(&buffer), &buffer_size)) {
202      if (XML_Parse(parser.get(), buffer, buffer_size, false) == XML_STATUS_ERROR) {
203        diag->Error(android::DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
204                    << XML_ErrorString(XML_GetErrorCode(parser.get())));
205        return {};
206      }
207    }
208  
209    if (in->HadError()) {
210      diag->Error(android::DiagMessage(source) << in->GetError());
211      return {};
212    } else {
213      // Finish off the parsing.
214      if (XML_Parse(parser.get(), nullptr, 0u, true) == XML_STATUS_ERROR) {
215        diag->Error(android::DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
216                    << XML_ErrorString(XML_GetErrorCode(parser.get())));
217        return {};
218      }
219    }
220    return util::make_unique<XmlResource>(ResourceFile{{}, {}, ResourceFile::Type::kUnknown, source},
221                                          android::StringPool{}, std::move(stack.root));
222  }
223  
CopyAttributes(Element * el,android::ResXMLParser * parser,android::StringPool * out_pool)224  static void CopyAttributes(Element* el, android::ResXMLParser* parser,
225                             android::StringPool* out_pool) {
226    const size_t attr_count = parser->getAttributeCount();
227    if (attr_count > 0) {
228      el->attributes.reserve(attr_count);
229      for (size_t i = 0; i < attr_count; i++) {
230        Attribute attr;
231        size_t len;
232        const char16_t* str16 = parser->getAttributeNamespace(i, &len);
233        if (str16) {
234          attr.namespace_uri = android::util::Utf16ToUtf8(StringPiece16(str16, len));
235        }
236  
237        str16 = parser->getAttributeName(i, &len);
238        if (str16) {
239          attr.name = android::util::Utf16ToUtf8(StringPiece16(str16, len));
240        }
241  
242        uint32_t res_id = parser->getAttributeNameResID(i);
243        if (res_id > 0) {
244          attr.compiled_attribute = AaptAttribute(::aapt::Attribute(), {res_id});
245        }
246  
247        str16 = parser->getAttributeStringValue(i, &len);
248        if (str16) {
249          attr.value = android::util::Utf16ToUtf8(StringPiece16(str16, len));
250        }
251  
252        android::Res_value res_value;
253        if (parser->getAttributeValue(i, &res_value) > 0) {
254          // Only compile the value if it is not a string, or it is a string that differs from
255          // the raw attribute value.
256          int32_t raw_value_idx = parser->getAttributeValueStringID(i);
257          if (res_value.dataType != android::Res_value::TYPE_STRING || raw_value_idx < 0 ||
258              static_cast<uint32_t>(raw_value_idx) != res_value.data) {
259            attr.compiled_value = ResourceUtils::ParseBinaryResValue(
260                ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
261          }
262        }
263  
264        el->attributes.push_back(std::move(attr));
265      }
266    }
267  }
268  
Inflate(const void * data,size_t len,std::string * out_error)269  std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string* out_error) {
270    TRACE_CALL();
271    // We import the android namespace because on Windows NO_ERROR is a macro, not
272    // an enum, which causes errors when qualifying it with android::
273    using namespace android;
274  
275    std::unique_ptr<XmlResource> xml_resource = util::make_unique<XmlResource>();
276  
277    std::stack<Element*> node_stack;
278    std::unique_ptr<Element> pending_element;
279  
280    ResXMLTree tree;
281    if (tree.setTo(data, len) != NO_ERROR) {
282      if (out_error != nullptr) {
283        *out_error = "failed to initialize ResXMLTree";
284      }
285      return {};
286    }
287  
288    ResXMLParser::event_code_t code;
289    while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT && code != ResXMLParser::END_DOCUMENT) {
290      std::unique_ptr<Node> new_node;
291      switch (code) {
292        case ResXMLParser::START_NAMESPACE: {
293          NamespaceDecl decl;
294          decl.line_number = tree.getLineNumber();
295  
296          size_t len;
297          const char16_t* str16 = tree.getNamespacePrefix(&len);
298          if (str16) {
299            decl.prefix = android::util::Utf16ToUtf8(StringPiece16(str16, len));
300          }
301  
302          str16 = tree.getNamespaceUri(&len);
303          if (str16) {
304            decl.uri = android::util::Utf16ToUtf8(StringPiece16(str16, len));
305          }
306  
307          if (pending_element == nullptr) {
308            pending_element = util::make_unique<Element>();
309          }
310          // pending_element is not nullptr
311          // NOLINTNEXTLINE(bugprone-use-after-move)
312          pending_element->namespace_decls.push_back(std::move(decl));
313          break;
314        }
315  
316        case ResXMLParser::START_TAG: {
317          std::unique_ptr<Element> el;
318          if (pending_element != nullptr) {
319            el = std::move(pending_element);
320          } else {
321            el = util::make_unique<Element>();
322          }
323          el->line_number = tree.getLineNumber();
324  
325          size_t len;
326          const char16_t* str16 = tree.getElementNamespace(&len);
327          if (str16) {
328            el->namespace_uri = android::util::Utf16ToUtf8(StringPiece16(str16, len));
329          }
330  
331          str16 = tree.getElementName(&len);
332          if (str16) {
333            el->name = android::util::Utf16ToUtf8(StringPiece16(str16, len));
334          }
335  
336          Element* this_el = el.get();
337          CopyAttributes(el.get(), &tree, &xml_resource->string_pool);
338  
339          if (!node_stack.empty()) {
340            node_stack.top()->AppendChild(std::move(el));
341          } else {
342            xml_resource->root = std::move(el);
343          }
344          node_stack.push(this_el);
345          break;
346        }
347  
348        case ResXMLParser::TEXT: {
349          std::unique_ptr<Text> text = util::make_unique<Text>();
350          text->line_number = tree.getLineNumber();
351          size_t len;
352          const char16_t* str16 = tree.getText(&len);
353          if (str16) {
354            text->text = android::util::Utf16ToUtf8(StringPiece16(str16, len));
355          }
356          CHECK(!node_stack.empty());
357          node_stack.top()->AppendChild(std::move(text));
358          break;
359        }
360  
361        case ResXMLParser::END_NAMESPACE:
362          break;
363  
364        case ResXMLParser::END_TAG:
365          CHECK(!node_stack.empty());
366          node_stack.pop();
367          break;
368  
369        default:
370          LOG(FATAL) << "unhandled XML chunk type";
371          break;
372      }
373    }
374    return xml_resource;
375  }
376  
Clone() const377  std::unique_ptr<XmlResource> XmlResource::Clone() const {
378    std::unique_ptr<XmlResource> cloned = util::make_unique<XmlResource>(file);
379    CloningValueTransformer cloner(&cloned->string_pool);
380    if (root != nullptr) {
381      cloned->root = root->CloneElement([&](const xml::Element& src, xml::Element* dst) {
382        dst->attributes.reserve(src.attributes.size());
383        for (const xml::Attribute& attr : src.attributes) {
384          xml::Attribute cloned_attr;
385          cloned_attr.name = attr.name;
386          cloned_attr.namespace_uri = attr.namespace_uri;
387          cloned_attr.value = attr.value;
388          cloned_attr.compiled_attribute = attr.compiled_attribute;
389          if (attr.compiled_value != nullptr) {
390            cloned_attr.compiled_value = attr.compiled_value->Transform(cloner);
391          }
392          dst->attributes.push_back(std::move(cloned_attr));
393        }
394      });
395    }
396    return cloned;
397  }
398  
FindRootElement(Node * node)399  Element* FindRootElement(Node* node) {
400    if (node == nullptr) {
401      return nullptr;
402    }
403  
404    while (node->parent != nullptr) {
405      node = node->parent;
406    }
407    return NodeCast<Element>(node);
408  }
409  
AppendChild(std::unique_ptr<Node> child)410  void Element::AppendChild(std::unique_ptr<Node> child) {
411    child->parent = this;
412    children.push_back(std::move(child));
413  }
414  
InsertChild(size_t index,std::unique_ptr<Node> child)415  void Element::InsertChild(size_t index, std::unique_ptr<Node> child) {
416    child->parent = this;
417    children.insert(children.begin() + index, std::move(child));
418  }
419  
FindAttribute(StringPiece ns,StringPiece name)420  Attribute* Element::FindAttribute(StringPiece ns, StringPiece name) {
421    return const_cast<Attribute*>(static_cast<const Element*>(this)->FindAttribute(ns, name));
422  }
423  
FindAttribute(StringPiece ns,StringPiece name) const424  const Attribute* Element::FindAttribute(StringPiece ns, StringPiece name) const {
425    for (const auto& attr : attributes) {
426      if (ns == attr.namespace_uri && name == attr.name) {
427        return &attr;
428      }
429    }
430    return nullptr;
431  }
432  
RemoveAttribute(StringPiece ns,StringPiece name)433  void Element::RemoveAttribute(StringPiece ns, StringPiece name) {
434    auto new_attr_end = std::remove_if(attributes.begin(), attributes.end(),
435      [&](const Attribute& attr) -> bool {
436        return ns == attr.namespace_uri && name == attr.name;
437      });
438  
439    attributes.erase(new_attr_end, attributes.end());
440  }
441  
FindOrCreateAttribute(StringPiece ns,StringPiece name)442  Attribute* Element::FindOrCreateAttribute(StringPiece ns, StringPiece name) {
443    Attribute* attr = FindAttribute(ns, name);
444    if (attr == nullptr) {
445      attributes.push_back(Attribute{std::string(ns), std::string(name)});
446      attr = &attributes.back();
447    }
448    return attr;
449  }
450  
FindChild(StringPiece ns,StringPiece name)451  Element* Element::FindChild(StringPiece ns, StringPiece name) {
452    return FindChildWithAttribute(ns, name, {}, {}, {});
453  }
454  
FindChild(StringPiece ns,StringPiece name) const455  const Element* Element::FindChild(StringPiece ns, StringPiece name) const {
456    return FindChildWithAttribute(ns, name, {}, {}, {});
457  }
458  
FindChildWithAttribute(StringPiece ns,StringPiece name,StringPiece attr_ns,StringPiece attr_name,StringPiece attr_value)459  Element* Element::FindChildWithAttribute(StringPiece ns, StringPiece name, StringPiece attr_ns,
460                                           StringPiece attr_name, StringPiece attr_value) {
461    return const_cast<Element*>(static_cast<const Element*>(this)->FindChildWithAttribute(
462        ns, name, attr_ns, attr_name, attr_value));
463  }
464  
FindChildWithAttribute(StringPiece ns,StringPiece name,StringPiece attr_ns,StringPiece attr_name,StringPiece attr_value) const465  const Element* Element::FindChildWithAttribute(StringPiece ns, StringPiece name,
466                                                 StringPiece attr_ns, StringPiece attr_name,
467                                                 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 (std::optional<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(StringPiece alias) const559  std::optional<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
560      StringPiece alias) const {
561    if (alias.empty()) {
562      return ExtractedPackage{{}, false /*private*/};
563    }
564  
565    const auto rend = package_decls_.rend();
566    for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
567      const std::vector<PackageDecl>& decls = *iter;
568      const auto rend2 = decls.rend();
569      for (auto iter2 = decls.rbegin(); iter2 != rend2; ++iter2) {
570        const PackageDecl& decl = *iter2;
571        if (alias == decl.prefix) {
572          if (decl.package.package.empty()) {
573            return ExtractedPackage{{}, decl.package.private_namespace};
574          }
575          return decl.package;
576        }
577      }
578    }
579    return {};
580  }
581  
582  }  // namespace xml
583  }  // namespace aapt
584