diff options
author | 2018-07-19 14:29:00 -0700 | |
---|---|---|
committer | 2018-08-14 15:56:29 -0700 | |
commit | 5d2755129dae6ff6f0061da0abe634f44054b23e (patch) | |
tree | 1cb30f47af58b340f5598defc4b062139812954d | |
parent | 1a8a69075e8710b3457f685de3984c7028ef2ffb (diff) |
AAPT2: Reformatted dump command invocations
Use with:
aapt2 dump apc [apc]
aapt2 dump configurations [apk]
aapt2 dump strings [apk]
aapt2 dump resources [apk]
aapt2 dump xmlstrings [apk] --file [file]
aapt2 dump xmltree [apk] --file [file]
Will add permissions and badging in a later commit.
Bug: 73351292
Test: Manual tests of the commands
Change-Id: I97eec01222af14053a98bd70255f1bfecd16b1c4
-rw-r--r-- | tools/aapt2/Debug.cpp | 35 | ||||
-rw-r--r-- | tools/aapt2/Debug.h | 1 | ||||
-rw-r--r-- | tools/aapt2/LoadedApk.cpp | 47 | ||||
-rw-r--r-- | tools/aapt2/LoadedApk.h | 6 | ||||
-rw-r--r-- | tools/aapt2/Main.cpp | 2 | ||||
-rw-r--r-- | tools/aapt2/cmd/Dump.cpp | 466 | ||||
-rw-r--r-- | tools/aapt2/cmd/Dump.h | 110 |
7 files changed, 469 insertions, 198 deletions
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index f064cb14248f..0a517ab8a2de 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -408,6 +408,41 @@ void Debug::DumpHex(const void* data, size_t len) { } } +void Debug::DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer) { + using namespace android; + + if (pool->getError() == NO_INIT) { + printer->Print("String pool is unitialized.\n"); + return; + } else if (pool->getError() != NO_ERROR) { + printer->Print("String pool is corrupt/invalid.\n"); + return; + } + + SortedVector<const void*> uniqueStrings; + const size_t N = pool->size(); + for (size_t i=0; i<N; i++) { + size_t len; + if (pool->isUTF8()) { + uniqueStrings.add(pool->string8At(i, &len)); + } else { + uniqueStrings.add(pool->stringAt(i, &len)); + } + } + + printer->Print(StringPrintf("String pool of %zd unique %s %s strings, %zd entries and %zd styles " + "using %zd bytes:\n", uniqueStrings.size(), + pool->isUTF8() ? "UTF-8" : "UTF-16", + pool->isSorted() ? "sorted" : "non-sorted", N, pool->styleCount(), + pool->bytes())); + + const size_t NS = pool->size(); + for (size_t s=0; s<NS; s++) { + String8 str = pool->string8ObjectAt(s); + printer->Print(StringPrintf("String #%zd : %s\n", s, str.string())); + } +} + namespace { class XmlPrinter : public xml::ConstVisitor { diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h index 382707e1d4cd..a43197cacf7b 100644 --- a/tools/aapt2/Debug.h +++ b/tools/aapt2/Debug.h @@ -38,6 +38,7 @@ struct Debug { 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, text::Printer* printer); + static void DumpResStringPool(const android::ResStringPool* pool, text::Printer* printer); }; } // namespace aapt diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp index b32766be8d18..b6ee1ad83ce3 100644 --- a/tools/aapt2/LoadedApk.cpp +++ b/tools/aapt2/LoadedApk.cpp @@ -257,6 +257,53 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table return true; } +std::unique_ptr<xml::XmlResource> LoadedApk::LoadXml(const std::string& file_path, + IDiagnostics* diag) { + io::IFile* file = apk_->FindFile(file_path); + if (file == nullptr) { + diag->Error(DiagMessage() << "failed to find file"); + return nullptr; + } + + std::unique_ptr<xml::XmlResource> doc; + if (format_ == ApkFormat::kProto) { + std::unique_ptr<io::InputStream> in = file->OpenInputStream(); + if (!in) { + diag->Error(DiagMessage() << "failed to open file"); + return nullptr; + } + + io::ZeroCopyInputAdaptor adaptor(in.get()); + pb::XmlNode pb_node; + if (!pb_node.ParseFromZeroCopyStream(&adaptor)) { + diag->Error(DiagMessage() << "failed to parse file as proto XML"); + return nullptr; + } + + std::string err; + doc = DeserializeXmlResourceFromPb(pb_node, &err); + if (!doc) { + diag->Error(DiagMessage() << "failed to deserialize proto XML: " << err); + return nullptr; + } + } else if (format_ == ApkFormat::kBinary) { + std::unique_ptr<io::IData> data = file->OpenAsData(); + if (!data) { + diag->Error(DiagMessage() << "failed to open file"); + return nullptr; + } + + std::string err; + doc = xml::Inflate(data->data(), data->size(), &err); + if (!doc) { + diag->Error(DiagMessage() << "failed to parse file as binary XML: " << err); + return nullptr; + } + } + + return doc; +} + ApkFormat LoadedApk::DetermineApkFormat(io::IFileCollection* apk) { if (apk->FindFile(kApkResourceTablePath) != nullptr) { return ApkFormat::kBinary; diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h index 41f879d0cdc3..dcb085aa2b0b 100644 --- a/tools/aapt2/LoadedApk.h +++ b/tools/aapt2/LoadedApk.h @@ -70,6 +70,10 @@ class LoadedApk { return apk_.get(); } + ApkFormat GetApkFormat() { + return format_; + } + const ResourceTable* GetResourceTable() const { return table_.get(); } @@ -106,6 +110,8 @@ class LoadedApk { const TableFlattenerOptions& options, FilterChain* filters, IArchiveWriter* writer, xml::XmlResource* manifest = nullptr); + /** Loads the file as an xml document. */ + std::unique_ptr<xml::XmlResource> LoadXml(const std::string& file_path, IDiagnostics* diag); private: DISALLOW_COPY_AND_ASSIGN(LoadedApk); diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index 23903c9e05f3..37013c07ffef 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -71,7 +71,7 @@ class MainCommand : public Command { explicit MainCommand(IDiagnostics* diagnostics) : Command("aapt2"), diagnostics_(diagnostics) { AddOptionalSubcommand(util::make_unique<CompileCommand>(diagnostics)); AddOptionalSubcommand(util::make_unique<LinkCommand>(diagnostics)); - AddOptionalSubcommand(util::make_unique<DumpCommand>()); + AddOptionalSubcommand(util::make_unique<DumpCommand>(diagnostics)); AddOptionalSubcommand(util::make_unique<DiffCommand>()); AddOptionalSubcommand(util::make_unique<OptimizeCommand>()); AddOptionalSubcommand(util::make_unique<ConvertCommand>()); diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp index 6e9c80024ddd..b4311c56428b 100644 --- a/tools/aapt2/cmd/Dump.cpp +++ b/tools/aapt2/cmd/Dump.cpp @@ -24,8 +24,11 @@ #include "Debug.h" #include "Diagnostics.h" +#include "LoadedApk.h" +#include "Util.h" #include "format/Container.h" #include "format/binary/BinaryResourceParser.h" +#include "format/binary/XmlFlattener.h" #include "format/proto/ProtoDeserialize.h" #include "io/FileStream.h" #include "io/ZipArchive.h" @@ -70,184 +73,6 @@ 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 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); - Printer printer(&fout); - - std::string err; - std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err); - if (zip) { - ResourceTable table(/** validate_resources **/ false); - 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"); - return false; - } - - pb::ResourceTable pb_table; - if (!pb_table.ParseFromArray(data->data(), data->size())) { - context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.pb"); - return false; - } - - if (!DeserializeTableFromPb(pb_table, zip.get(), &table, &err)) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to parse table: " << err); - return false; - } - } else if (io::IFile* file = zip->FindFile("resources.arsc")) { - std::unique_ptr<io::IData> data = file->OpenAsData(); - if (!data) { - context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc"); - return false; - } - - BinaryResourceParser parser(context->GetDiagnostics(), &table, Source(file_path), - data->data(), data->size()); - 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, 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); - if (input.HadError()) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to open file: " << input.GetError()); - return false; - } - - // Try as a compiled file. - ContainerReader reader(&input); - if (reader.HadError()) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to read container: " << reader.GetError()); - return false; - } - - printer.Println("AAPT2 Container (APC)"); - ContainerReaderEntry* entry; - while ((entry = reader.Next()) != nullptr) { - if (entry->Type() == ContainerEntryType::kResTable) { - printer.Println("kResTable"); - - pb::ResourceTable pb_table; - if (!entry->GetResTable(&pb_table)) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to parse proto table: " << entry->GetError()); - continue; - } - - ResourceTable table; - err.clear(); - if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &err)) { - context->GetDiagnostics()->Error(DiagMessage(file_path) - << "failed to parse table: " << err); - continue; - } - - printer.Indent(); - Debug::PrintTable(table, options.print_options, &printer); - printer.Undent(); - } else if (entry->Type() == ContainerEntryType::kResFile) { - printer.Println("kResFile"); - pb::internal::CompiledFile pb_compiled_file; - off64_t offset; - size_t length; - if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) { - context->GetDiagnostics()->Error( - DiagMessage(file_path) << "failed to parse compiled proto file: " << entry->GetError()); - continue; - } - - ResourceFile file; - std::string error; - if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) { - context->GetDiagnostics()->Warn(DiagMessage(file_path) - << "failed to parse compiled file: " << error); - continue; - } - - printer.Indent(); - DumpCompiledFile(file, Source(file_path), offset, length, &printer); - printer.Undent(); - } - } - return true; -} - namespace { class DumpContext : public IAaptContext { @@ -299,17 +124,290 @@ class DumpContext : public IAaptContext { } // namespace -int DumpCommand::Action(const std::vector<std::string>& args) { +// Use a smaller buffer so that there is less latency for dumping to stdout. +constexpr size_t kStdOutBufferSize = 1024u; + +int DumpAPCCommand::Action(const std::vector<std::string>& args) { + DumpContext context; + DebugPrintTableOptions print_options; + print_options.show_sources = true; + print_options.show_values = !no_values_; + + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump container specified."); + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + for (auto container : args) { + io::FileInputStream input(container); + if (input.HadError()) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to open file: " << input.GetError()); + return false; + } + + // Try as a compiled file. + ContainerReader reader(&input); + if (reader.HadError()) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to read container: " << reader.GetError()); + return false; + } + + printer.Println("AAPT2 Container (APC)"); + ContainerReaderEntry* entry; + std::string error; + while ((entry = reader.Next()) != nullptr) { + if (entry->Type() == ContainerEntryType::kResTable) { + printer.Println("kResTable"); + + pb::ResourceTable pb_table; + if (!entry->GetResTable(&pb_table)) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to parse proto table: " + << entry->GetError()); + continue; + } + + ResourceTable table; + error.clear(); + if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) { + context.GetDiagnostics()->Error(DiagMessage(container) + << "failed to parse table: " << error); + continue; + } + + printer.Indent(); + Debug::PrintTable(table, print_options, &printer); + printer.Undent(); + } else if (entry->Type() == ContainerEntryType::kResFile) { + printer.Println("kResFile"); + pb::internal::CompiledFile pb_compiled_file; + off64_t offset; + size_t length; + if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) { + context.GetDiagnostics()->Error( + DiagMessage(container) << "failed to parse compiled proto file: " + << entry->GetError()); + continue; + } + + ResourceFile file; + if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) { + context.GetDiagnostics()->Warn(DiagMessage(container) + << "failed to parse compiled file: " << error); + continue; + } + + printer.Indent(); + DumpCompiledFile(file, Source(container), offset, length, &printer); + printer.Undent(); + } + } + } + + return 0; +} + +int DumpConfigsCommand::Action(const std::vector<std::string>& args) { + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified."); + return 1; + } + + auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_); + if (!loaded_apk) { + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + // Comparison function used to order configurations + auto compare = [](ConfigDescription c1, ConfigDescription c2) -> bool { + return c1.compare(c2) < 0; + }; + + // Insert the configurations into a set in order to keep every configuarion seen + std::set<ConfigDescription, decltype(compare)> configs(compare); + for (auto& package : loaded_apk->GetResourceTable()->packages) { + for (auto& type : package->types) { + for (auto& entry : type->entries) { + for (auto& value : entry->values) { + configs.insert(value->config); + } + } + } + } + + // Print the configurations in order + for (auto& config : configs) { + printer.Print(StringPrintf("%s\n", config.to_string().data())); + } + + return 0; +} + +int DumpStringsCommand::Action(const std::vector<std::string>& args) { DumpContext context; - context.SetVerbose(verbose_); - options_.print_options.show_sources = true; - options_.print_options.show_values = !no_values_; - for (const std::string& arg : args) { - if (!TryDumpFile(&context, arg, options_)) { + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified."); + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + for (auto apk : args) { + auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_); + if (!loaded_apk) { + return 1; + } + + // Load the run-time xml string pool using the flattened data + BigBuffer buffer(4096); + StringPool::FlattenUtf8(&buffer, loaded_apk->GetResourceTable()->string_pool, + context.GetDiagnostics()); + auto data = buffer.to_string(); + android::ResStringPool pool(data.data(), data.size(), false); + Debug::DumpResStringPool(&pool, &printer); + } + + return 0; +} + +int DumpTableCommand::Action(const std::vector<std::string>& args) { + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified."); + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + DebugPrintTableOptions print_options; + print_options.show_sources = true; + print_options.show_values = !no_values_; + + for (auto apk : args) { + auto loaded_apk = LoadedApk::LoadApkFromPath(apk, diag_); + if (!loaded_apk) { + return 1; + } + + if (loaded_apk->GetApkFormat()) { + printer.Println("Proto APK"); + } else { + printer.Println("Binary APK"); + } + + Debug::PrintTable(*loaded_apk->GetResourceTable(), print_options, &printer); + } + + return 0; +} + +int DumpXmlTreeCommand::Action(const std::vector<std::string>& args) { + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified"); + return 1; + } + + auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_); + if (!loaded_apk) { + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + // Dump the xml tree of every passed in file + for (auto file : files_) { + auto xml = loaded_apk->LoadXml(file, diag_); + if (!xml) { return 1; } + + Debug::DumpXml(*xml, &printer); + } + + return 0; +} + +int DumpXmlStringsCommand::Action(const std::vector<std::string>& args) { + DumpContext context; + if (args.size() < 1) { + diag_->Error(DiagMessage() << "No dump apk specified."); + return 1; + } + + auto loaded_apk = LoadedApk::LoadApkFromPath(args[0], diag_); + if (!loaded_apk) { + return 1; + } + + io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize); + Printer printer(&fout); + + // Dump the xml strings of every passed in file + for (auto xml_file : files_) { + android::ResXMLTree tree; + + if (loaded_apk->GetApkFormat() == kProto) { + auto xml = loaded_apk->LoadXml(xml_file, diag_); + if (!xml) { + return 1; + } + + // Flatten the xml document to get a binary representation of the proto xml file + BigBuffer buffer(4096); + XmlFlattenerOptions options = {}; + options.keep_raw_values = true; + XmlFlattener flattener(&buffer, options); + if (!flattener.Consume(&context, xml.get())) { + return 1; + } + + // Load the run-time xml tree using the flattened data + std::string data = buffer.to_string(); + tree.setTo(data.data(), data.size(), /** copyData */ true); + + } else if (loaded_apk->GetApkFormat() == kBinary) { + io::IFile* file = loaded_apk->GetFileCollection()->FindFile(xml_file); + if (!file) { + diag_->Error(DiagMessage(xml_file) << "file '" << xml_file << "' not found in APK"); + return 1; + } + + std::unique_ptr<io::IData> data = file->OpenAsData(); + if (!data) { + diag_->Error(DiagMessage() << "failed to open file"); + return 1; + } + + // Load the run-time xml tree from the file data + tree.setTo(data->data(), data->size(), /** copyData */ true); + } + + Debug::DumpResStringPool(&tree.getStrings(), &printer); } + return 0; } +/** Preform no action because a subcommand is required. */ +int DumpCommand::Action(const std::vector<std::string>& args) { + if (args.size() == 0) { + diag_->Error(DiagMessage() << "no subcommand specified"); + } else { + diag_->Error(DiagMessage() << "unknown subcommand '" << args[0] << "'"); + } + + Usage(&std::cerr); + return 1; +} + } // namespace aapt diff --git a/tools/aapt2/cmd/Dump.h b/tools/aapt2/cmd/Dump.h index 4893c8b76041..03a4fba133ba 100644 --- a/tools/aapt2/cmd/Dump.h +++ b/tools/aapt2/cmd/Dump.h @@ -22,33 +22,117 @@ namespace aapt { -struct DumpOptions { - DebugPrintTableOptions print_options; +/** Command the contents of files generated from the compilation stage. */ +class DumpAPCCommand : public Command { + public: + explicit DumpAPCCommand(IDiagnostics* diag) : Command("apc"), diag_(diag) { + SetDescription("Print the contents of the AAPT2 Container (APC) generated fom compilation."); + AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.", + &no_values_); + AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); + } - // The path to a file within an APK to dump. - Maybe<std::string> file_to_dump_path; + int Action(const std::vector<std::string>& args) override; + + private: + IDiagnostics* diag_; + bool verbose_ = false; + bool no_values_ = false; }; -class DumpCommand : public Command { +/** Prints every configuration used by a resource in an APK. */ +class DumpConfigsCommand : public Command { public: - DumpCommand() : Command("dump", "d") { - SetDescription("Prints resource and manifest information."); - AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.", - &no_values_); - AddOptionalFlag("--file", "Dumps the specified file from the APK passed as arg.", - &options_.file_to_dump_path); - AddOptionalSwitch("-v", "increase verbosity of output", &verbose_); + explicit DumpConfigsCommand(IDiagnostics* diag) : Command("configurations"), diag_(diag) { + SetDescription("Print every configuration used by a resource in the APK."); } int Action(const std::vector<std::string>& args) override; private: - DumpOptions options_; + IDiagnostics* diag_; +}; +/** Prints the contents of the resource table string pool in the APK. */ +class DumpStringsCommand : public Command { + public: + explicit DumpStringsCommand(IDiagnostics* diag) : Command("strings"), diag_(diag) { + SetDescription("Print the contents of the resource table string pool in the APK."); + } + + int Action(const std::vector<std::string>& args) override; + + private: + IDiagnostics* diag_; +}; + +/** Prints the contents of the resource table from the APK. */ +class DumpTableCommand : public Command { + public: + explicit DumpTableCommand(IDiagnostics* diag) : Command("resources"), diag_(diag) { + SetDescription("Print the contents of the resource table from the APK."); + AddOptionalSwitch("--no-values", "Suppresses output of values when displaying resource tables.", + &no_values_); + AddOptionalSwitch("-v", "Enables verbose logging.", &verbose_); + } + + int Action(const std::vector<std::string>& args) override; + + private: + IDiagnostics* diag_; bool verbose_ = false; bool no_values_ = false; }; +/** Prints the string pool of a compiled xml in an APK. */ +class DumpXmlStringsCommand : public Command { +public: + explicit DumpXmlStringsCommand(IDiagnostics* diag) : Command("xmlstrings"), diag_(diag) { + SetDescription("Print the string pool of a compiled xml in an APK."); + AddRequiredFlagList("--file", "A compiled xml file to print", &files_); + } + + int Action(const std::vector<std::string>& args) override; + +private: + IDiagnostics* diag_; + std::vector<std::string> files_; +}; + + +/** Prints the tree of a compiled xml in an APK. */ +class DumpXmlTreeCommand : public Command { + public: + explicit DumpXmlTreeCommand(IDiagnostics* diag) : Command("xmltree"), diag_(diag) { + SetDescription("Print the tree of a compiled xml in an APK."); + AddRequiredFlagList("--file", "A compiled xml file to print", &files_); + } + + int Action(const std::vector<std::string>& args) override; + + private: + IDiagnostics* diag_; + std::vector<std::string> files_; +}; + +/** The default dump command. Preforms no action because a subcommand is required. */ +class DumpCommand : public Command { + public: + explicit DumpCommand(IDiagnostics* diag) : Command("dump", "d"), diag_(diag) { + AddOptionalSubcommand(util::make_unique<DumpAPCCommand>(diag_)); + AddOptionalSubcommand(util::make_unique<DumpConfigsCommand>(diag_)); + AddOptionalSubcommand(util::make_unique<DumpStringsCommand>(diag_)); + AddOptionalSubcommand(util::make_unique<DumpTableCommand>(diag_)); + AddOptionalSubcommand(util::make_unique<DumpXmlStringsCommand>(diag_)); + AddOptionalSubcommand(util::make_unique<DumpXmlTreeCommand>(diag_)); + } + + int Action(const std::vector<std::string>& args) override; + + private: + IDiagnostics* diag_; +}; + }// namespace aapt #endif //AAPT2_DUMP_H |