summaryrefslogtreecommitdiff
path: root/tools/aapt2/xml/XmlDom.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/aapt2/xml/XmlDom.cpp')
-rw-r--r--tools/aapt2/xml/XmlDom.cpp346
1 files changed, 158 insertions, 188 deletions
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 885ab3e33fed..cbb652ed9a1a 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -29,8 +29,9 @@
#include "XmlPullParser.h"
#include "util/Util.h"
-using android::StringPiece;
-using android::StringPiece16;
+using ::aapt::io::InputStream;
+using ::android::StringPiece;
+using ::android::StringPiece16;
namespace aapt {
namespace xml {
@@ -38,17 +39,15 @@ namespace xml {
constexpr char kXmlNamespaceSep = 1;
struct Stack {
- std::unique_ptr<xml::Node> root;
- std::stack<xml::Node*> node_stack;
+ std::unique_ptr<xml::Element> root;
+ std::stack<xml::Element*> node_stack;
+ std::unique_ptr<xml::Element> pending_element;
std::string pending_comment;
std::unique_ptr<xml::Text> last_text_node;
};
-/**
- * Extracts the namespace and name of an expanded element or attribute name.
- */
-static void SplitName(const char* name, std::string* out_ns,
- std::string* out_name) {
+// Extracts the namespace and name of an expanded element or attribute name.
+static void SplitName(const char* name, std::string* out_ns, std::string* out_name) {
const char* p = name;
while (*p != 0 && *p != kXmlNamespaceSep) {
p++;
@@ -66,6 +65,7 @@ static void SplitName(const char* name, std::string* out_ns,
static void FinishPendingText(Stack* stack) {
if (stack->last_text_node != nullptr) {
if (!stack->last_text_node->text.empty()) {
+ CHECK(!stack->node_stack.empty());
stack->node_stack.top()->AppendChild(std::move(stack->last_text_node));
} else {
// Drop an empty text node.
@@ -74,48 +74,27 @@ static void FinishPendingText(Stack* stack) {
}
}
-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()) {
- stack->node_stack.top()->AppendChild(std::move(node));
- } else {
- stack->root = std::move(node);
- }
-
- if (!NodeCast<Text>(this_node)) {
- stack->node_stack.push(this_node);
- }
-}
-
-static void XMLCALL StartNamespaceHandler(void* user_data, const char* prefix,
- const char* uri) {
+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));
FinishPendingText(stack);
- std::unique_ptr<Namespace> ns = util::make_unique<Namespace>();
- if (prefix) {
- ns->namespace_prefix = prefix;
- }
+ NamespaceDecl decl;
+ decl.line_number = XML_GetCurrentLineNumber(parser);
+ decl.column_number = XML_GetCurrentColumnNumber(parser);
+ decl.prefix = prefix ? prefix : "";
+ decl.uri = uri ? uri : "";
- if (uri) {
- ns->namespace_uri = uri;
+ if (stack->pending_element == nullptr) {
+ stack->pending_element = util::make_unique<Element>();
}
-
- AddToStack(stack, parser, std::move(ns));
+ stack->pending_element->namespace_decls.push_back(std::move(decl));
}
-static void XMLCALL EndNamespaceHandler(void* user_data, const char* prefix) {
+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));
FinishPendingText(stack);
-
- CHECK(!stack->node_stack.empty());
- stack->node_stack.pop();
}
static bool less_attribute(const Attribute& lhs, const Attribute& rhs) {
@@ -123,28 +102,42 @@ static bool less_attribute(const Attribute& lhs, const Attribute& rhs) {
std::tie(rhs.namespace_uri, rhs.name, rhs.value);
}
-static void XMLCALL StartElementHandler(void* user_data, const char* name,
- const char** attrs) {
+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));
FinishPendingText(stack);
- std::unique_ptr<Element> el = util::make_unique<Element>();
+ std::unique_ptr<Element> el;
+ if (stack->pending_element != nullptr) {
+ el = std::move(stack->pending_element);
+ } else {
+ el = util::make_unique<Element>();
+ }
+
+ el->line_number = XML_GetCurrentLineNumber(parser);
+ el->column_number = XML_GetCurrentColumnNumber(parser);
+ el->comment = std::move(stack->pending_comment);
+
SplitName(name, &el->namespace_uri, &el->name);
while (*attrs) {
Attribute attribute;
SplitName(*attrs++, &attribute.namespace_uri, &attribute.name);
attribute.value = *attrs++;
-
- // Insert in sorted order.
- auto iter = std::lower_bound(el->attributes.begin(), el->attributes.end(), attribute,
- less_attribute);
- el->attributes.insert(iter, std::move(attribute));
+ el->attributes.push_back(std::move(attribute));
}
- el->comment = std::move(stack->pending_comment);
- AddToStack(stack, parser, std::move(el));
+ // Sort the attributes.
+ std::sort(el->attributes.begin(), el->attributes.end(), less_attribute);
+
+ // Add to the stack.
+ Element* this_el = el.get();
+ if (!stack->node_stack.empty()) {
+ stack->node_stack.top()->AppendChild(std::move(el));
+ } else {
+ stack->root = std::move(el);
+ }
+ stack->node_stack.push(this_el);
}
static void XMLCALL EndElementHandler(void* user_data, const char* name) {
@@ -189,40 +182,41 @@ static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
stack->pending_comment += comment;
}
-std::unique_ptr<XmlResource> Inflate(std::istream* in, IDiagnostics* diag, const Source& source) {
+std::unique_ptr<XmlResource> Inflate(InputStream* in, IDiagnostics* diag, const Source& source) {
Stack stack;
- XML_Parser parser = XML_ParserCreateNS(nullptr, kXmlNamespaceSep);
- XML_SetUserData(parser, &stack);
- XML_UseParserAsHandlerArg(parser);
- XML_SetElementHandler(parser, StartElementHandler, EndElementHandler);
- XML_SetNamespaceDeclHandler(parser, StartNamespaceHandler, EndNamespaceHandler);
- 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;
- }
-
- if (XML_Parse(parser, buffer, in->gcount(), in->eof()) == XML_STATUS_ERROR) {
- stack.root = {};
- diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser)))
- << XML_ErrorString(XML_GetErrorCode(parser)));
- break;
+ std::unique_ptr<std::remove_pointer<XML_Parser>::type, decltype(XML_ParserFree)*> parser = {
+ XML_ParserCreateNS(nullptr, kXmlNamespaceSep), XML_ParserFree};
+ XML_SetUserData(parser.get(), &stack);
+ XML_UseParserAsHandlerArg(parser.get());
+ XML_SetElementHandler(parser.get(), StartElementHandler, EndElementHandler);
+ XML_SetNamespaceDeclHandler(parser.get(), StartNamespaceHandler, EndNamespaceHandler);
+ XML_SetCharacterDataHandler(parser.get(), CharacterDataHandler);
+ XML_SetCommentHandler(parser.get(), CommentDataHandler);
+
+ const char* buffer = nullptr;
+ size_t buffer_size = 0;
+ while (in->Next(reinterpret_cast<const void**>(&buffer), &buffer_size)) {
+ if (XML_Parse(parser.get(), buffer, buffer_size, false) == XML_STATUS_ERROR) {
+ diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
+ << XML_ErrorString(XML_GetErrorCode(parser.get())));
+ return {};
}
}
- XML_ParserFree(parser);
- if (stack.root) {
- return util::make_unique<XmlResource>(ResourceFile{{}, {}, source}, StringPool{},
- std::move(stack.root));
+ if (in->HadError()) {
+ diag->Error(DiagMessage(source) << in->GetError());
+ return {};
+ } else {
+ // Finish off the parsing.
+ if (XML_Parse(parser.get(), nullptr, 0u, true) == XML_STATUS_ERROR) {
+ diag->Error(DiagMessage(source.WithLine(XML_GetCurrentLineNumber(parser.get())))
+ << XML_ErrorString(XML_GetErrorCode(parser.get())));
+ return {};
+ }
}
- return {};
+ return util::make_unique<XmlResource>(ResourceFile{{}, {}, source}, StringPool{},
+ std::move(stack.root));
}
static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPool* out_pool) {
@@ -261,13 +255,13 @@ static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPoo
std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnostics* diag,
const Source& source) {
// We import the android namespace because on Windows NO_ERROR is a macro, not
- // an enum, which
- // causes errors when qualifying it with android::
+ // an enum, which causes errors when qualifying it with android::
using namespace android;
StringPool string_pool;
- std::unique_ptr<Node> root;
- std::stack<Node*> node_stack;
+ std::unique_ptr<Element> root;
+ std::stack<Element*> node_stack;
+ std::unique_ptr<Element> pending_element;
ResXMLTree tree;
if (tree.setTo(data, data_len) != NO_ERROR) {
@@ -275,57 +269,76 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnos
}
ResXMLParser::event_code_t code;
- while ((code = tree.next()) != ResXMLParser::BAD_DOCUMENT &&
- code != ResXMLParser::END_DOCUMENT) {
+ 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>();
+ NamespaceDecl decl;
size_t len;
const char16_t* str16 = tree.getNamespacePrefix(&len);
if (str16) {
- node->namespace_prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
+ decl.prefix = util::Utf16ToUtf8(StringPiece16(str16, len));
}
str16 = tree.getNamespaceUri(&len);
if (str16) {
- node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
+ decl.uri = util::Utf16ToUtf8(StringPiece16(str16, len));
+ }
+
+ if (pending_element == nullptr) {
+ pending_element = util::make_unique<Element>();
}
- new_node = std::move(node);
break;
}
case ResXMLParser::START_TAG: {
- std::unique_ptr<Element> node = util::make_unique<Element>();
+ std::unique_ptr<Element> el;
+ if (pending_element != nullptr) {
+ el = std::move(pending_element);
+ } else {
+ el = util::make_unique<Element>();
+ ;
+ }
+
size_t len;
const char16_t* str16 = tree.getElementNamespace(&len);
if (str16) {
- node->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
+ el->namespace_uri = util::Utf16ToUtf8(StringPiece16(str16, len));
}
str16 = tree.getElementName(&len);
if (str16) {
- node->name = util::Utf16ToUtf8(StringPiece16(str16, len));
+ el->name = util::Utf16ToUtf8(StringPiece16(str16, len));
}
- CopyAttributes(node.get(), &tree, &string_pool);
+ Element* this_el = el.get();
+ CopyAttributes(el.get(), &tree, &string_pool);
- new_node = std::move(node);
+ if (!node_stack.empty()) {
+ node_stack.top()->AppendChild(std::move(el));
+ } else {
+ root = std::move(el);
+ }
+ node_stack.push(this_el);
break;
}
case ResXMLParser::TEXT: {
- std::unique_ptr<Text> node = util::make_unique<Text>();
+ std::unique_ptr<Text> text = util::make_unique<Text>();
+ text->line_number = tree.getLineNumber();
size_t len;
const char16_t* str16 = tree.getText(&len);
if (str16) {
- node->text = util::Utf16ToUtf8(StringPiece16(str16, len));
+ text->text = util::Utf16ToUtf8(StringPiece16(str16, len));
}
- new_node = std::move(node);
+ CHECK(!node_stack.empty());
+ node_stack.top()->AppendChild(std::move(text));
break;
}
case ResXMLParser::END_NAMESPACE:
+ break;
+
case ResXMLParser::END_TAG:
CHECK(!node_stack.empty());
node_stack.pop();
@@ -335,74 +348,32 @@ std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnos
LOG(FATAL) << "unhandled XML chunk type";
break;
}
-
- 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";
- node_stack.top()->AppendChild(std::move(new_node));
- }
-
- if (!NodeCast<Text>(this_node)) {
- node_stack.push(this_node);
- }
- }
}
return util::make_unique<XmlResource>(ResourceFile{}, std::move(string_pool), std::move(root));
}
-std::unique_ptr<Node> Namespace::Clone(const ElementCloneFunc& el_cloner) {
- 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) {
- ns->AppendChild(child->Clone(el_cloner));
- }
- return std::move(ns);
-}
-
-Element* FindRootElement(XmlResource* doc) {
- return FindRootElement(doc->root.get());
-}
-
Element* FindRootElement(Node* node) {
- if (!node) {
+ if (node == nullptr) {
return nullptr;
}
- Element* el = nullptr;
- while ((el = NodeCast<Element>(node)) == nullptr) {
- if (node->children.empty()) {
- return nullptr;
- }
- // We are looking for the first element, and namespaces can only have one
- // child.
- node = node->children.front().get();
+ while (node->parent != nullptr) {
+ node = node->parent;
}
- return el;
+ return NodeCast<Element>(node);
}
-void Node::AppendChild(std::unique_ptr<Node> child) {
+void Element::AppendChild(std::unique_ptr<Node> child) {
child->parent = this;
children.push_back(std::move(child));
}
-void Node::InsertChild(size_t index, std::unique_ptr<Node> child) {
+void Element::InsertChild(size_t index, std::unique_ptr<Node> child) {
child->parent = this;
children.insert(children.begin() + index, std::move(child));
}
-Attribute* Element::FindAttribute(const StringPiece& ns,
- const StringPiece& name) {
+Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) {
for (auto& attr : attributes) {
if (ns == attr.namespace_uri && name == attr.name) {
return &attr;
@@ -424,21 +395,11 @@ Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
return FindChildWithAttribute(ns, name, {}, {}, {});
}
-Element* Element::FindChildWithAttribute(const StringPiece& ns,
- const StringPiece& name,
- const StringPiece& attr_ns,
- const StringPiece& attr_name,
+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();
- }
-
- if (Element* el = NodeCast<Element>(child)) {
+ for (auto& child : children) {
+ if (Element* el = NodeCast<Element>(child.get())) {
if (ns == el->namespace_uri && name == el->name) {
if (attr_ns.empty() && attr_name.empty()) {
return el;
@@ -457,23 +418,16 @@ Element* Element::FindChildWithAttribute(const StringPiece& ns,
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();
- }
-
- if (Element* el = NodeCast<Element>(child)) {
- elements.push_back(el);
+ if (Element* child = NodeCast<Element>(child_node.get())) {
+ elements.push_back(child);
}
}
return elements;
}
-std::unique_ptr<Node> Element::Clone(const ElementCloneFunc& el_cloner) {
+std::unique_ptr<Node> Element::Clone(const ElementCloneFunc& el_cloner) const {
auto el = util::make_unique<Element>();
+ el->namespace_decls = namespace_decls;
el->comment = comment;
el->line_number = line_number;
el->column_number = column_number;
@@ -488,7 +442,17 @@ std::unique_ptr<Node> Element::Clone(const ElementCloneFunc& el_cloner) {
return std::move(el);
}
-std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) {
+std::unique_ptr<Element> Element::CloneElement(const ElementCloneFunc& el_cloner) const {
+ return std::unique_ptr<Element>(static_cast<Element*>(Clone(el_cloner).release()));
+}
+
+void Element::Accept(Visitor* visitor) {
+ visitor->BeforeVisitElement(this);
+ visitor->Visit(this);
+ visitor->AfterVisitElement(this);
+}
+
+std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) const {
auto t = util::make_unique<Text>();
t->comment = comment;
t->line_number = line_number;
@@ -497,21 +461,22 @@ std::unique_ptr<Node> Text::Clone(const ElementCloneFunc&) {
return std::move(t);
}
-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);
+void Text::Accept(Visitor* visitor) {
+ visitor->Visit(this);
+}
- if (added) {
- package_decls_.pop_back();
+void PackageAwareVisitor::BeforeVisitElement(Element* el) {
+ std::vector<PackageDecl> decls;
+ for (const NamespaceDecl& decl : el->namespace_decls) {
+ if (Maybe<ExtractedPackage> maybe_package = ExtractPackageFromNamespace(decl.uri)) {
+ decls.push_back(PackageDecl{decl.prefix, std::move(maybe_package.value())});
+ }
}
+ package_decls_.push_back(std::move(decls));
+}
+
+void PackageAwareVisitor::AfterVisitElement(Element* el) {
+ package_decls_.pop_back();
}
Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
@@ -522,11 +487,16 @@ Maybe<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
const auto rend = package_decls_.rend();
for (auto iter = package_decls_.rbegin(); iter != rend; ++iter) {
- if (alias == iter->prefix) {
- if (iter->package.package.empty()) {
- return ExtractedPackage{local_package.to_string(), iter->package.private_namespace};
+ const std::vector<PackageDecl>& decls = *iter;
+ const auto rend2 = decls.rend();
+ for (auto iter2 = decls.rbegin(); iter2 != rend2; ++iter2) {
+ const PackageDecl& decl = *iter2;
+ if (alias == decl.prefix) {
+ if (decl.package.package.empty()) {
+ return ExtractedPackage{local_package.to_string(), decl.package.private_namespace};
+ }
+ return decl.package;
}
- return iter->package;
}
}
return {};