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#include "XmlPullParser.h" 19#include "util/Util.h" 20 21#include <cassert> 22#include <expat.h> 23#include <memory> 24#include <stack> 25#include <string> 26#include <tuple> 27 28namespace aapt { 29namespace xml { 30 31constexpr char kXmlNamespaceSep = 1; 32 33struct Stack { 34 std::unique_ptr<xml::Node> root; 35 std::stack<xml::Node*> nodeStack; 36 std::u16string pendingComment; 37}; 38 39/** 40 * Extracts the namespace and name of an expanded element or attribute name. 41 */ 42static void splitName(const char* name, std::u16string* outNs, std::u16string* outName) { 43 const char* p = name; 44 while (*p != 0 && *p != kXmlNamespaceSep) { 45 p++; 46 } 47 48 if (*p == 0) { 49 outNs->clear(); 50 *outName = util::utf8ToUtf16(name); 51 } else { 52 *outNs = util::utf8ToUtf16(StringPiece(name, (p - name))); 53 *outName = util::utf8ToUtf16(p + 1); 54 } 55} 56 57static void addToStack(Stack* stack, XML_Parser parser, std::unique_ptr<Node> node) { 58 node->lineNumber = XML_GetCurrentLineNumber(parser); 59 node->columnNumber = XML_GetCurrentColumnNumber(parser); 60 61 Node* thisNode = node.get(); 62 if (!stack->nodeStack.empty()) { 63 stack->nodeStack.top()->addChild(std::move(node)); 64 } else { 65 stack->root = std::move(node); 66 } 67 68 if (!nodeCast<Text>(thisNode)) { 69 stack->nodeStack.push(thisNode); 70 } 71} 72 73static void XMLCALL startNamespaceHandler(void* userData, const char* prefix, const char* uri) { 74 XML_Parser parser = reinterpret_cast<XML_Parser>(userData); 75 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser)); 76 77 std::unique_ptr<Namespace> ns = util::make_unique<Namespace>(); 78 if (prefix) { 79 ns->namespacePrefix = util::utf8ToUtf16(prefix); 80 } 81 82 if (uri) { 83 ns->namespaceUri = util::utf8ToUtf16(uri); 84 } 85 86 addToStack(stack, parser, std::move(ns)); 87} 88 89static void XMLCALL endNamespaceHandler(void* userData, const char* prefix) { 90 XML_Parser parser = reinterpret_cast<XML_Parser>(userData); 91 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser)); 92 93 assert(!stack->nodeStack.empty()); 94 stack->nodeStack.pop(); 95} 96 97static bool lessAttribute(const Attribute& lhs, const Attribute& rhs) { 98 return std::tie(lhs.namespaceUri, lhs.name, lhs.value) < 99 std::tie(rhs.namespaceUri, rhs.name, rhs.value); 100} 101 102static void XMLCALL startElementHandler(void* userData, const char* name, const char** attrs) { 103 XML_Parser parser = reinterpret_cast<XML_Parser>(userData); 104 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser)); 105 106 std::unique_ptr<Element> el = util::make_unique<Element>(); 107 splitName(name, &el->namespaceUri, &el->name); 108 109 while (*attrs) { 110 Attribute attribute; 111 splitName(*attrs++, &attribute.namespaceUri, &attribute.name); 112 attribute.value = util::utf8ToUtf16(*attrs++); 113 114 // Insert in sorted order. 115 auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(), attribute, 116 lessAttribute); 117 el->attributes.insert(iter, std::move(attribute)); 118 } 119 120 el->comment = std::move(stack->pendingComment); 121 addToStack(stack, parser, std::move(el)); 122} 123 124static void XMLCALL endElementHandler(void* userData, const char* name) { 125 XML_Parser parser = reinterpret_cast<XML_Parser>(userData); 126 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser)); 127 128 assert(!stack->nodeStack.empty()); 129 //stack->nodeStack.top()->comment = std::move(stack->pendingComment); 130 stack->nodeStack.pop(); 131} 132 133static void XMLCALL characterDataHandler(void* userData, const char* s, int len) { 134 XML_Parser parser = reinterpret_cast<XML_Parser>(userData); 135 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser)); 136 137 if (!s || len <= 0) { 138 return; 139 } 140 141 // See if we can just append the text to a previous text node. 142 if (!stack->nodeStack.empty()) { 143 Node* currentParent = stack->nodeStack.top(); 144 if (!currentParent->children.empty()) { 145 Node* lastChild = currentParent->children.back().get(); 146 if (Text* text = nodeCast<Text>(lastChild)) { 147 text->text += util::utf8ToUtf16(StringPiece(s, len)); 148 return; 149 } 150 } 151 } 152 153 std::unique_ptr<Text> text = util::make_unique<Text>(); 154 text->text = util::utf8ToUtf16(StringPiece(s, len)); 155 addToStack(stack, parser, std::move(text)); 156} 157 158static void XMLCALL commentDataHandler(void* userData, const char* comment) { 159 XML_Parser parser = reinterpret_cast<XML_Parser>(userData); 160 Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser)); 161 162 if (!stack->pendingComment.empty()) { 163 stack->pendingComment += '\n'; 164 } 165 stack->pendingComment += util::utf8ToUtf16(comment); 166} 167 168std::unique_ptr<XmlResource> inflate(std::istream* in, IDiagnostics* diag, const Source& source) { 169 Stack stack; 170 171 XML_Parser parser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep); 172 XML_SetUserData(parser, &stack); 173 XML_UseParserAsHandlerArg(parser); 174 XML_SetElementHandler(parser, startElementHandler, endElementHandler); 175 XML_SetNamespaceDeclHandler(parser, startNamespaceHandler, endNamespaceHandler); 176 XML_SetCharacterDataHandler(parser, characterDataHandler); 177 XML_SetCommentHandler(parser, commentDataHandler); 178 179 char buffer[1024]; 180 while (!in->eof()) { 181 in->read(buffer, sizeof(buffer) / sizeof(buffer[0])); 182 if (in->bad() && !in->eof()) { 183 stack.root = {}; 184 diag->error(DiagMessage(source) << strerror(errno)); 185 break; 186 } 187 188 if (XML_Parse(parser, buffer, in->gcount(), in->eof()) == XML_STATUS_ERROR) { 189 stack.root = {}; 190 diag->error(DiagMessage(source.withLine(XML_GetCurrentLineNumber(parser))) 191 << XML_ErrorString(XML_GetErrorCode(parser))); 192 break; 193 } 194 } 195 196 XML_ParserFree(parser); 197 if (stack.root) { 198 return util::make_unique<XmlResource>(ResourceFile{ {}, {}, source }, std::move(stack.root)); 199 } 200 return {}; 201} 202 203static void copyAttributes(Element* el, android::ResXMLParser* parser) { 204 const size_t attrCount = parser->getAttributeCount(); 205 if (attrCount > 0) { 206 el->attributes.reserve(attrCount); 207 for (size_t i = 0; i < attrCount; i++) { 208 Attribute attr; 209 size_t len; 210 const char16_t* str16 = parser->getAttributeNamespace(i, &len); 211 if (str16) { 212 attr.namespaceUri.assign(str16, len); 213 } 214 215 str16 = parser->getAttributeName(i, &len); 216 if (str16) { 217 attr.name.assign(str16, len); 218 } 219 220 str16 = parser->getAttributeStringValue(i, &len); 221 if (str16) { 222 attr.value.assign(str16, len); 223 } 224 el->attributes.push_back(std::move(attr)); 225 } 226 } 227} 228 229std::unique_ptr<XmlResource> inflate(const void* data, size_t dataLen, IDiagnostics* diag, 230 const Source& source) { 231 // We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which 232 // causes errors when qualifying it with android:: 233 using namespace android; 234 235 std::unique_ptr<Node> root; 236 std::stack<Node*> nodeStack; 237 238 ResXMLTree tree; 239 if (tree.setTo(data, dataLen) != NO_ERROR) { 240 return {}; 241 } 242 243 ResXMLParser::event_code_t code; 244 while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT && 245 code != ResXMLParser::END_DOCUMENT) { 246 std::unique_ptr<Node> newNode; 247 switch (code) { 248 case ResXMLParser::START_NAMESPACE: { 249 std::unique_ptr<Namespace> node = util::make_unique<Namespace>(); 250 size_t len; 251 const char16_t* str16 = tree.getNamespacePrefix(&len); 252 if (str16) { 253 node->namespacePrefix.assign(str16, len); 254 } 255 256 str16 = tree.getNamespaceUri(&len); 257 if (str16) { 258 node->namespaceUri.assign(str16, len); 259 } 260 newNode = std::move(node); 261 break; 262 } 263 264 case ResXMLParser::START_TAG: { 265 std::unique_ptr<Element> node = util::make_unique<Element>(); 266 size_t len; 267 const char16_t* str16 = tree.getElementNamespace(&len); 268 if (str16) { 269 node->namespaceUri.assign(str16, len); 270 } 271 272 str16 = tree.getElementName(&len); 273 if (str16) { 274 node->name.assign(str16, len); 275 } 276 277 copyAttributes(node.get(), &tree); 278 279 newNode = std::move(node); 280 break; 281 } 282 283 case ResXMLParser::TEXT: { 284 std::unique_ptr<Text> node = util::make_unique<Text>(); 285 size_t len; 286 const char16_t* str16 = tree.getText(&len); 287 if (str16) { 288 node->text.assign(str16, len); 289 } 290 newNode = std::move(node); 291 break; 292 } 293 294 case ResXMLParser::END_NAMESPACE: 295 case ResXMLParser::END_TAG: 296 assert(!nodeStack.empty()); 297 nodeStack.pop(); 298 break; 299 300 default: 301 assert(false); 302 break; 303 } 304 305 if (newNode) { 306 newNode->lineNumber = tree.getLineNumber(); 307 308 Node* thisNode = newNode.get(); 309 if (!root) { 310 assert(nodeStack.empty()); 311 root = std::move(newNode); 312 } else { 313 assert(!nodeStack.empty()); 314 nodeStack.top()->addChild(std::move(newNode)); 315 } 316 317 if (!nodeCast<Text>(thisNode)) { 318 nodeStack.push(thisNode); 319 } 320 } 321 } 322 return util::make_unique<XmlResource>(ResourceFile{}, std::move(root)); 323} 324 325Element* findRootElement(XmlResource* doc) { 326 return findRootElement(doc->root.get()); 327} 328 329Element* findRootElement(Node* node) { 330 if (!node) { 331 return nullptr; 332 } 333 334 Element* el = nullptr; 335 while ((el = nodeCast<Element>(node)) == nullptr) { 336 if (node->children.empty()) { 337 return nullptr; 338 } 339 // We are looking for the first element, and namespaces can only have one child. 340 node = node->children.front().get(); 341 } 342 return el; 343} 344 345void Node::addChild(std::unique_ptr<Node> child) { 346 child->parent = this; 347 children.push_back(std::move(child)); 348} 349 350Attribute* Element::findAttribute(const StringPiece16& ns, const StringPiece16& name) { 351 for (auto& attr : attributes) { 352 if (ns == attr.namespaceUri && name == attr.name) { 353 return &attr; 354 } 355 } 356 return nullptr; 357} 358 359Element* Element::findChild(const StringPiece16& ns, const StringPiece16& name) { 360 return findChildWithAttribute(ns, name, {}, {}, {}); 361} 362 363Element* Element::findChildWithAttribute(const StringPiece16& ns, const StringPiece16& name, 364 const StringPiece16& attrNs, const StringPiece16& attrName, 365 const StringPiece16& attrValue) { 366 for (auto& childNode : children) { 367 Node* child = childNode.get(); 368 while (nodeCast<Namespace>(child)) { 369 if (child->children.empty()) { 370 break; 371 } 372 child = child->children[0].get(); 373 } 374 375 if (Element* el = nodeCast<Element>(child)) { 376 if (ns == el->namespaceUri && name == el->name) { 377 if (attrNs.empty() && attrName.empty()) { 378 return el; 379 } 380 381 Attribute* attr = el->findAttribute(attrNs, attrName); 382 if (attr && attrValue == attr->value) { 383 return el; 384 } 385 } 386 } 387 } 388 return nullptr; 389} 390 391std::vector<Element*> Element::getChildElements() { 392 std::vector<Element*> elements; 393 for (auto& childNode : children) { 394 Node* child = childNode.get(); 395 while (nodeCast<Namespace>(child)) { 396 if (child->children.empty()) { 397 break; 398 } 399 child = child->children[0].get(); 400 } 401 402 if (Element* el = nodeCast<Element>(child)) { 403 elements.push_back(el); 404 } 405 } 406 return elements; 407} 408 409void PackageAwareVisitor::visit(Namespace* ns) { 410 bool added = false; 411 if (Maybe<ExtractedPackage> maybePackage = extractPackageFromNamespace(ns->namespaceUri)) { 412 ExtractedPackage& package = maybePackage.value(); 413 mPackageDecls.push_back(PackageDecl{ ns->namespacePrefix, std::move(package) }); 414 added = true; 415 } 416 417 Visitor::visit(ns); 418 419 if (added) { 420 mPackageDecls.pop_back(); 421 } 422} 423 424Maybe<ExtractedPackage> PackageAwareVisitor::transformPackageAlias( 425 const StringPiece16& alias, const StringPiece16& localPackage) const { 426 if (alias.empty()) { 427 return ExtractedPackage{ localPackage.toString(), false /* private */ }; 428 } 429 430 const auto rend = mPackageDecls.rend(); 431 for (auto iter = mPackageDecls.rbegin(); iter != rend; ++iter) { 432 if (alias == iter->prefix) { 433 if (iter->package.package.empty()) { 434 return ExtractedPackage{ localPackage.toString(), 435 iter->package.privateNamespace }; 436 } 437 return iter->package; 438 } 439 } 440 return {}; 441} 442 443} // namespace xml 444} // namespace aapt 445