2015-06-03 14:54:23 -07:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
|
|
*
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
*
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
*
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
* limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "XmlDom.h"
|
|
|
|
|
2015-11-16 17:35:44 -08:00
|
|
|
#include <expat.h>
|
2016-10-21 17:56:45 -07:00
|
|
|
|
2015-06-03 14:54:23 -07:00
|
|
|
#include <memory>
|
|
|
|
#include <stack>
|
|
|
|
#include <string>
|
|
|
|
#include <tuple>
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
#include "android-base/logging.h"
|
|
|
|
|
2017-04-03 18:12:45 -07:00
|
|
|
#include "ResourceUtils.h"
|
2016-10-21 17:56:45 -07:00
|
|
|
#include "XmlPullParser.h"
|
|
|
|
#include "util/Util.h"
|
|
|
|
|
2017-01-16 15:07:21 -08:00
|
|
|
using android::StringPiece;
|
|
|
|
using android::StringPiece16;
|
|
|
|
|
2015-06-03 14:54:23 -07:00
|
|
|
namespace aapt {
|
|
|
|
namespace xml {
|
|
|
|
|
|
|
|
constexpr char kXmlNamespaceSep = 1;
|
|
|
|
|
|
|
|
struct Stack {
|
2016-10-21 17:56:45 -07:00
|
|
|
std::unique_ptr<xml::Node> root;
|
|
|
|
std::stack<xml::Node*> node_stack;
|
|
|
|
std::string pending_comment;
|
2017-03-02 19:31:28 -08:00
|
|
|
std::unique_ptr<xml::Text> last_text_node;
|
2015-06-03 14:54:23 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extracts the namespace and name of an expanded element or attribute name.
|
|
|
|
*/
|
2016-10-21 17:56:45 -07:00
|
|
|
static void SplitName(const char* name, std::string* out_ns,
|
|
|
|
std::string* out_name) {
|
|
|
|
const char* p = name;
|
|
|
|
while (*p != 0 && *p != kXmlNamespaceSep) {
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*p == 0) {
|
|
|
|
out_ns->clear();
|
2017-01-16 15:07:21 -08:00
|
|
|
out_name->assign(name);
|
2016-10-21 17:56:45 -07:00
|
|
|
} else {
|
2017-01-16 15:07:21 -08:00
|
|
|
out_ns->assign(name, (p - name));
|
|
|
|
out_name->assign(p + 1);
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2017-03-02 19:31:28 -08:00
|
|
|
static void FinishPendingText(Stack* stack) {
|
|
|
|
if (stack->last_text_node != nullptr) {
|
2017-04-26 15:13:52 -07:00
|
|
|
if (!stack->last_text_node->text.empty()) {
|
2017-03-02 19:31:28 -08:00
|
|
|
stack->node_stack.top()->AppendChild(std::move(stack->last_text_node));
|
|
|
|
} else {
|
|
|
|
// Drop an empty text node.
|
|
|
|
}
|
2017-04-26 15:13:52 -07:00
|
|
|
stack->last_text_node = nullptr;
|
2017-03-02 19:31:28 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
static void AddToStack(Stack* stack, XML_Parser parser,
|
|
|
|
std::unique_ptr<Node> node) {
|
|
|
|
node->line_number = XML_GetCurrentLineNumber(parser);
|
|
|
|
node->column_number = XML_GetCurrentColumnNumber(parser);
|
|
|
|
|
|
|
|
Node* this_node = node.get();
|
|
|
|
if (!stack->node_stack.empty()) {
|
2016-10-27 16:31:58 -07:00
|
|
|
stack->node_stack.top()->AppendChild(std::move(node));
|
2016-10-21 17:56:45 -07:00
|
|
|
} else {
|
|
|
|
stack->root = std::move(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!NodeCast<Text>(this_node)) {
|
|
|
|
stack->node_stack.push(this_node);
|
|
|
|
}
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
static void XMLCALL StartNamespaceHandler(void* user_data, const char* prefix,
|
|
|
|
const char* uri) {
|
|
|
|
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
|
|
|
|
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
|
2017-03-02 19:31:28 -08:00
|
|
|
FinishPendingText(stack);
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
std::unique_ptr<Namespace> ns = util::make_unique<Namespace>();
|
|
|
|
if (prefix) {
|
2017-01-16 15:07:21 -08:00
|
|
|
ns->namespace_prefix = prefix;
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
if (uri) {
|
2017-01-16 15:07:21 -08:00
|
|
|
ns->namespace_uri = uri;
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
AddToStack(stack, parser, std::move(ns));
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
static void XMLCALL EndNamespaceHandler(void* user_data, const char* prefix) {
|
|
|
|
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
|
|
|
|
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
|
2017-03-02 19:31:28 -08:00
|
|
|
FinishPendingText(stack);
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
CHECK(!stack->node_stack.empty());
|
|
|
|
stack->node_stack.pop();
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
static bool less_attribute(const Attribute& lhs, const Attribute& rhs) {
|
|
|
|
return std::tie(lhs.namespace_uri, lhs.name, lhs.value) <
|
|
|
|
std::tie(rhs.namespace_uri, rhs.name, rhs.value);
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
static void XMLCALL StartElementHandler(void* user_data, const char* name,
|
|
|
|
const char** attrs) {
|
|
|
|
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
|
|
|
|
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
|
2017-03-02 19:31:28 -08:00
|
|
|
FinishPendingText(stack);
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
std::unique_ptr<Element> el = util::make_unique<Element>();
|
|
|
|
SplitName(name, &el->namespace_uri, &el->name);
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
while (*attrs) {
|
|
|
|
Attribute attribute;
|
|
|
|
SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
|
2017-04-26 15:13:52 -07:00
|
|
|
attribute.value = *attrs++;
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
// Insert in sorted order.
|
2017-04-26 15:13:52 -07:00
|
|
|
auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(), attribute,
|
|
|
|
less_attribute);
|
2016-10-21 17:56:45 -07:00
|
|
|
el->attributes.insert(iter, std::move(attribute));
|
|
|
|
}
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
el->comment = std::move(stack->pending_comment);
|
|
|
|
AddToStack(stack, parser, std::move(el));
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
static void XMLCALL EndElementHandler(void* user_data, const char* name) {
|
|
|
|
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
|
|
|
|
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
|
2017-03-02 19:31:28 -08:00
|
|
|
FinishPendingText(stack);
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
CHECK(!stack->node_stack.empty());
|
|
|
|
// stack->nodeStack.top()->comment = std::move(stack->pendingComment);
|
|
|
|
stack->node_stack.pop();
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2017-03-02 19:31:28 -08:00
|
|
|
static void XMLCALL CharacterDataHandler(void* user_data, const char* s, int len) {
|
2016-10-21 17:56:45 -07:00
|
|
|
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
|
|
|
|
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
|
|
|
|
|
2017-03-02 19:31:28 -08:00
|
|
|
const StringPiece str(s, len);
|
|
|
|
if (str.empty()) {
|
2016-10-21 17:56:45 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if we can just append the text to a previous text node.
|
2017-03-02 19:31:28 -08:00
|
|
|
if (stack->last_text_node != nullptr) {
|
2017-04-26 15:13:52 -07:00
|
|
|
stack->last_text_node->text.append(str.data(), str.size());
|
2017-03-02 19:31:28 -08:00
|
|
|
return;
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2017-03-02 19:31:28 -08:00
|
|
|
stack->last_text_node = util::make_unique<Text>();
|
|
|
|
stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
|
|
|
|
stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
|
2017-04-26 15:13:52 -07:00
|
|
|
stack->last_text_node->text = str.to_string();
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
|
|
|
|
XML_Parser parser = reinterpret_cast<XML_Parser>(user_data);
|
|
|
|
Stack* stack = reinterpret_cast<Stack*>(XML_GetUserData(parser));
|
2017-03-02 19:31:28 -08:00
|
|
|
FinishPendingText(stack);
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
if (!stack->pending_comment.empty()) {
|
|
|
|
stack->pending_comment += '\n';
|
|
|
|
}
|
|
|
|
stack->pending_comment += comment;
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2017-04-03 18:12:45 -07:00
|
|
|
std::unique_ptr<XmlResource> Inflate(std::istream* in, IDiagnostics* diag, const Source& source) {
|
2016-10-21 17:56:45 -07:00
|
|
|
Stack stack;
|
|
|
|
|
|
|
|
XML_Parser parser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
|
|
|
|
XML_SetUserData(parser, &stack);
|
|
|
|
XML_UseParserAsHandlerArg(parser);
|
|
|
|
XML_SetElementHandler(parser, StartElementHandler, EndElementHandler);
|
2017-04-03 18:12:45 -07:00
|
|
|
XML_SetNamespaceDeclHandler(parser, StartNamespaceHandler, EndNamespaceHandler);
|
2016-10-21 17:56:45 -07:00
|
|
|
XML_SetCharacterDataHandler(parser, CharacterDataHandler);
|
|
|
|
XML_SetCommentHandler(parser, CommentDataHandler);
|
|
|
|
|
|
|
|
char buffer[1024];
|
|
|
|
while (!in->eof()) {
|
|
|
|
in->read(buffer, sizeof(buffer) / sizeof(buffer[0]));
|
|
|
|
if (in->bad() && !in->eof()) {
|
|
|
|
stack.root = {};
|
|
|
|
diag->Error(DiagMessage(source) << strerror(errno));
|
|
|
|
break;
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2017-04-03 18:12:45 -07:00
|
|
|
if (XML_Parse(parser, buffer, in->gcount(), in->eof()) == XML_STATUS_ERROR) {
|
2016-10-21 17:56:45 -07:00
|
|
|
stack.root = {};
|
|
|
|
diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser)))
|
|
|
|
<< XML_ErrorString(XML_GetErrorCode(parser)));
|
|
|
|
break;
|
2015-08-14 14:26:04 -07:00
|
|
|
}
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
XML_ParserFree(parser);
|
|
|
|
if (stack.root) {
|
2017-04-13 12:55:19 -07:00
|
|
|
return util::make_unique<XmlResource>(ResourceFile{{}, {}, source}, StringPool{},
|
|
|
|
std::move(stack.root));
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
|
|
|
return {};
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2017-04-03 18:12:45 -07:00
|
|
|
static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
|
2016-10-21 17:56:45 -07:00
|
|
|
const size_t attr_count = parser->getAttributeCount();
|
|
|
|
if (attr_count > 0) {
|
|
|
|
el->attributes.reserve(attr_count);
|
|
|
|
for (size_t i = 0; i < attr_count; i++) {
|
|
|
|
Attribute attr;
|
|
|
|
size_t len;
|
|
|
|
const char16_t* str16 = parser->getAttributeNamespace(i, &len);
|
|
|
|
if (str16) {
|
|
|
|
attr.namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
|
|
|
|
}
|
|
|
|
|
|
|
|
str16 = parser->getAttributeName(i, &len);
|
|
|
|
if (str16) {
|
|
|
|
attr.name = util::Utf16ToUtf8(StringPiece16(str16, len));
|
|
|
|
}
|
|
|
|
|
|
|
|
str16 = parser->getAttributeStringValue(i, &len);
|
|
|
|
if (str16) {
|
|
|
|
attr.value = util::Utf16ToUtf8(StringPiece16(str16, len));
|
|
|
|
}
|
2017-04-03 18:12:45 -07:00
|
|
|
|
|
|
|
android::Res_value res_value;
|
|
|
|
if (parser->getAttributeValue(i, &res_value) > 0) {
|
|
|
|
attr.compiled_value = ResourceUtils::ParseBinaryResValue(
|
|
|
|
ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool);
|
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
el->attributes.push_back(std::move(attr));
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2017-04-03 18:12:45 -07:00
|
|
|
std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnostics* diag,
|
|
|
|
const Source& source) {
|
2016-10-21 17:56:45 -07:00
|
|
|
// We import the android namespace because on Windows NO_ERROR is a macro, not
|
|
|
|
// an enum, which
|
|
|
|
// causes errors when qualifying it with android::
|
|
|
|
using namespace android;
|
2016-04-06 16:09:43 -07:00
|
|
|
|
2017-04-03 18:12:45 -07:00
|
|
|
StringPool string_pool;
|
2016-10-21 17:56:45 -07:00
|
|
|
std::unique_ptr<Node> root;
|
|
|
|
std::stack<Node*> node_stack;
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
ResXMLTree tree;
|
|
|
|
if (tree.setTo(data, data_len) != NO_ERROR) {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
ResXMLParser::event_code_t code;
|
|
|
|
while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT &&
|
|
|
|
code != ResXMLParser::END_DOCUMENT) {
|
|
|
|
std::unique_ptr<Node> new_node;
|
|
|
|
switch (code) {
|
|
|
|
case ResXMLParser::START_NAMESPACE: {
|
|
|
|
std::unique_ptr<Namespace> node = util::make_unique<Namespace>();
|
|
|
|
size_t len;
|
|
|
|
const char16_t* str16 = tree.getNamespacePrefix(&len);
|
|
|
|
if (str16) {
|
|
|
|
node->namespace_prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
|
|
|
|
}
|
|
|
|
|
|
|
|
str16 = tree.getNamespaceUri(&len);
|
|
|
|
if (str16) {
|
|
|
|
node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
|
|
|
|
}
|
|
|
|
new_node = std::move(node);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ResXMLParser::START_TAG: {
|
|
|
|
std::unique_ptr<Element> node = util::make_unique<Element>();
|
|
|
|
size_t len;
|
|
|
|
const char16_t* str16 = tree.getElementNamespace(&len);
|
|
|
|
if (str16) {
|
|
|
|
node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
|
|
|
|
}
|
2015-06-03 14:54:23 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
str16 = tree.getElementName(&len);
|
|
|
|
if (str16) {
|
|
|
|
node->name = util::Utf16ToUtf8(StringPiece16(str16, len));
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2017-04-03 18:12:45 -07:00
|
|
|
CopyAttributes(node.get(), &tree, &string_pool);
|
2016-10-21 17:56:45 -07:00
|
|
|
|
|
|
|
new_node = std::move(node);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ResXMLParser::TEXT: {
|
|
|
|
std::unique_ptr<Text> node = util::make_unique<Text>();
|
|
|
|
size_t len;
|
|
|
|
const char16_t* str16 = tree.getText(&len);
|
|
|
|
if (str16) {
|
|
|
|
node->text = util::Utf16ToUtf8(StringPiece16(str16, len));
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
2016-10-21 17:56:45 -07:00
|
|
|
new_node = std::move(node);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ResXMLParser::END_NAMESPACE:
|
|
|
|
case ResXMLParser::END_TAG:
|
|
|
|
CHECK(!node_stack.empty());
|
|
|
|
node_stack.pop();
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
LOG(FATAL) << "unhandled XML chunk type";
|
|
|
|
break;
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
if (new_node) {
|
|
|
|
new_node->line_number = tree.getLineNumber();
|
|
|
|
|
|
|
|
Node* this_node = new_node.get();
|
|
|
|
if (!root) {
|
|
|
|
CHECK(node_stack.empty()) << "node stack should be empty";
|
|
|
|
root = std::move(new_node);
|
|
|
|
} else {
|
|
|
|
CHECK(!node_stack.empty()) << "node stack should not be empty";
|
2016-10-27 16:31:58 -07:00
|
|
|
node_stack.top()->AppendChild(std::move(new_node));
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!NodeCast<Text>(this_node)) {
|
|
|
|
node_stack.push(this_node);
|
|
|
|
}
|
2016-08-25 12:26:56 -07:00
|
|
|
}
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
2017-04-13 12:55:19 -07:00
|
|
|
return util::make_unique<XmlResource>(ResourceFile{}, std::move(string_pool), std::move(root));
|
2016-08-25 12:26:56 -07:00
|
|
|
}
|
|
|
|
|
2017-05-17 19:28:38 -07:00
|
|
|
std::unique_ptr<Node> Namespace::Clone(const ElementCloneFunc& el_cloner) {
|
2016-10-21 17:56:45 -07:00
|
|
|
auto ns = util::make_unique<Namespace>();
|
|
|
|
ns->comment = comment;
|
|
|
|
ns->line_number = line_number;
|
|
|
|
ns->column_number = column_number;
|
|
|
|
ns->namespace_prefix = namespace_prefix;
|
|
|
|
ns->namespace_uri = namespace_uri;
|
|
|
|
ns->children.reserve(children.size());
|
|
|
|
for (const std::unique_ptr<xml::Node>& child : children) {
|
2017-05-17 19:28:38 -07:00
|
|
|
ns->AppendChild(child->Clone(el_cloner));
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
|
|
|
return std::move(ns);
|
2015-11-16 17:35:44 -08:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
Element* FindRootElement(XmlResource* doc) {
|
|
|
|
return FindRootElement(doc->root.get());
|
|
|
|
}
|
2015-10-21 14:42:43 -07:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
Element* FindRootElement(Node* node) {
|
|
|
|
if (!node) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
Element* el = nullptr;
|
|
|
|
while ((el = NodeCast<Element>(node)) == nullptr) {
|
|
|
|
if (node->children.empty()) {
|
|
|
|
return nullptr;
|
2015-10-21 14:42:43 -07:00
|
|
|
}
|
2016-10-21 17:56:45 -07:00
|
|
|
// We are looking for the first element, and namespaces can only have one
|
|
|
|
// child.
|
|
|
|
node = node->children.front().get();
|
|
|
|
}
|
|
|
|
return el;
|
2015-10-21 14:42:43 -07:00
|
|
|
}
|
|
|
|
|
2016-10-27 16:31:58 -07:00
|
|
|
void Node::AppendChild(std::unique_ptr<Node> child) {
|
2016-10-21 17:56:45 -07:00
|
|
|
child->parent = this;
|
|
|
|
children.push_back(std::move(child));
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-27 16:31:58 -07:00
|
|
|
void Node::InsertChild(size_t index, std::unique_ptr<Node> child) {
|
|
|
|
child->parent = this;
|
|
|
|
children.insert(children.begin() + index, std::move(child));
|
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
Attribute* Element::FindAttribute(const StringPiece& ns,
|
|
|
|
const StringPiece& name) {
|
|
|
|
for (auto& attr : attributes) {
|
|
|
|
if (ns == attr.namespace_uri && name == attr.name) {
|
|
|
|
return &attr;
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
|
|
|
return nullptr;
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2017-05-17 19:28:38 -07:00
|
|
|
const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
|
|
|
|
for (const auto& attr : attributes) {
|
|
|
|
if (ns == attr.namespace_uri && name == attr.name) {
|
|
|
|
return &attr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
|
|
|
|
return FindChildWithAttribute(ns, name, {}, {}, {});
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
Element* Element::FindChildWithAttribute(const StringPiece& ns,
|
|
|
|
const StringPiece& name,
|
|
|
|
const StringPiece& attr_ns,
|
|
|
|
const StringPiece& attr_name,
|
|
|
|
const StringPiece& attr_value) {
|
|
|
|
for (auto& child_node : children) {
|
|
|
|
Node* child = child_node.get();
|
|
|
|
while (NodeCast<Namespace>(child)) {
|
|
|
|
if (child->children.empty()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
child = child->children[0].get();
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
if (Element* el = NodeCast<Element>(child)) {
|
|
|
|
if (ns == el->namespace_uri && name == el->name) {
|
|
|
|
if (attr_ns.empty() && attr_name.empty()) {
|
|
|
|
return el;
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
Attribute* attr = el->FindAttribute(attr_ns, attr_name);
|
|
|
|
if (attr && attr_value == attr->value) {
|
|
|
|
return el;
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
|
|
|
return nullptr;
|
2015-06-03 14:54:23 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
std::vector<Element*> Element::GetChildElements() {
|
|
|
|
std::vector<Element*> elements;
|
|
|
|
for (auto& child_node : children) {
|
|
|
|
Node* child = child_node.get();
|
|
|
|
while (NodeCast<Namespace>(child)) {
|
|
|
|
if (child->children.empty()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
child = child->children[0].get();
|
2016-08-25 12:26:56 -07:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
if (Element* el = NodeCast<Element>(child)) {
|
|
|
|
elements.push_back(el);
|
2016-08-25 12:26:56 -07:00
|
|
|
}
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
|
|
|
return elements;
|
2016-08-25 12:26:56 -07:00
|
|
|
}
|
|
|
|
|
2017-05-17 19:28:38 -07:00
|
|
|
std::unique_ptr<Node> Element::Clone(const ElementCloneFunc& el_cloner) {
|
2016-10-21 17:56:45 -07:00
|
|
|
auto el = util::make_unique<Element>();
|
|
|
|
el->comment = comment;
|
|
|
|
el->line_number = line_number;
|
|
|
|
el->column_number = column_number;
|
|
|
|
el->name = name;
|
|
|
|
el->namespace_uri = namespace_uri;
|
|
|
|
el->attributes.reserve(attributes.size());
|
2017-05-17 19:28:38 -07:00
|
|
|
el_cloner(*this, el.get());
|
2016-10-21 17:56:45 -07:00
|
|
|
el->children.reserve(children.size());
|
|
|
|
for (const std::unique_ptr<xml::Node>& child : children) {
|
2017-05-17 19:28:38 -07:00
|
|
|
el->AppendChild(child->Clone(el_cloner));
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
|
|
|
return std::move(el);
|
2016-08-25 12:26:56 -07:00
|
|
|
}
|
|
|
|
|
2017-05-17 19:28:38 -07:00
|
|
|
std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) {
|
2016-10-21 17:56:45 -07:00
|
|
|
auto t = util::make_unique<Text>();
|
|
|
|
t->comment = comment;
|
|
|
|
t->line_number = line_number;
|
|
|
|
t->column_number = column_number;
|
|
|
|
t->text = text;
|
|
|
|
return std::move(t);
|
|
|
|
}
|
2015-11-16 17:35:44 -08:00
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
void PackageAwareVisitor::Visit(Namespace* ns) {
|
|
|
|
bool added = false;
|
|
|
|
if (Maybe<ExtractedPackage> maybe_package =
|
|
|
|
ExtractPackageFromNamespace(ns->namespace_uri)) {
|
|
|
|
ExtractedPackage& package = maybe_package.value();
|
|
|
|
package_decls_.push_back(
|
|
|
|
PackageDecl{ns->namespace_prefix, std::move(package)});
|
|
|
|
added = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Visitor::Visit(ns);
|
|
|
|
|
|
|
|
if (added) {
|
|
|
|
package_decls_.pop_back();
|
|
|
|
}
|
2015-11-16 17:35:44 -08:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
|
|
|
|
const StringPiece& alias, const StringPiece& local_package) const {
|
|
|
|
if (alias.empty()) {
|
2017-01-16 15:07:21 -08:00
|
|
|
return ExtractedPackage{local_package.to_string(), false /* private */};
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const auto rend = package_decls_.rend();
|
|
|
|
for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
|
|
|
|
if (alias == iter->prefix) {
|
|
|
|
if (iter->package.package.empty()) {
|
2017-01-16 15:07:21 -08:00
|
|
|
return ExtractedPackage{local_package.to_string(), iter->package.private_namespace};
|
2016-10-21 17:56:45 -07:00
|
|
|
}
|
|
|
|
return iter->package;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {};
|
2015-11-16 17:35:44 -08:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:56:45 -07:00
|
|
|
} // namespace xml
|
|
|
|
} // namespace aapt
|