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