blob: 7be6dc018ad5af33607dd397c06c8a4e12dc8a7d [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;
68 if (io::IFile* file = zip->FindFile("resources.arsc.flat")) {
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 Lesinskid0f492d2017-04-03 18:12:45 -070071 context->GetDiagnostics()->Error(DiagMessage(file_path)
72 << "failed to open resources.arsc.flat");
Pierre Lecesneaadf27e2017-05-05 14:58:21 +010073 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070074 }
Adam Lesinski64587af2016-02-18 18:33:06 -080075
Adam Lesinskice5e56e2016-10-21 17:56:45 -070076 pb::ResourceTable pb_table;
77 if (!pb_table.ParseFromArray(data->data(), data->size())) {
Adam Lesinskid0f492d2017-04-03 18:12:45 -070078 context->GetDiagnostics()->Error(DiagMessage(file_path) << "invalid resources.arsc.flat");
Pierre Lecesneaadf27e2017-05-05 14:58:21 +010079 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070080 }
Adam Lesinski64587af2016-02-18 18:33:06 -080081
Adam Lesinski8cdca1b2017-09-28 15:50:03 -070082 ResourceTable table;
83 if (!DeserializeTableFromPb(pb_table, &table, &err)) {
84 context->GetDiagnostics()->Error(DiagMessage(file_path)
85 << "failed to parse table: " << err);
86 return false;
87 }
88 } else if (io::IFile* file = zip->FindFile("resources.arsc")) {
89 std::unique_ptr<io::IData> data = file->OpenAsData();
90 if (!data) {
91 context->GetDiagnostics()->Error(DiagMessage(file_path) << "failed to open resources.arsc");
92 return false;
93 }
94
95 BinaryResourceParser parser(context, &table, Source(file_path), data->data(), data->size());
96 if (!parser.Parse()) {
Pierre Lecesneaadf27e2017-05-05 14:58:21 +010097 return false;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070098 }
Adam Lesinski64587af2016-02-18 18:33:06 -080099 }
100
Adam Lesinski00451162017-10-03 07:44:08 -0700101 Debug::PrintTable(&table, print_options);
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700102 return true;
103 }
Adam Lesinski5e8fa3a2016-06-27 16:21:42 -0700104
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700105 err.clear();
106
Adam Lesinski00451162017-10-03 07:44:08 -0700107 io::FileInputStream input(file_path);
108 if (input.HadError()) {
109 context->GetDiagnostics()->Error(DiagMessage(file_path)
110 << "failed to open file: " << input.GetError());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700111 return false;
112 }
113
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700114 // Try as a compiled file.
Adam Lesinski00451162017-10-03 07:44:08 -0700115 ContainerReader reader(&input);
116 if (reader.HadError()) {
117 context->GetDiagnostics()->Error(DiagMessage(file_path)
118 << "failed to read container: " << reader.GetError());
Adam Lesinski8cdca1b2017-09-28 15:50:03 -0700119 return false;
120 }
121
Adam Lesinski00451162017-10-03 07:44:08 -0700122 ContainerReaderEntry* entry;
123 while ((entry = reader.Next()) != nullptr) {
124 if (entry->Type() == ContainerEntryType::kResTable) {
125 pb::ResourceTable pb_table;
126 if (!entry->GetResTable(&pb_table)) {
127 context->GetDiagnostics()->Error(DiagMessage(file_path)
128 << "failed to parse proto table: " << entry->GetError());
129 continue;
130 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800131
Adam Lesinski00451162017-10-03 07:44:08 -0700132 ResourceTable table;
133 err.clear();
134 if (!DeserializeTableFromPb(pb_table, &table, &err)) {
135 context->GetDiagnostics()->Error(DiagMessage(file_path)
136 << "failed to parse table: " << err);
137 continue;
138 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700139
Adam Lesinski00451162017-10-03 07:44:08 -0700140 Debug::PrintTable(&table, print_options);
141 } else if (entry->Type() == ContainerEntryType::kResFile) {
142 pb::internal::CompiledFile pb_compiled_file;
143 off64_t offset;
144 size_t length;
145 if (!entry->GetResFileOffsets(&pb_compiled_file, &offset, &length)) {
146 context->GetDiagnostics()->Error(
147 DiagMessage(file_path) << "failed to parse compiled proto file: " << entry->GetError());
148 continue;
149 }
150
151 ResourceFile file;
152 std::string error;
153 if (!DeserializeCompiledFileFromPb(pb_compiled_file, &file, &error)) {
154 context->GetDiagnostics()->Warn(DiagMessage(file_path)
155 << "failed to parse compiled file: " << error);
156 continue;
157 }
158
159 DumpCompiledFile(file, Source(file_path), offset, length);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700160 }
161 }
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100162 return true;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800163}
164
Adam Lesinski00451162017-10-03 07:44:08 -0700165namespace {
166
Adam Lesinski59e04c62016-02-04 15:59:23 -0800167class DumpContext : public IAaptContext {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700168 public:
Adam Lesinskib522f042017-04-21 16:57:59 -0700169 PackageType GetPackageType() override {
170 // Doesn't matter.
171 return PackageType::kApp;
172 }
173
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700174 IDiagnostics* GetDiagnostics() override {
175 return &diagnostics_;
176 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800177
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700178 NameMangler* GetNameMangler() override {
Adam Lesinski00451162017-10-03 07:44:08 -0700179 UNIMPLEMENTED(FATAL);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700180 return nullptr;
181 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800182
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700183 const std::string& GetCompilationPackage() override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700184 static std::string empty;
185 return empty;
186 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800187
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700188 uint8_t GetPackageId() override {
189 return 0;
190 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800191
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700192 SymbolTable* GetExternalSymbols() override {
Adam Lesinski00451162017-10-03 07:44:08 -0700193 UNIMPLEMENTED(FATAL);
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700194 return nullptr;
195 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800196
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700197 bool IsVerbose() override {
198 return verbose_;
199 }
Adam Lesinski355f2852016-02-13 20:26:45 -0800200
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700201 void SetVerbose(bool val) {
202 verbose_ = val;
203 }
Adam Lesinski355f2852016-02-13 20:26:45 -0800204
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700205 int GetMinSdkVersion() override {
206 return 0;
207 }
Adam Lesinskifb6312f2016-06-28 14:40:32 -0700208
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700209 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700210 StdErrDiagnostics diagnostics_;
211 bool verbose_ = false;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800212};
213
Adam Lesinski00451162017-10-03 07:44:08 -0700214} // namespace
215
216// Entry point for dump command.
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700217int Dump(const std::vector<StringPiece>& args) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700218 bool verbose = false;
Adam Lesinskid0f492d2017-04-03 18:12:45 -0700219 Flags flags = Flags().OptionalSwitch("-v", "increase verbosity of output", &verbose);
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700220 if (!flags.Parse("aapt2 dump", args, &std::cerr)) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700221 return 1;
222 }
Adam Lesinski59e04c62016-02-04 15:59:23 -0800223
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700224 DumpContext context;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700225 context.SetVerbose(verbose);
Adam Lesinski59e04c62016-02-04 15:59:23 -0800226
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700227 for (const std::string& arg : flags.GetArgs()) {
Pierre Lecesneaadf27e2017-05-05 14:58:21 +0100228 if (!TryDumpFile(&context, arg)) {
229 return 1;
230 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700231 }
232 return 0;
Adam Lesinski59e04c62016-02-04 15:59:23 -0800233}
234
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700235} // namespace aapt