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

Commit da9eba30 authored by Adam Lesinski's avatar Adam Lesinski
Browse files

Dump XML files in aapt2 dump

Test: manual
Change-Id: Id7f656c1385f6d1fec8eaa993c8e2b36bb1ae5b0
parent 97661735
Loading
Loading
Loading
Loading
+35 −24
Original line number Diff line number Diff line
@@ -414,59 +414,70 @@ class XmlPrinter : public xml::ConstVisitor {
 public:
  using xml::ConstVisitor::Visit;

  void Visit(const xml::Element* el) override {
    const size_t previous_size = prefix_.size();
  XmlPrinter(Printer* printer) : printer_(printer) {
  }

  void Visit(const xml::Element* el) override {
    for (const xml::NamespaceDecl& decl : el->namespace_decls) {
      std::cerr << prefix_ << "N: " << decl.prefix << "=" << decl.uri
                << " (line=" << decl.line_number << ")\n";
      prefix_ += "  ";
      printer_->Println(StringPrintf("N: %s=%s (line=%zu)", decl.prefix.c_str(), decl.uri.c_str(),
                                     decl.line_number));
      printer_->Indent();
    }

    std::cerr << prefix_ << "E: ";
    printer_->Print("E: ");
    if (!el->namespace_uri.empty()) {
      std::cerr << el->namespace_uri << ":";
      printer_->Print(el->namespace_uri);
      printer_->Print(":");
    }
    std::cerr << el->name << " (line=" << el->line_number << ")\n";
    printer_->Println(StringPrintf("%s (line=%zu)", el->name.c_str(), el->line_number));
    printer_->Indent();

    for (const xml::Attribute& attr : el->attributes) {
      std::cerr << prefix_ << "  A: ";
      printer_->Print("A: ");
      if (!attr.namespace_uri.empty()) {
        std::cerr << attr.namespace_uri << ":";
        printer_->Print(attr.namespace_uri);
        printer_->Print(":");
      }
      std::cerr << attr.name;
      printer_->Print(attr.name);

      if (attr.compiled_attribute) {
        std::cerr << "(" << attr.compiled_attribute.value().id.value_or_default(ResourceId(0x0))
                  << ")";
        printer_->Print("(");
        printer_->Print(
            attr.compiled_attribute.value().id.value_or_default(ResourceId(0)).to_string());
        printer_->Print(")");
      }
      std::cerr << "=";
      printer_->Print("=");
      if (attr.compiled_value != nullptr) {
        std::cerr << *attr.compiled_value;
        attr.compiled_value->PrettyPrint(printer_);
      } else {
        std::cerr << attr.value;
        printer_->Print(attr.value);
      }
      std::cerr << "\n";
      printer_->Println();
    }

    prefix_ += "  ";
    printer_->Indent();
    xml::ConstVisitor::Visit(el);
    prefix_.resize(previous_size);
    printer_->Undent();
    printer_->Undent();

    for (size_t i = 0; i < el->namespace_decls.size(); i++) {
      printer_->Undent();
    }
  }

  void Visit(const xml::Text* text) override {
    std::cerr << prefix_ << "T: '" << text->text << "'\n";
    printer_->Println(StringPrintf("T: '%s'", text->text.c_str()));
  }

 private:
  std::string prefix_;
  Printer* printer_;
};

}  // namespace

void Debug::DumpXml(const xml::XmlResource& doc) {
  XmlPrinter printer;
  doc.root->Accept(&printer);
void Debug::DumpXml(const xml::XmlResource& doc, Printer* printer) {
  XmlPrinter xml_visitor(printer);
  doc.root->Accept(&xml_visitor);
}

}  // namespace aapt
+1 −1
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ struct Debug {
                         text::Printer* printer);
  static void PrintStyleGraph(ResourceTable* table, const ResourceName& target_style);
  static void DumpHex(const void* data, size_t len);
  static void DumpXml(const xml::XmlResource& doc);
  static void DumpXml(const xml::XmlResource& doc, text::Printer* printer);
};

}  // namespace aapt
+79 −11
Original line number Diff line number Diff line
@@ -38,6 +38,13 @@ using ::android::base::StringPrintf;

namespace aapt {

struct DumpOptions {
  DebugPrintTableOptions print_options;

  // The path to a file within an APK to dump.
  Maybe<std::string> file_to_dump_path;
};

static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
  switch (type) {
    case ResourceFile::Type::kPng:
@@ -69,8 +76,52 @@ static void DumpCompiledFile(const ResourceFile& file, const Source& source, off
  printer->Println(StringPrintf("Data:     offset=%" PRIi64 " length=%zd", offset, len));
}

static bool DumpXmlFile(IAaptContext* context, io::IFile* file, bool proto,
                        text::Printer* printer) {
  std::unique_ptr<xml::XmlResource> doc;
  if (proto) {
    std::unique_ptr<io::InputStream> in = file->OpenInputStream();
    if (in == nullptr) {
      context->GetDiagnostics()->Error(DiagMessage() << "failed to open file");
      return false;
    }

    io::ZeroCopyInputAdaptor adaptor(in.get());
    pb::XmlNode pb_node;
    if (!pb_node.ParseFromZeroCopyStream(&adaptor)) {
      context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as proto XML");
      return false;
    }

    std::string err;
    doc = DeserializeXmlResourceFromPb(pb_node, &err);
    if (doc == nullptr) {
      context->GetDiagnostics()->Error(DiagMessage() << "failed to deserialize proto XML");
      return false;
    }
    printer->Println("Proto XML");
  } else {
    std::unique_ptr<io::IData> data = file->OpenAsData();
    if (data == nullptr) {
      context->GetDiagnostics()->Error(DiagMessage() << "failed to open file");
      return false;
    }

    std::string err;
    doc = xml::Inflate(data->data(), data->size(), &err);
    if (doc == nullptr) {
      context->GetDiagnostics()->Error(DiagMessage() << "failed to parse file as binary XML");
      return false;
    }
    printer->Println("Binary XML");
  }

  Debug::DumpXml(*doc, printer);
  return true;
}

static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
                        const DebugPrintTableOptions& print_options) {
                        const DumpOptions& options) {
  // Use a smaller buffer so that there is less latency for dumping to stdout.
  constexpr size_t kStdOutBufferSize = 1024u;
  io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
@@ -80,7 +131,10 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
  std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
  if (zip) {
    ResourceTable table;
    bool proto = false;
    if (io::IFile* file = zip->FindFile("resources.pb")) {
      proto = true;

      std::unique_ptr<io::IData> data = file->OpenAsData();
      if (data == nullptr) {
        context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb");
@@ -98,8 +152,6 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
                                         << "failed to parse table: " << err);
        return false;
      }

      printer.Println("Proto APK");
    } else if (io::IFile* file = zip->FindFile("resources.arsc")) {
      std::unique_ptr<io::IData> data = file->OpenAsData();
      if (!data) {
@@ -112,14 +164,28 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
      if (!parser.Parse()) {
        return false;
      }
    }

    if (!options.file_to_dump_path) {
      if (proto) {
        printer.Println("Proto APK");
      } else {
        printer.Println("Binary APK");
      }

    Debug::PrintTable(table, print_options, &printer);
      Debug::PrintTable(table, options.print_options, &printer);
      return true;
    }

    io::IFile* file = zip->FindFile(options.file_to_dump_path.value());
    if (file == nullptr) {
      context->GetDiagnostics()->Error(DiagMessage(file_path)
                                       << "file '" << options.file_to_dump_path.value()
                                       << "' not found in APK");
      return false;
    }
    return DumpXmlFile(context, file, proto, &printer);
  }

  err.clear();

  io::FileInputStream input(file_path);
@@ -159,7 +225,7 @@ static bool TryDumpFile(IAaptContext* context, const std::string& file_path,
      }

      printer.Indent();
      Debug::PrintTable(table, print_options, &printer);
      Debug::PrintTable(table, options.print_options, &printer);
      printer.Undent();
    } else if (entry->Type() == ContainerEntryType::kResFile) {
      printer.Println("kResFile");
@@ -243,10 +309,13 @@ class DumpContext : public IAaptContext {
int Dump(const std::vector<StringPiece>& args) {
  bool verbose = false;
  bool no_values = false;
  DumpOptions options;
  Flags flags = Flags()
                    .OptionalSwitch("--no-values",
                                    "Suppresses output of values when displaying resource tables.",
                                    &no_values)
                    .OptionalFlag("--file", "Dumps the specified file from the APK passed as arg.",
                                  &options.file_to_dump_path)
                    .OptionalSwitch("-v", "increase verbosity of output", &verbose);
  if (!flags.Parse("aapt2 dump", args, &std::cerr)) {
    return 1;
@@ -255,11 +324,10 @@ int Dump(const std::vector<StringPiece>& args) {
  DumpContext context;
  context.SetVerbose(verbose);

  DebugPrintTableOptions dump_table_options;
  dump_table_options.show_sources = true;
  dump_table_options.show_values = !no_values;
  options.print_options.show_sources = true;
  options.print_options.show_values = !no_values;
  for (const std::string& arg : flags.GetArgs()) {
    if (!TryDumpFile(&context, arg, dump_table_options)) {
    if (!TryDumpFile(&context, arg, options)) {
      return 1;
    }
  }