Loading tools/aapt2/Debug.cpp +31 −33 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,8 @@ namespace aapt { namespace aapt { namespace { class PrintVisitor : public ValueVisitor { class PrintVisitor : public ValueVisitor { public: public: using ValueVisitor::Visit; using ValueVisitor::Visit; Loading Loading @@ -88,9 +90,13 @@ class PrintVisitor : public ValueVisitor { } } } } void Visit(Array* array) override { array->Print(&std::cout); } void Visit(Array* array) override { array->Print(&std::cout); } void Visit(Plural* plural) override { plural->Print(&std::cout); } void Visit(Plural* plural) override { plural->Print(&std::cout); } void Visit(Styleable* styleable) override { void Visit(Styleable* styleable) override { std::cout << "(styleable)"; std::cout << "(styleable)"; Loading @@ -110,11 +116,14 @@ class PrintVisitor : public ValueVisitor { } } } } void VisitItem(Item* item) override { item->Print(&std::cout); } void VisitItem(Item* item) override { item->Print(&std::cout); } }; }; void Debug::PrintTable(ResourceTable* table, } // namespace const DebugPrintTableOptions& options) { void Debug::PrintTable(ResourceTable* table, const DebugPrintTableOptions& options) { PrintVisitor visitor; PrintVisitor visitor; for (auto& package : table->packages) { for (auto& package : table->packages) { Loading Loading @@ -148,10 +157,9 @@ void Debug::PrintTable(ResourceTable* table, } } for (const ResourceEntry* entry : sorted_entries) { for (const ResourceEntry* entry : sorted_entries) { ResourceId id(package->id ? package->id.value() : uint8_t(0), const ResourceId id(package->id.value_or_default(0), type->id.value_or_default(0), type->id ? type->id.value() : uint8_t(0), entry->id.value_or_default(0)); entry->id ? entry->id.value() : uint16_t(0)); const ResourceName name(package->name, type->type, entry->name); ResourceName name(package->name, type->type, entry->name); std::cout << " spec resource " << id << " " << name; std::cout << " spec resource " << id << " " << name; switch (entry->symbol_status.state) { switch (entry->symbol_status.state) { Loading Loading @@ -180,16 +188,14 @@ void Debug::PrintTable(ResourceTable* table, } } } } static size_t GetNodeIndex(const std::vector<ResourceName>& names, static size_t GetNodeIndex(const std::vector<ResourceName>& names, const ResourceName& name) { const ResourceName& name) { auto iter = std::lower_bound(names.begin(), names.end(), name); auto iter = std::lower_bound(names.begin(), names.end(), name); CHECK(iter != names.end()); CHECK(iter != names.end()); CHECK(*iter == name); CHECK(*iter == name); return std::distance(names.begin(), iter); return std::distance(names.begin(), iter); } } void Debug::PrintStyleGraph(ResourceTable* table, void Debug::PrintStyleGraph(ResourceTable* table, const ResourceName& target_style) { const ResourceName& target_style) { std::map<ResourceName, std::set<ResourceName>> graph; std::map<ResourceName, std::set<ResourceName>> graph; std::queue<ResourceName> styles_to_visit; std::queue<ResourceName> styles_to_visit; Loading Loading @@ -223,8 +229,7 @@ void Debug::PrintStyleGraph(ResourceTable* table, std::cout << "digraph styles {\n"; std::cout << "digraph styles {\n"; for (const auto& name : names) { for (const auto& name : names) { std::cout << " node_" << GetNodeIndex(names, name) << " [label=\"" << name std::cout << " node_" << GetNodeIndex(names, name) << " [label=\"" << name << "\"];\n"; << "\"];\n"; } } for (const auto& entry : graph) { for (const auto& entry : graph) { Loading @@ -243,8 +248,7 @@ void Debug::PrintStyleGraph(ResourceTable* table, void Debug::DumpHex(const void* data, size_t len) { void Debug::DumpHex(const void* data, size_t len) { const uint8_t* d = (const uint8_t*)data; const uint8_t* d = (const uint8_t*)data; for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) { std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)d[i] std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)d[i] << " "; << " "; if (i % 8 == 7) { if (i % 8 == 7) { std::cerr << "\n"; std::cerr << "\n"; } } Loading @@ -262,8 +266,15 @@ class XmlPrinter : public xml::Visitor { using xml::Visitor::Visit; using xml::Visitor::Visit; void Visit(xml::Element* el) override { void Visit(xml::Element* el) override { std::cerr << prefix_; const size_t previous_size = prefix_.size(); std::cerr << "E: "; for (const xml::NamespaceDecl& decl : el->namespace_decls) { std::cerr << prefix_ << "N: " << decl.prefix << "=" << decl.uri << " (line=" << decl.line_number << ")\n"; prefix_ += " "; } std::cerr << prefix_ << "E: "; if (!el->namespace_uri.empty()) { if (!el->namespace_uri.empty()) { std::cerr << el->namespace_uri << ":"; std::cerr << el->namespace_uri << ":"; } } Loading @@ -283,26 +294,13 @@ class XmlPrinter : public xml::Visitor { std::cerr << "=" << attr.value << "\n"; std::cerr << "=" << attr.value << "\n"; } } const size_t previous_size = prefix_.size(); prefix_ += " "; prefix_ += " "; xml::Visitor::Visit(el); xml::Visitor::Visit(el); prefix_.resize(previous_size); prefix_.resize(previous_size); } } void Visit(xml::Namespace* ns) override { std::cerr << prefix_; std::cerr << "N: " << ns->namespace_prefix << "=" << ns->namespace_uri << " (line=" << ns->line_number << ")\n"; const size_t previous_size = prefix_.size(); prefix_ += " "; xml::Visitor::Visit(ns); prefix_.resize(previous_size); } void Visit(xml::Text* text) override { void Visit(xml::Text* text) override { std::cerr << prefix_; std::cerr << prefix_ << "T: '" << text->text << "'\n"; std::cerr << "T: '" << text->text << "'\n"; } } private: private: Loading tools/aapt2/cmd/Link.cpp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -482,7 +482,7 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer if (options_.no_version_vectors || options_.no_version_transitions) { if (options_.no_version_vectors || options_.no_version_transitions) { // Skip this if it is a vector or animated-vector. // Skip this if it is a vector or animated-vector. xml::Element* el = xml::FindRootElement(doc); xml::Element* el = doc->root.get(); if (el && el->namespace_uri.empty()) { if (el && el->namespace_uri.empty()) { if ((options_.no_version_vectors && IsVectorElement(el->name)) || if ((options_.no_version_vectors && IsVectorElement(el->name)) || (options_.no_version_transitions && IsTransitionElement(el->name))) { (options_.no_version_transitions && IsTransitionElement(el->name))) { Loading tools/aapt2/cmd/Util.cpp +15 −12 Original line number Original line Diff line number Diff line Loading @@ -28,7 +28,7 @@ #include "util/Maybe.h" #include "util/Maybe.h" #include "util/Util.h" #include "util/Util.h" using android::StringPiece; using ::android::StringPiece; namespace aapt { namespace aapt { Loading Loading @@ -134,19 +134,21 @@ static xml::AaptAttribute CreateAttributeWithId(const ResourceId& id) { return xml::AaptAttribute(Attribute(), id); return xml::AaptAttribute(Attribute(), id); } } static xml::NamespaceDecl CreateAndroidNamespaceDecl() { xml::NamespaceDecl decl; decl.prefix = "android"; decl.uri = xml::kSchemaAndroid; return decl; } std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info, std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info, const SplitConstraints& constraints) { const SplitConstraints& constraints) { const ResourceId kVersionCode(0x0101021b); const ResourceId kVersionCode(0x0101021b); const ResourceId kRevisionCode(0x010104d5); const ResourceId kRevisionCode(0x010104d5); const ResourceId kHasCode(0x0101000c); const ResourceId kHasCode(0x0101000c); std::unique_ptr<xml::XmlResource> doc = util::make_unique<xml::XmlResource>(); std::unique_ptr<xml::Namespace> namespace_android = util::make_unique<xml::Namespace>(); namespace_android->namespace_uri = xml::kSchemaAndroid; namespace_android->namespace_prefix = "android"; std::unique_ptr<xml::Element> manifest_el = util::make_unique<xml::Element>(); std::unique_ptr<xml::Element> manifest_el = util::make_unique<xml::Element>(); manifest_el->namespace_decls.push_back(CreateAndroidNamespaceDecl()); manifest_el->name = "manifest"; manifest_el->name = "manifest"; manifest_el->attributes.push_back(xml::Attribute{"", "package", app_info.package}); manifest_el->attributes.push_back(xml::Attribute{"", "package", app_info.package}); Loading Loading @@ -179,8 +181,8 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info, xml::Attribute{"", "configForSplit", app_info.split_name.value()}); xml::Attribute{"", "configForSplit", app_info.split_name.value()}); } } // Splits may contain more configurations than originally desired (fallback densities, etc.). // Splits may contain more configurations than originally desired (fall-back densities, etc.). // This makes programmatic discovery of split targetting difficult. Encode the original // This makes programmatic discovery of split targeting difficult. Encode the original // split constraints intended for this split. // split constraints intended for this split. std::stringstream target_config_str; std::stringstream target_config_str; target_config_str << util::Joiner(constraints.configs, ","); target_config_str << util::Joiner(constraints.configs, ","); Loading @@ -193,8 +195,9 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info, util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN, 0u)}); util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN, 0u)}); manifest_el->AppendChild(std::move(application_el)); manifest_el->AppendChild(std::move(application_el)); namespace_android->AppendChild(std::move(manifest_el)); doc->root = std::move(namespace_android); std::unique_ptr<xml::XmlResource> doc = util::make_unique<xml::XmlResource>(); doc->root = std::move(manifest_el); return doc; return doc; } } Loading Loading @@ -284,7 +287,7 @@ static Maybe<int> ExtractSdkVersion(xml::Attribute* attr, std::string* out_error Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(xml::XmlResource* xml_res, IDiagnostics* diag) { Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(xml::XmlResource* xml_res, IDiagnostics* diag) { // Make sure the first element is <manifest> with package attribute. // Make sure the first element is <manifest> with package attribute. xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get()); xml::Element* manifest_el = xml_res->root.get(); if (manifest_el == nullptr) { if (manifest_el == nullptr) { return {}; return {}; } } Loading tools/aapt2/compile/InlineXmlFormatParser.cpp +40 −68 Original line number Original line Diff line number Diff line Loading @@ -16,12 +16,8 @@ #include "compile/InlineXmlFormatParser.h" #include "compile/InlineXmlFormatParser.h" #include <sstream> #include <string> #include <string> #include "android-base/macros.h" #include "Debug.h" #include "ResourceUtils.h" #include "ResourceUtils.h" #include "util/Util.h" #include "util/Util.h" #include "xml/XmlDom.h" #include "xml/XmlDom.h" Loading @@ -31,19 +27,17 @@ namespace aapt { namespace { namespace { /** * XML Visitor that will find all <aapt:attr> elements for extraction. */ class Visitor : public xml::PackageAwareVisitor { public: using xml::PackageAwareVisitor::Visit; struct InlineDeclaration { struct InlineDeclaration { xml::Element* el; xml::Element* el; std::string attr_namespace_uri; std::string attr_namespace_uri; std::string attr_name; std::string attr_name; }; }; // XML Visitor that will find all <aapt:attr> elements for extraction. class Visitor : public xml::PackageAwareVisitor { public: using xml::PackageAwareVisitor::Visit; explicit Visitor(IAaptContext* context, xml::XmlResource* xml_resource) explicit Visitor(IAaptContext* context, xml::XmlResource* xml_resource) : context_(context), xml_resource_(xml_resource) {} : context_(context), xml_resource_(xml_resource) {} Loading @@ -53,51 +47,44 @@ class Visitor : public xml::PackageAwareVisitor { return; return; } } const Source& src = xml_resource_->file.source.WithLine(el->line_number); const Source src = xml_resource_->file.source.WithLine(el->line_number); xml::Attribute* attr = el->FindAttribute({}, "name"); xml::Attribute* attr = el->FindAttribute({}, "name"); if (!attr) { if (!attr) { context_->GetDiagnostics()->Error(DiagMessage(src) context_->GetDiagnostics()->Error(DiagMessage(src) << "missing 'name' attribute"); << "missing 'name' attribute"); error_ = true; error_ = true; return; return; } } Maybe<Reference> ref = ResourceUtils::ParseXmlAttributeName(attr->value); Maybe<Reference> ref = ResourceUtils::ParseXmlAttributeName(attr->value); if (!ref) { if (!ref) { context_->GetDiagnostics()->Error( context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid XML attribute '" << attr->value DiagMessage(src) << "invalid XML attribute '" << attr->value << "'"); << "'"); error_ = true; error_ = true; return; return; } } const ResourceName& name = ref.value().name.value(); const ResourceName& name = ref.value().name.value(); // Use an empty string for the compilation package because we don't want to // Use an empty string for the compilation package because we don't want to default to // default to // the local package if the user specified name="style" or something. This should just // the local package if the user specified name="style" or something. This // should just // be the default namespace. // be the default namespace. Maybe<xml::ExtractedPackage> maybe_pkg = Maybe<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package, {}); TransformPackageAlias(name.package, {}); if (!maybe_pkg) { if (!maybe_pkg) { context_->GetDiagnostics()->Error(DiagMessage(src) context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid namespace prefix '" << "invalid namespace prefix '" << name.package << "'"); << name.package << "'"); error_ = true; error_ = true; return; return; } } const xml::ExtractedPackage& pkg = maybe_pkg.value(); const xml::ExtractedPackage& pkg = maybe_pkg.value(); const bool private_namespace = const bool private_namespace = pkg.private_namespace || ref.value().private_reference; pkg.private_namespace || ref.value().private_reference; InlineDeclaration decl; InlineDeclaration decl; decl.el = el; decl.el = el; decl.attr_name = name.entry; decl.attr_name = name.entry; if (!pkg.package.empty()) { if (!pkg.package.empty()) { decl.attr_namespace_uri = decl.attr_namespace_uri = xml::BuildPackageNamespace(pkg.package, private_namespace); xml::BuildPackageNamespace(pkg.package, private_namespace); } } inline_declarations_.push_back(std::move(decl)); inline_declarations_.push_back(std::move(decl)); Loading @@ -107,7 +94,9 @@ class Visitor : public xml::PackageAwareVisitor { return inline_declarations_; return inline_declarations_; } } bool HasError() const { return error_; } bool HasError() const { return error_; } private: private: DISALLOW_COPY_AND_ASSIGN(Visitor); DISALLOW_COPY_AND_ASSIGN(Visitor); Loading @@ -120,8 +109,7 @@ class Visitor : public xml::PackageAwareVisitor { } // namespace } // namespace bool InlineXmlFormatParser::Consume(IAaptContext* context, bool InlineXmlFormatParser::Consume(IAaptContext* context, xml::XmlResource* doc) { xml::XmlResource* doc) { Visitor visitor(context, doc); Visitor visitor(context, doc); doc->root->Accept(&visitor); doc->root->Accept(&visitor); if (visitor.HasError()) { if (visitor.HasError()) { Loading @@ -129,69 +117,53 @@ bool InlineXmlFormatParser::Consume(IAaptContext* context, } } size_t name_suffix_counter = 0; size_t name_suffix_counter = 0; for (const Visitor::InlineDeclaration& decl : for (const InlineDeclaration& decl : visitor.GetInlineDeclarations()) { visitor.GetInlineDeclarations()) { auto new_doc = util::make_unique<xml::XmlResource>(); auto new_doc = util::make_unique<xml::XmlResource>(); new_doc->file.config = doc->file.config; new_doc->file.config = doc->file.config; new_doc->file.source = doc->file.source.WithLine(decl.el->line_number); new_doc->file.source = doc->file.source.WithLine(decl.el->line_number); new_doc->file.name = doc->file.name; new_doc->file.name = doc->file.name; // Modify the new entry name. We need to suffix the entry with a number to // Modify the new entry name. We need to suffix the entry with a number to // avoid // avoid local collisions, then mangle it with the empty package, such that it won't show up // local collisions, then mangle it with the empty package, such that it // won't show up // in R.java. // in R.java. new_doc->file.name.entry = NameMangler::MangleEntry( new_doc->file.name.entry = {}, new_doc->file.name.entry + "__" + std::to_string(name_suffix_counter)); NameMangler::MangleEntry({}, new_doc->file.name.entry + "__" + std::to_string(name_suffix_counter)); // Extracted elements must be the only child of <aapt:attr>. // Extracted elements must be the only child of <aapt:attr>. // Make sure there is one root node in the children (ignore empty text). // Make sure there is one root node in the children (ignore empty text). for (auto& child : decl.el->children) { for (std::unique_ptr<xml::Node>& child : decl.el->children) { const Source child_source = doc->file.source.WithLine(child->line_number); const Source child_source = doc->file.source.WithLine(child->line_number); if (xml::Text* t = xml::NodeCast<xml::Text>(child.get())) { if (xml::Text* t = xml::NodeCast<xml::Text>(child.get())) { if (!util::TrimWhitespace(t->text).empty()) { if (!util::TrimWhitespace(t->text).empty()) { context->GetDiagnostics()->Error( context->GetDiagnostics()->Error(DiagMessage(child_source) DiagMessage(child_source) << "can't extract text into its own resource"); << "can't extract text into its own resource"); return false; return false; } } } else if (new_doc->root) { } else if (new_doc->root) { context->GetDiagnostics()->Error( context->GetDiagnostics()->Error(DiagMessage(child_source) DiagMessage(child_source) << "inline XML resources must have a single root"); << "inline XML resources must have a single root"); return false; return false; } else { } else { new_doc->root = std::move(child); new_doc->root.reset(static_cast<xml::Element*>(child.release())); new_doc->root->parent = nullptr; new_doc->root->parent = nullptr; } } } } // Walk up and find the parent element. // Get the parent element of <aapt:attr> xml::Node* node = decl.el; xml::Element* parent_el = decl.el->parent; xml::Element* parent_el = nullptr; while (node->parent && (parent_el = xml::NodeCast<xml::Element>(node->parent)) == nullptr) { node = node->parent; } if (!parent_el) { if (!parent_el) { context->GetDiagnostics()->Error( context->GetDiagnostics()->Error(DiagMessage(new_doc->file.source) DiagMessage(new_doc->file.source) << "no suitable parent for inheriting attribute"); << "no suitable parent for inheriting attribute"); return false; return false; } } // Add the inline attribute to the parent. // Add the inline attribute to the parent. parent_el->attributes.push_back( parent_el->attributes.push_back(xml::Attribute{decl.attr_namespace_uri, decl.attr_name, xml::Attribute{decl.attr_namespace_uri, decl.attr_name, "@" + new_doc->file.name.ToString()}); "@" + new_doc->file.name.ToString()}); // Delete the subtree. // Delete the subtree. for (auto iter = parent_el->children.begin(); for (auto iter = parent_el->children.begin(); iter != parent_el->children.end(); ++iter) { iter != parent_el->children.end(); ++iter) { if (iter->get() == decl.el) { if (iter->get() == node) { parent_el->children.erase(iter); parent_el->children.erase(iter); break; break; } } Loading tools/aapt2/compile/InlineXmlFormatParser.h +18 −23 Original line number Original line Diff line number Diff line Loading @@ -26,35 +26,30 @@ namespace aapt { namespace aapt { /** // Extracts Inline XML definitions into their own xml::XmlResource objects. * Extracts Inline XML definitions into their own xml::XmlResource objects. // * // Inline XML looks like: * Inline XML looks like: // * // <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" * <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" // xmlns:aapt="http://schemas.android.com/aapt" > * xmlns:aapt="http://schemas.android.com/aapt" > // <aapt:attr name="android:drawable" > * <aapt:attr name="android:drawable" > // <vector * <vector // android:height="64dp" * android:height="64dp" // android:width="64dp" * android:width="64dp" // android:viewportHeight="600" * android:viewportHeight="600" // android:viewportWidth="600"/> * android:viewportWidth="600"/> // </aapt:attr> * </aapt:attr> // </animated-vector> * </animated-vector> // * // The <vector> will be extracted into its own XML file and <animated-vector> will * The <vector> will be extracted into its own XML file and <animated-vector> // gain an attribute 'android:drawable' set to a reference to the extracted <vector> resource. * will * gain an attribute 'android:drawable' set to a reference to the extracted * <vector> resource. */ class InlineXmlFormatParser : public IXmlResourceConsumer { class InlineXmlFormatParser : public IXmlResourceConsumer { public: public: explicit InlineXmlFormatParser() = default; explicit InlineXmlFormatParser() = default; bool Consume(IAaptContext* context, xml::XmlResource* doc) override; bool Consume(IAaptContext* context, xml::XmlResource* doc) override; std::vector<std::unique_ptr<xml::XmlResource>>& std::vector<std::unique_ptr<xml::XmlResource>>& GetExtractedInlineXmlDocuments() { GetExtractedInlineXmlDocuments() { return queue_; return queue_; } } Loading Loading
tools/aapt2/Debug.cpp +31 −33 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,8 @@ namespace aapt { namespace aapt { namespace { class PrintVisitor : public ValueVisitor { class PrintVisitor : public ValueVisitor { public: public: using ValueVisitor::Visit; using ValueVisitor::Visit; Loading Loading @@ -88,9 +90,13 @@ class PrintVisitor : public ValueVisitor { } } } } void Visit(Array* array) override { array->Print(&std::cout); } void Visit(Array* array) override { array->Print(&std::cout); } void Visit(Plural* plural) override { plural->Print(&std::cout); } void Visit(Plural* plural) override { plural->Print(&std::cout); } void Visit(Styleable* styleable) override { void Visit(Styleable* styleable) override { std::cout << "(styleable)"; std::cout << "(styleable)"; Loading @@ -110,11 +116,14 @@ class PrintVisitor : public ValueVisitor { } } } } void VisitItem(Item* item) override { item->Print(&std::cout); } void VisitItem(Item* item) override { item->Print(&std::cout); } }; }; void Debug::PrintTable(ResourceTable* table, } // namespace const DebugPrintTableOptions& options) { void Debug::PrintTable(ResourceTable* table, const DebugPrintTableOptions& options) { PrintVisitor visitor; PrintVisitor visitor; for (auto& package : table->packages) { for (auto& package : table->packages) { Loading Loading @@ -148,10 +157,9 @@ void Debug::PrintTable(ResourceTable* table, } } for (const ResourceEntry* entry : sorted_entries) { for (const ResourceEntry* entry : sorted_entries) { ResourceId id(package->id ? package->id.value() : uint8_t(0), const ResourceId id(package->id.value_or_default(0), type->id.value_or_default(0), type->id ? type->id.value() : uint8_t(0), entry->id.value_or_default(0)); entry->id ? entry->id.value() : uint16_t(0)); const ResourceName name(package->name, type->type, entry->name); ResourceName name(package->name, type->type, entry->name); std::cout << " spec resource " << id << " " << name; std::cout << " spec resource " << id << " " << name; switch (entry->symbol_status.state) { switch (entry->symbol_status.state) { Loading Loading @@ -180,16 +188,14 @@ void Debug::PrintTable(ResourceTable* table, } } } } static size_t GetNodeIndex(const std::vector<ResourceName>& names, static size_t GetNodeIndex(const std::vector<ResourceName>& names, const ResourceName& name) { const ResourceName& name) { auto iter = std::lower_bound(names.begin(), names.end(), name); auto iter = std::lower_bound(names.begin(), names.end(), name); CHECK(iter != names.end()); CHECK(iter != names.end()); CHECK(*iter == name); CHECK(*iter == name); return std::distance(names.begin(), iter); return std::distance(names.begin(), iter); } } void Debug::PrintStyleGraph(ResourceTable* table, void Debug::PrintStyleGraph(ResourceTable* table, const ResourceName& target_style) { const ResourceName& target_style) { std::map<ResourceName, std::set<ResourceName>> graph; std::map<ResourceName, std::set<ResourceName>> graph; std::queue<ResourceName> styles_to_visit; std::queue<ResourceName> styles_to_visit; Loading Loading @@ -223,8 +229,7 @@ void Debug::PrintStyleGraph(ResourceTable* table, std::cout << "digraph styles {\n"; std::cout << "digraph styles {\n"; for (const auto& name : names) { for (const auto& name : names) { std::cout << " node_" << GetNodeIndex(names, name) << " [label=\"" << name std::cout << " node_" << GetNodeIndex(names, name) << " [label=\"" << name << "\"];\n"; << "\"];\n"; } } for (const auto& entry : graph) { for (const auto& entry : graph) { Loading @@ -243,8 +248,7 @@ void Debug::PrintStyleGraph(ResourceTable* table, void Debug::DumpHex(const void* data, size_t len) { void Debug::DumpHex(const void* data, size_t len) { const uint8_t* d = (const uint8_t*)data; const uint8_t* d = (const uint8_t*)data; for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) { std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)d[i] std::cerr << std::hex << std::setfill('0') << std::setw(2) << (uint32_t)d[i] << " "; << " "; if (i % 8 == 7) { if (i % 8 == 7) { std::cerr << "\n"; std::cerr << "\n"; } } Loading @@ -262,8 +266,15 @@ class XmlPrinter : public xml::Visitor { using xml::Visitor::Visit; using xml::Visitor::Visit; void Visit(xml::Element* el) override { void Visit(xml::Element* el) override { std::cerr << prefix_; const size_t previous_size = prefix_.size(); std::cerr << "E: "; for (const xml::NamespaceDecl& decl : el->namespace_decls) { std::cerr << prefix_ << "N: " << decl.prefix << "=" << decl.uri << " (line=" << decl.line_number << ")\n"; prefix_ += " "; } std::cerr << prefix_ << "E: "; if (!el->namespace_uri.empty()) { if (!el->namespace_uri.empty()) { std::cerr << el->namespace_uri << ":"; std::cerr << el->namespace_uri << ":"; } } Loading @@ -283,26 +294,13 @@ class XmlPrinter : public xml::Visitor { std::cerr << "=" << attr.value << "\n"; std::cerr << "=" << attr.value << "\n"; } } const size_t previous_size = prefix_.size(); prefix_ += " "; prefix_ += " "; xml::Visitor::Visit(el); xml::Visitor::Visit(el); prefix_.resize(previous_size); prefix_.resize(previous_size); } } void Visit(xml::Namespace* ns) override { std::cerr << prefix_; std::cerr << "N: " << ns->namespace_prefix << "=" << ns->namespace_uri << " (line=" << ns->line_number << ")\n"; const size_t previous_size = prefix_.size(); prefix_ += " "; xml::Visitor::Visit(ns); prefix_.resize(previous_size); } void Visit(xml::Text* text) override { void Visit(xml::Text* text) override { std::cerr << prefix_; std::cerr << prefix_ << "T: '" << text->text << "'\n"; std::cerr << "T: '" << text->text << "'\n"; } } private: private: Loading
tools/aapt2/cmd/Link.cpp +1 −1 Original line number Original line Diff line number Diff line Loading @@ -482,7 +482,7 @@ std::vector<std::unique_ptr<xml::XmlResource>> ResourceFileFlattener::LinkAndVer if (options_.no_version_vectors || options_.no_version_transitions) { if (options_.no_version_vectors || options_.no_version_transitions) { // Skip this if it is a vector or animated-vector. // Skip this if it is a vector or animated-vector. xml::Element* el = xml::FindRootElement(doc); xml::Element* el = doc->root.get(); if (el && el->namespace_uri.empty()) { if (el && el->namespace_uri.empty()) { if ((options_.no_version_vectors && IsVectorElement(el->name)) || if ((options_.no_version_vectors && IsVectorElement(el->name)) || (options_.no_version_transitions && IsTransitionElement(el->name))) { (options_.no_version_transitions && IsTransitionElement(el->name))) { Loading
tools/aapt2/cmd/Util.cpp +15 −12 Original line number Original line Diff line number Diff line Loading @@ -28,7 +28,7 @@ #include "util/Maybe.h" #include "util/Maybe.h" #include "util/Util.h" #include "util/Util.h" using android::StringPiece; using ::android::StringPiece; namespace aapt { namespace aapt { Loading Loading @@ -134,19 +134,21 @@ static xml::AaptAttribute CreateAttributeWithId(const ResourceId& id) { return xml::AaptAttribute(Attribute(), id); return xml::AaptAttribute(Attribute(), id); } } static xml::NamespaceDecl CreateAndroidNamespaceDecl() { xml::NamespaceDecl decl; decl.prefix = "android"; decl.uri = xml::kSchemaAndroid; return decl; } std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info, std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info, const SplitConstraints& constraints) { const SplitConstraints& constraints) { const ResourceId kVersionCode(0x0101021b); const ResourceId kVersionCode(0x0101021b); const ResourceId kRevisionCode(0x010104d5); const ResourceId kRevisionCode(0x010104d5); const ResourceId kHasCode(0x0101000c); const ResourceId kHasCode(0x0101000c); std::unique_ptr<xml::XmlResource> doc = util::make_unique<xml::XmlResource>(); std::unique_ptr<xml::Namespace> namespace_android = util::make_unique<xml::Namespace>(); namespace_android->namespace_uri = xml::kSchemaAndroid; namespace_android->namespace_prefix = "android"; std::unique_ptr<xml::Element> manifest_el = util::make_unique<xml::Element>(); std::unique_ptr<xml::Element> manifest_el = util::make_unique<xml::Element>(); manifest_el->namespace_decls.push_back(CreateAndroidNamespaceDecl()); manifest_el->name = "manifest"; manifest_el->name = "manifest"; manifest_el->attributes.push_back(xml::Attribute{"", "package", app_info.package}); manifest_el->attributes.push_back(xml::Attribute{"", "package", app_info.package}); Loading Loading @@ -179,8 +181,8 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info, xml::Attribute{"", "configForSplit", app_info.split_name.value()}); xml::Attribute{"", "configForSplit", app_info.split_name.value()}); } } // Splits may contain more configurations than originally desired (fallback densities, etc.). // Splits may contain more configurations than originally desired (fall-back densities, etc.). // This makes programmatic discovery of split targetting difficult. Encode the original // This makes programmatic discovery of split targeting difficult. Encode the original // split constraints intended for this split. // split constraints intended for this split. std::stringstream target_config_str; std::stringstream target_config_str; target_config_str << util::Joiner(constraints.configs, ","); target_config_str << util::Joiner(constraints.configs, ","); Loading @@ -193,8 +195,9 @@ std::unique_ptr<xml::XmlResource> GenerateSplitManifest(const AppInfo& app_info, util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN, 0u)}); util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN, 0u)}); manifest_el->AppendChild(std::move(application_el)); manifest_el->AppendChild(std::move(application_el)); namespace_android->AppendChild(std::move(manifest_el)); doc->root = std::move(namespace_android); std::unique_ptr<xml::XmlResource> doc = util::make_unique<xml::XmlResource>(); doc->root = std::move(manifest_el); return doc; return doc; } } Loading Loading @@ -284,7 +287,7 @@ static Maybe<int> ExtractSdkVersion(xml::Attribute* attr, std::string* out_error Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(xml::XmlResource* xml_res, IDiagnostics* diag) { Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(xml::XmlResource* xml_res, IDiagnostics* diag) { // Make sure the first element is <manifest> with package attribute. // Make sure the first element is <manifest> with package attribute. xml::Element* manifest_el = xml::FindRootElement(xml_res->root.get()); xml::Element* manifest_el = xml_res->root.get(); if (manifest_el == nullptr) { if (manifest_el == nullptr) { return {}; return {}; } } Loading
tools/aapt2/compile/InlineXmlFormatParser.cpp +40 −68 Original line number Original line Diff line number Diff line Loading @@ -16,12 +16,8 @@ #include "compile/InlineXmlFormatParser.h" #include "compile/InlineXmlFormatParser.h" #include <sstream> #include <string> #include <string> #include "android-base/macros.h" #include "Debug.h" #include "ResourceUtils.h" #include "ResourceUtils.h" #include "util/Util.h" #include "util/Util.h" #include "xml/XmlDom.h" #include "xml/XmlDom.h" Loading @@ -31,19 +27,17 @@ namespace aapt { namespace { namespace { /** * XML Visitor that will find all <aapt:attr> elements for extraction. */ class Visitor : public xml::PackageAwareVisitor { public: using xml::PackageAwareVisitor::Visit; struct InlineDeclaration { struct InlineDeclaration { xml::Element* el; xml::Element* el; std::string attr_namespace_uri; std::string attr_namespace_uri; std::string attr_name; std::string attr_name; }; }; // XML Visitor that will find all <aapt:attr> elements for extraction. class Visitor : public xml::PackageAwareVisitor { public: using xml::PackageAwareVisitor::Visit; explicit Visitor(IAaptContext* context, xml::XmlResource* xml_resource) explicit Visitor(IAaptContext* context, xml::XmlResource* xml_resource) : context_(context), xml_resource_(xml_resource) {} : context_(context), xml_resource_(xml_resource) {} Loading @@ -53,51 +47,44 @@ class Visitor : public xml::PackageAwareVisitor { return; return; } } const Source& src = xml_resource_->file.source.WithLine(el->line_number); const Source src = xml_resource_->file.source.WithLine(el->line_number); xml::Attribute* attr = el->FindAttribute({}, "name"); xml::Attribute* attr = el->FindAttribute({}, "name"); if (!attr) { if (!attr) { context_->GetDiagnostics()->Error(DiagMessage(src) context_->GetDiagnostics()->Error(DiagMessage(src) << "missing 'name' attribute"); << "missing 'name' attribute"); error_ = true; error_ = true; return; return; } } Maybe<Reference> ref = ResourceUtils::ParseXmlAttributeName(attr->value); Maybe<Reference> ref = ResourceUtils::ParseXmlAttributeName(attr->value); if (!ref) { if (!ref) { context_->GetDiagnostics()->Error( context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid XML attribute '" << attr->value DiagMessage(src) << "invalid XML attribute '" << attr->value << "'"); << "'"); error_ = true; error_ = true; return; return; } } const ResourceName& name = ref.value().name.value(); const ResourceName& name = ref.value().name.value(); // Use an empty string for the compilation package because we don't want to // Use an empty string for the compilation package because we don't want to default to // default to // the local package if the user specified name="style" or something. This should just // the local package if the user specified name="style" or something. This // should just // be the default namespace. // be the default namespace. Maybe<xml::ExtractedPackage> maybe_pkg = Maybe<xml::ExtractedPackage> maybe_pkg = TransformPackageAlias(name.package, {}); TransformPackageAlias(name.package, {}); if (!maybe_pkg) { if (!maybe_pkg) { context_->GetDiagnostics()->Error(DiagMessage(src) context_->GetDiagnostics()->Error(DiagMessage(src) << "invalid namespace prefix '" << "invalid namespace prefix '" << name.package << "'"); << name.package << "'"); error_ = true; error_ = true; return; return; } } const xml::ExtractedPackage& pkg = maybe_pkg.value(); const xml::ExtractedPackage& pkg = maybe_pkg.value(); const bool private_namespace = const bool private_namespace = pkg.private_namespace || ref.value().private_reference; pkg.private_namespace || ref.value().private_reference; InlineDeclaration decl; InlineDeclaration decl; decl.el = el; decl.el = el; decl.attr_name = name.entry; decl.attr_name = name.entry; if (!pkg.package.empty()) { if (!pkg.package.empty()) { decl.attr_namespace_uri = decl.attr_namespace_uri = xml::BuildPackageNamespace(pkg.package, private_namespace); xml::BuildPackageNamespace(pkg.package, private_namespace); } } inline_declarations_.push_back(std::move(decl)); inline_declarations_.push_back(std::move(decl)); Loading @@ -107,7 +94,9 @@ class Visitor : public xml::PackageAwareVisitor { return inline_declarations_; return inline_declarations_; } } bool HasError() const { return error_; } bool HasError() const { return error_; } private: private: DISALLOW_COPY_AND_ASSIGN(Visitor); DISALLOW_COPY_AND_ASSIGN(Visitor); Loading @@ -120,8 +109,7 @@ class Visitor : public xml::PackageAwareVisitor { } // namespace } // namespace bool InlineXmlFormatParser::Consume(IAaptContext* context, bool InlineXmlFormatParser::Consume(IAaptContext* context, xml::XmlResource* doc) { xml::XmlResource* doc) { Visitor visitor(context, doc); Visitor visitor(context, doc); doc->root->Accept(&visitor); doc->root->Accept(&visitor); if (visitor.HasError()) { if (visitor.HasError()) { Loading @@ -129,69 +117,53 @@ bool InlineXmlFormatParser::Consume(IAaptContext* context, } } size_t name_suffix_counter = 0; size_t name_suffix_counter = 0; for (const Visitor::InlineDeclaration& decl : for (const InlineDeclaration& decl : visitor.GetInlineDeclarations()) { visitor.GetInlineDeclarations()) { auto new_doc = util::make_unique<xml::XmlResource>(); auto new_doc = util::make_unique<xml::XmlResource>(); new_doc->file.config = doc->file.config; new_doc->file.config = doc->file.config; new_doc->file.source = doc->file.source.WithLine(decl.el->line_number); new_doc->file.source = doc->file.source.WithLine(decl.el->line_number); new_doc->file.name = doc->file.name; new_doc->file.name = doc->file.name; // Modify the new entry name. We need to suffix the entry with a number to // Modify the new entry name. We need to suffix the entry with a number to // avoid // avoid local collisions, then mangle it with the empty package, such that it won't show up // local collisions, then mangle it with the empty package, such that it // won't show up // in R.java. // in R.java. new_doc->file.name.entry = NameMangler::MangleEntry( new_doc->file.name.entry = {}, new_doc->file.name.entry + "__" + std::to_string(name_suffix_counter)); NameMangler::MangleEntry({}, new_doc->file.name.entry + "__" + std::to_string(name_suffix_counter)); // Extracted elements must be the only child of <aapt:attr>. // Extracted elements must be the only child of <aapt:attr>. // Make sure there is one root node in the children (ignore empty text). // Make sure there is one root node in the children (ignore empty text). for (auto& child : decl.el->children) { for (std::unique_ptr<xml::Node>& child : decl.el->children) { const Source child_source = doc->file.source.WithLine(child->line_number); const Source child_source = doc->file.source.WithLine(child->line_number); if (xml::Text* t = xml::NodeCast<xml::Text>(child.get())) { if (xml::Text* t = xml::NodeCast<xml::Text>(child.get())) { if (!util::TrimWhitespace(t->text).empty()) { if (!util::TrimWhitespace(t->text).empty()) { context->GetDiagnostics()->Error( context->GetDiagnostics()->Error(DiagMessage(child_source) DiagMessage(child_source) << "can't extract text into its own resource"); << "can't extract text into its own resource"); return false; return false; } } } else if (new_doc->root) { } else if (new_doc->root) { context->GetDiagnostics()->Error( context->GetDiagnostics()->Error(DiagMessage(child_source) DiagMessage(child_source) << "inline XML resources must have a single root"); << "inline XML resources must have a single root"); return false; return false; } else { } else { new_doc->root = std::move(child); new_doc->root.reset(static_cast<xml::Element*>(child.release())); new_doc->root->parent = nullptr; new_doc->root->parent = nullptr; } } } } // Walk up and find the parent element. // Get the parent element of <aapt:attr> xml::Node* node = decl.el; xml::Element* parent_el = decl.el->parent; xml::Element* parent_el = nullptr; while (node->parent && (parent_el = xml::NodeCast<xml::Element>(node->parent)) == nullptr) { node = node->parent; } if (!parent_el) { if (!parent_el) { context->GetDiagnostics()->Error( context->GetDiagnostics()->Error(DiagMessage(new_doc->file.source) DiagMessage(new_doc->file.source) << "no suitable parent for inheriting attribute"); << "no suitable parent for inheriting attribute"); return false; return false; } } // Add the inline attribute to the parent. // Add the inline attribute to the parent. parent_el->attributes.push_back( parent_el->attributes.push_back(xml::Attribute{decl.attr_namespace_uri, decl.attr_name, xml::Attribute{decl.attr_namespace_uri, decl.attr_name, "@" + new_doc->file.name.ToString()}); "@" + new_doc->file.name.ToString()}); // Delete the subtree. // Delete the subtree. for (auto iter = parent_el->children.begin(); for (auto iter = parent_el->children.begin(); iter != parent_el->children.end(); ++iter) { iter != parent_el->children.end(); ++iter) { if (iter->get() == decl.el) { if (iter->get() == node) { parent_el->children.erase(iter); parent_el->children.erase(iter); break; break; } } Loading
tools/aapt2/compile/InlineXmlFormatParser.h +18 −23 Original line number Original line Diff line number Diff line Loading @@ -26,35 +26,30 @@ namespace aapt { namespace aapt { /** // Extracts Inline XML definitions into their own xml::XmlResource objects. * Extracts Inline XML definitions into their own xml::XmlResource objects. // * // Inline XML looks like: * Inline XML looks like: // * // <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" * <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" // xmlns:aapt="http://schemas.android.com/aapt" > * xmlns:aapt="http://schemas.android.com/aapt" > // <aapt:attr name="android:drawable" > * <aapt:attr name="android:drawable" > // <vector * <vector // android:height="64dp" * android:height="64dp" // android:width="64dp" * android:width="64dp" // android:viewportHeight="600" * android:viewportHeight="600" // android:viewportWidth="600"/> * android:viewportWidth="600"/> // </aapt:attr> * </aapt:attr> // </animated-vector> * </animated-vector> // * // The <vector> will be extracted into its own XML file and <animated-vector> will * The <vector> will be extracted into its own XML file and <animated-vector> // gain an attribute 'android:drawable' set to a reference to the extracted <vector> resource. * will * gain an attribute 'android:drawable' set to a reference to the extracted * <vector> resource. */ class InlineXmlFormatParser : public IXmlResourceConsumer { class InlineXmlFormatParser : public IXmlResourceConsumer { public: public: explicit InlineXmlFormatParser() = default; explicit InlineXmlFormatParser() = default; bool Consume(IAaptContext* context, xml::XmlResource* doc) override; bool Consume(IAaptContext* context, xml::XmlResource* doc) override; std::vector<std::unique_ptr<xml::XmlResource>>& std::vector<std::unique_ptr<xml::XmlResource>>& GetExtractedInlineXmlDocuments() { GetExtractedInlineXmlDocuments() { return queue_; return queue_; } } Loading