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