Home | History | Annotate | Download | only in xml
      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.
     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 
     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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    373 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 
    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 
    405 void Element::AppendChild(std::unique_ptr<Node> child) {
    406   child->parent = this;
    407   children.push_back(std::move(child));
    408 }
    409 
    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 
    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 
    419 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 
    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 
    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 
    446 Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
    447   return FindChildWithAttribute(ns, name, {}, {}, {});
    448 }
    449 
    450 const Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) const {
    451   return FindChildWithAttribute(ns, name, {}, {}, {});
    452 }
    453 
    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 
    461 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 
    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 
    492 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 
    509 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 
    513 void Element::Accept(Visitor* visitor) {
    514   visitor->BeforeVisitElement(this);
    515   visitor->Visit(this);
    516   visitor->AfterVisitElement(this);
    517 }
    518 
    519 void Element::Accept(ConstVisitor* visitor) const {
    520   visitor->BeforeVisitElement(this);
    521   visitor->Visit(this);
    522   visitor->AfterVisitElement(this);
    523 }
    524 
    525 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 
    534 void Text::Accept(Visitor* visitor) {
    535   visitor->Visit(this);
    536 }
    537 
    538 void Text::Accept(ConstVisitor* visitor) const {
    539   visitor->Visit(this);
    540 }
    541 
    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 
    552 void PackageAwareVisitor::AfterVisitElement(Element* el) {
    553   package_decls_.pop_back();
    554 }
    555 
    556 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