Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2def7dcf authored by Adam Lesinski's avatar Adam Lesinski Committed by Android (Google) Code Review
Browse files

Merge "AAPT2: Change XmlDom to exclude Namespace as a node"

parents 88bf7675 6b372991
Loading
Loading
Loading
Loading
+31 −33
Original line number Original line Diff line number Diff line
@@ -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;
@@ -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)";
@@ -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) {
@@ -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) {
@@ -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;
@@ -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) {
@@ -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";
    }
    }
@@ -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 << ":";
    }
    }
@@ -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:
+1 −1
Original line number Original line Diff line number Diff line
@@ -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))) {
+15 −12
Original line number Original line Diff line number Diff line
@@ -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 {


@@ -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});


@@ -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, ",");
@@ -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;
}
}


@@ -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 {};
  }
  }
+40 −68
Original line number Original line Diff line number Diff line
@@ -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"
@@ -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) {}


@@ -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));
@@ -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);
@@ -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()) {
@@ -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;
      }
      }
+18 −23
Original line number Original line Diff line number Diff line
@@ -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