blob: bc8f1dcb2289193397bac31cfca7b9c3d9ee33e1 [file] [log] [blame]
Adam Lesinski59e04c62016-02-04 15:59:23 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Adam Lesinskice5e56e2016-10-21 17:56:45 -070017#include <vector>
18
Adam Lesinskid5083f62017-01-16 15:07:21 -080019#include "androidfw/StringPiece.h"
20
Adam Lesinski59e04c62016-02-04 15:59:23 -080021#include "Debug.h"
22#include "Diagnostics.h"
23#include "Flags.h"
Adam Lesinski00451162017-10-03 07:44:08 -070024#include "format/Container.h"
Adam Lesinski46708052017-09-29 14:49:15 -070025#include "format/binary/BinaryResourceParser.h"
26#include "format/proto/ProtoDeserialize.h"
Adam Lesinski00451162017-10-03 07:44:08 -070027#include "io/FileStream.h"
Adam Lesinski64587af2016-02-18 18:33:06 -080028#include "io/ZipArchive.h"
Adam Lesinski59e04c62016-02-04 15:59:23 -080029#include "process/IResourceTableConsumer.h"
Adam Lesinski59e04c62016-02-04 15:59:23 -080030#include "util/Files.h"
Adam Lesinskid5083f62017-01-16 15:07:21 -080031
Adam Lesinski4ffea042017-08-10 15:37:28 -070032using ::android::StringPiece;
Adam Lesinski59e04c62016-02-04 15:59:23 -080033
Adam Lesinski59e04c62016-02-04 15:59:23 -080034namespace aapt {
35
Adam Lesinski00451162017-10-03 07:44:08 -070036static const char* ResourceFileTypeToString(const ResourceFile::Type& type) {
37 switch (type) {
38 case ResourceFile::Type::kPng:
39 return "PNG";
40 case ResourceFile::Type::kBinaryXml:
41 return "BINARY_XML";
42 case ResourceFile::Type::kProtoXml:
43 return "PROTO_XML";
44 default:
45 break;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070046 }
Adam Lesinski00451162017-10-03 07:44:08 -070047 return "UNKNOWN";
Adam Lesinski59e04c62016-02-04 15:59:23 -080048}
49
Adam Lesinski00451162017-10-03 07:44:08 -070050static void DumpCompiledFile(const ResourceFile& file, const Source& source, off64_t offset,
51 size_t len) {
52 std::cout << "Resource: " << file.name << "\n"
53 << "Config: " << file.config << "\n"
54 << "Source: " << file.source << "\n"
55 << "Type: " << ResourceFileTypeToString(file.type) << "\n"
56 << "DataOff: " << offset << "\n"
57 << "DataLen: " << len << "\n";
58}
59
60static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
61 DebugPrintTableOptions print_options;
62 print_options.show_sources = true;
63
Adam Lesinskicacb28f2016-10-19 12:18:14 -070064 std::string err;
Adam Lesinskid0f492d2017-04-03 18:12:45 -070065 std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::Create(file_path, &err);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070066 if (zip) {
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070067 ResourceTable table;
Adam Lesinskie59f0d82017-10-13 09:36:53 -070068 if (io::IFile* file = zip->FindFile("resources.pb")) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070069 std::unique_ptr<io::IData> data = file->OpenAsData();
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070070 if (data == nullptr) {
Adam Lesinskie59f0d82017-10-13 09:36:53 -070071 context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.pb");
Pierre Lecesneaadf27e2017-05-05 14:58:21 +010072 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070073 }
Adam Lesinski64587af2016-02-18 18:33:06 -080074
Adam Lesinskice5e56e2016-10-21 17:56:45 -070075 pb::ResourceTable pb_table;
76 if (!pb_table.ParseFromArray(data->data(), data->size())) {
Adam Lesinskie59f0d82017-10-13 09:36:53 -070077 context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.pb");
Pierre Lecesneaadf27e2017-05-05 14:58:21 +010078 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070079 }
Adam Lesinski64587af2016-02-18 18:33:06 -080080
Adam Lesinski8780eb62017-10-31 17:44:39 -070081 if (!DeserializeTableFromPb(pb_table, zip.get(), &table, &err)) {
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070082 context->GetDiagnostics()->Error(DiagMessage(file_path)
83 << "failed to parse table: " << err);
84 return false;
85 }
86 } else if (io::IFile* file = zip->FindFile("resources.arsc")) {
87 std::unique_ptr<io::IData> data = file->OpenAsData();
88 if (!data) {
89 context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc");
90 return false;
91 }
92
Adam Lesinski8780eb62017-10-31 17:44:39 -070093 BinaryResourceParser parser(context->GetDiagnostics(), &table, Source(file_path),
94 data->data(), data->size());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070095 if (!parser.Parse()) {
Pierre Lecesneaadf27e2017-05-05 14:58:21 +010096 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070097 }
Adam Lesinski64587af2016-02-18 18:33:06 -080098 }
99
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700100 Debug::PrintTable(table, print_options);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700101 return true;
102 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700103
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700104 err.clear();
105
Adam Lesinski00451162017-10-03 07:44:08 -0700106 io::FileInputStream input(file_path);
107 if (input.HadError()) {
108 context->GetDiagnostics()->Error(DiagMessage(file_path)
109 << "failed to open file: " << input.GetError());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700110 return false;
111 }
112
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700113 // Try as a compiled file.
Adam Lesinski00451162017-10-03 07:44:08 -0700114 ContainerReader reader(&input);
115 if (reader.HadError()) {
116 context->GetDiagnostics()->Error(DiagMessage(file_path)
117 << "failed to read container: " << reader.GetError());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700118 return false;
119 }
120
Adam Lesinski00451162017-10-03 07:44:08 -0700121 ContainerReaderEntry* entry;
122 while ((entry = reader.Next()) != nullptr) {
123 if (entry->Type() == ContainerEntryType::kResTable) {
124 pb::ResourceTable pb_table;
125 if (!entry->GetResTable(&pb_table)) {
126 context->GetDiagnostics()->Error(DiagMessage(file_path)
127 << "failed to parse proto table: " << entry->GetError());
128 continue;
129 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800130
Adam Lesinski00451162017-10-03 07:44:08 -0700131 ResourceTable table;
132 err.clear();
Adam Lesinski8780eb62017-10-31 17:44:39 -0700133 if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &err)) {
Adam Lesinski00451162017-10-03 07:44:08 -0700134 context->GetDiagnostics()->Error(DiagMessage(file_path)
135 << "failed to parse table: " << err);
136 continue;
137 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700138
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700139 Debug::PrintTable(table, print_options);
Adam Lesinski00451162017-10-03 07:44:08 -0700140 } else if (entry->Type() == ContainerEntryType::kResFile) {
141 pb::internal::CompiledFile pb_compiled_file;
142 off64_t offset;
143 size_t length;
144 if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
145 context->GetDiagnostics()->Error(
146 DiagMessage(file_path) << "failed to parse compiled proto file: " << entry->GetError());
147 continue;
148 }
149
150 ResourceFile file;
151 std::string error;
152 if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
153 context->GetDiagnostics()->Warn(DiagMessage(file_path)
154 << "failed to parse compiled file: " << error);
155 continue;
156 }
157
158 DumpCompiledFile(file, Source(file_path), offset, length);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700159 }
160 }
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100161 return true;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800162}
163
Adam Lesinski00451162017-10-03 07:44:08 -0700164namespace {
165
Adam Lesinski59e04c62016-02-04 15:59:23 -0800166class DumpContext : public IAaptContext {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700167 public:
Adam Lesinskib522f042017-04-21 16:57:59 -0700168 PackageType GetPackageType() override {
169 // Doesn't matter.
170 return PackageType::kApp;
171 }
172
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700173 IDiagnostics* GetDiagnostics() override {
174 return &diagnostics_;
175 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800176
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700177 NameMangler* GetNameMangler() override {
Adam Lesinski00451162017-10-03 07:44:08 -0700178 UNIMPLEMENTED(FATAL);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700179 return nullptr;
180 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800181
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700182 const std::string& GetCompilationPackage() override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700183 static std::string empty;
184 return empty;
185 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800186
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700187 uint8_t GetPackageId() override {
188 return 0;
189 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800190
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700191 SymbolTable* GetExternalSymbols() override {
Adam Lesinski00451162017-10-03 07:44:08 -0700192 UNIMPLEMENTED(FATAL);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700193 return nullptr;
194 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800195
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700196 bool IsVerbose() override {
197 return verbose_;
198 }
Adam Lesinski355f2852016-02-13 20:26:45 -0800199
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700200 void SetVerbose(bool val) {
201 verbose_ = val;
202 }
Adam Lesinski355f2852016-02-13 20:26:45 -0800203
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700204 int GetMinSdkVersion() override {
205 return 0;
206 }
Adam Lesinskifb6312f2016-06-28 14:40:32 -0700207
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700208 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700209 StdErrDiagnostics diagnostics_;
210 bool verbose_ = false;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800211};
212
Adam Lesinski00451162017-10-03 07:44:08 -0700213} // namespace
214
215// Entry point for dump command.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700216int Dump(const std::vector<StringPiece>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700217 bool verbose = false;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700218 Flags flags = Flags().OptionalSwitch("-v", "increase verbosity of output", &verbose);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700219 if (!flags.Parse("aapt2 dump", args, &std::cerr)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700220 return 1;
221 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800222
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700223 DumpContext context;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700224 context.SetVerbose(verbose);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800225
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700226 for (const std::string& arg : flags.GetArgs()) {
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100227 if (!TryDumpFile(&context, arg)) {
228 return 1;
229 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700230 }
231 return 0;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800232}
233
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700234} // namespace aapt