| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "Debug.h" |
| #include "Diagnostics.h" |
| #include "Flags.h" |
| #include "io/ZipArchive.h" |
| #include "process/IResourceTableConsumer.h" |
| #include "proto/ProtoSerialize.h" |
| #include "unflatten/BinaryResourceParser.h" |
| #include "util/Files.h" |
| #include "util/StringPiece.h" |
| |
| #include <vector> |
| |
| namespace aapt { |
| |
| // struct DumpOptions { |
| // |
| //}; |
| |
| void dumpCompiledFile(const pb::CompiledFile& pbFile, const void* data, |
| size_t len, const Source& source, IAaptContext* context) { |
| std::unique_ptr<ResourceFile> file = |
| deserializeCompiledFileFromPb(pbFile, source, context->getDiagnostics()); |
| if (!file) { |
| context->getDiagnostics()->warn(DiagMessage() |
| << "failed to read compiled file"); |
| return; |
| } |
| |
| std::cout << "Resource: " << file->name << "\n" |
| << "Config: " << file->config << "\n" |
| << "Source: " << file->source << "\n"; |
| } |
| |
| void tryDumpFile(IAaptContext* context, const std::string& filePath) { |
| std::unique_ptr<ResourceTable> table; |
| |
| std::string err; |
| std::unique_ptr<io::ZipFileCollection> zip = |
| io::ZipFileCollection::create(filePath, &err); |
| if (zip) { |
| io::IFile* file = zip->findFile("resources.arsc.flat"); |
| if (file) { |
| std::unique_ptr<io::IData> data = file->openAsData(); |
| if (!data) { |
| context->getDiagnostics()->error( |
| DiagMessage(filePath) << "failed to open resources.arsc.flat"); |
| return; |
| } |
| |
| pb::ResourceTable pbTable; |
| if (!pbTable.ParseFromArray(data->data(), data->size())) { |
| context->getDiagnostics()->error(DiagMessage(filePath) |
| << "invalid resources.arsc.flat"); |
| return; |
| } |
| |
| table = deserializeTableFromPb(pbTable, Source(filePath), |
| context->getDiagnostics()); |
| if (!table) { |
| return; |
| } |
| } |
| |
| if (!table) { |
| file = zip->findFile("resources.arsc"); |
| if (file) { |
| std::unique_ptr<io::IData> data = file->openAsData(); |
| if (!data) { |
| context->getDiagnostics()->error(DiagMessage(filePath) |
| << "failed to open resources.arsc"); |
| return; |
| } |
| |
| table = util::make_unique<ResourceTable>(); |
| BinaryResourceParser parser(context, table.get(), Source(filePath), |
| data->data(), data->size()); |
| if (!parser.parse()) { |
| return; |
| } |
| } |
| } |
| } |
| |
| if (!table) { |
| Maybe<android::FileMap> file = file::mmapPath(filePath, &err); |
| if (!file) { |
| context->getDiagnostics()->error(DiagMessage(filePath) << err); |
| return; |
| } |
| |
| android::FileMap* fileMap = &file.value(); |
| |
| // Try as a compiled table. |
| pb::ResourceTable pbTable; |
| if (pbTable.ParseFromArray(fileMap->getDataPtr(), |
| fileMap->getDataLength())) { |
| table = deserializeTableFromPb(pbTable, Source(filePath), |
| context->getDiagnostics()); |
| } |
| |
| if (!table) { |
| // Try as a compiled file. |
| CompiledFileInputStream input(fileMap->getDataPtr(), |
| fileMap->getDataLength()); |
| |
| uint32_t numFiles = 0; |
| if (!input.ReadLittleEndian32(&numFiles)) { |
| return; |
| } |
| |
| for (uint32_t i = 0; i < numFiles; i++) { |
| pb::CompiledFile compiledFile; |
| if (!input.ReadCompiledFile(&compiledFile)) { |
| context->getDiagnostics()->warn(DiagMessage() |
| << "failed to read compiled file"); |
| return; |
| } |
| |
| uint64_t offset, len; |
| if (!input.ReadDataMetaData(&offset, &len)) { |
| context->getDiagnostics()->warn(DiagMessage() |
| << "failed to read meta data"); |
| return; |
| } |
| |
| const void* data = |
| static_cast<const uint8_t*>(fileMap->getDataPtr()) + offset; |
| dumpCompiledFile(compiledFile, data, len, Source(filePath), context); |
| } |
| } |
| } |
| |
| if (table) { |
| DebugPrintTableOptions debugPrintTableOptions; |
| debugPrintTableOptions.showSources = true; |
| Debug::printTable(table.get(), debugPrintTableOptions); |
| } |
| } |
| |
| class DumpContext : public IAaptContext { |
| public: |
| IDiagnostics* getDiagnostics() override { return &mDiagnostics; } |
| |
| NameMangler* getNameMangler() override { |
| abort(); |
| return nullptr; |
| } |
| |
| const std::string& getCompilationPackage() override { |
| static std::string empty; |
| return empty; |
| } |
| |
| uint8_t getPackageId() override { return 0; } |
| |
| SymbolTable* getExternalSymbols() override { |
| abort(); |
| return nullptr; |
| } |
| |
| bool verbose() override { return mVerbose; } |
| |
| void setVerbose(bool val) { mVerbose = val; } |
| |
| int getMinSdkVersion() override { return 0; } |
| |
| private: |
| StdErrDiagnostics mDiagnostics; |
| bool mVerbose = false; |
| }; |
| |
| /** |
| * Entry point for dump command. |
| */ |
| int dump(const std::vector<StringPiece>& args) { |
| bool verbose = false; |
| Flags flags = |
| Flags().optionalSwitch("-v", "increase verbosity of output", &verbose); |
| if (!flags.parse("aapt2 dump", args, &std::cerr)) { |
| return 1; |
| } |
| |
| DumpContext context; |
| context.setVerbose(verbose); |
| |
| for (const std::string& arg : flags.getArgs()) { |
| tryDumpFile(&context, arg); |
| } |
| return 0; |
| } |
| |
| } // namespace aapt |