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