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