blob: 090c3fbc5731a3483640ee6a8baa554f383b7650 [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 Lesinski8cdca1b2017-09-28 15:50:03 -070081 if (!DeserializeTableFromPb(pb_table, &table, &err)) {
82 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
93 BinaryResourceParser parser(context, &table, Source(file_path), data->data(), data->size());
94 if (!parser.Parse()) {
Pierre Lecesneaadf27e2017-05-05 14:58:21 +010095 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070096 }
Adam Lesinski64587af2016-02-18 18:33:06 -080097 }
98
Adam Lesinskie59f0d82017-10-13 09:36:53 -070099 Debug::PrintTable(table, print_options);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700100 return true;
101 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700102
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700103 err.clear();
104
Adam Lesinski00451162017-10-03 07:44:08 -0700105 io::FileInputStream input(file_path);
106 if (input.HadError()) {
107 context->GetDiagnostics()->Error(DiagMessage(file_path)
108 << "failed to open file: " << input.GetError());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700109 return false;
110 }
111
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700112 // Try as a compiled file.
Adam Lesinski00451162017-10-03 07:44:08 -0700113 ContainerReader reader(&input);
114 if (reader.HadError()) {
115 context->GetDiagnostics()->Error(DiagMessage(file_path)
116 << "failed to read container: " << reader.GetError());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700117 return false;
118 }
119
Adam Lesinski00451162017-10-03 07:44:08 -0700120 ContainerReaderEntry* entry;
121 while ((entry = reader.Next()) != nullptr) {
122 if (entry->Type() == ContainerEntryType::kResTable) {
123 pb::ResourceTable pb_table;
124 if (!entry->GetResTable(&pb_table)) {
125 context->GetDiagnostics()->Error(DiagMessage(file_path)
126 << "failed to parse proto table: " << entry->GetError());
127 continue;
128 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800129
Adam Lesinski00451162017-10-03 07:44:08 -0700130 ResourceTable table;
131 err.clear();
132 if (!DeserializeTableFromPb(pb_table, &table, &err)) {
133 context->GetDiagnostics()->Error(DiagMessage(file_path)
134 << "failed to parse table: " << err);
135 continue;
136 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700137
Adam Lesinskie59f0d82017-10-13 09:36:53 -0700138 Debug::PrintTable(table, print_options);
Adam Lesinski00451162017-10-03 07:44:08 -0700139 } else if (entry->Type() == ContainerEntryType::kResFile) {
140 pb::internal::CompiledFile pb_compiled_file;
141 off64_t offset;
142 size_t length;
143 if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
144 context->GetDiagnostics()->Error(
145 DiagMessage(file_path) << "failed to parse compiled proto file: " << entry->GetError());
146 continue;
147 }
148
149 ResourceFile file;
150 std::string error;
151 if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
152 context->GetDiagnostics()->Warn(DiagMessage(file_path)
153 << "failed to parse compiled file: " << error);
154 continue;
155 }
156
157 DumpCompiledFile(file, Source(file_path), offset, length);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700158 }
159 }
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100160 return true;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800161}
162
Adam Lesinski00451162017-10-03 07:44:08 -0700163namespace {
164
Adam Lesinski59e04c62016-02-04 15:59:23 -0800165class DumpContext : public IAaptContext {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700166 public:
Adam Lesinskib522f042017-04-21 16:57:59 -0700167 PackageType GetPackageType() override {
168 // Doesn't matter.
169 return PackageType::kApp;
170 }
171
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700172 IDiagnostics* GetDiagnostics() override {
173 return &diagnostics_;
174 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800175
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700176 NameMangler* GetNameMangler() override {
Adam Lesinski00451162017-10-03 07:44:08 -0700177 UNIMPLEMENTED(FATAL);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700178 return nullptr;
179 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800180
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700181 const std::string& GetCompilationPackage() override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700182 static std::string empty;
183 return empty;
184 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800185
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700186 uint8_t GetPackageId() override {
187 return 0;
188 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800189
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700190 SymbolTable* GetExternalSymbols() override {
Adam Lesinski00451162017-10-03 07:44:08 -0700191 UNIMPLEMENTED(FATAL);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700192 return nullptr;
193 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800194
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700195 bool IsVerbose() override {
196 return verbose_;
197 }
Adam Lesinski355f2852016-02-13 20:26:45 -0800198
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700199 void SetVerbose(bool val) {
200 verbose_ = val;
201 }
Adam Lesinski355f2852016-02-13 20:26:45 -0800202
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700203 int GetMinSdkVersion() override {
204 return 0;
205 }
Adam Lesinskifb6312f2016-06-28 14:40:32 -0700206
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700207 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700208 StdErrDiagnostics diagnostics_;
209 bool verbose_ = false;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800210};
211
Adam Lesinski00451162017-10-03 07:44:08 -0700212} // namespace
213
214// Entry point for dump command.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700215int Dump(const std::vector<StringPiece>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700216 bool verbose = false;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700217 Flags flags = Flags().OptionalSwitch("-v", "increase verbosity of output", &verbose);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700218 if (!flags.Parse("aapt2 dump", args, &std::cerr)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700219 return 1;
220 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800221
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700222 DumpContext context;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700223 context.SetVerbose(verbose);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800224
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700225 for (const std::string& arg : flags.GetArgs()) {
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100226 if (!TryDumpFile(&context, arg)) {
227 return 1;
228 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700229 }
230 return 0;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800231}
232
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700233} // namespace aapt