Loading tools/aapt2/compile/Compile.cpp +154 −65 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include "compile/IdAssigner.h" #include "compile/Png.h" #include "compile/XmlIdCollector.h" #include "flatten/Archive.h" #include "flatten/FileExportWriter.h" #include "flatten/TableFlattener.h" #include "flatten/XmlFlattener.h" Loading @@ -31,6 +32,7 @@ #include "xml/XmlDom.h" #include "xml/XmlPullParser.h" #include <dirent.h> #include <fstream> #include <string> Loading Loading @@ -90,7 +92,7 @@ static Maybe<ResourcePathData> extractResourcePathData(const std::string& path, } return ResourcePathData{ Source{ path }, Source(path), util::utf8ToUtf16(dirStr), util::utf8ToUtf16(name), extension.toString(), Loading @@ -101,25 +103,79 @@ static Maybe<ResourcePathData> extractResourcePathData(const std::string& path, struct CompileOptions { std::string outputPath; Maybe<std::string> resDir; Maybe<std::u16string> product; bool verbose = false; }; static std::string buildIntermediateFilename(const std::string outDir, const ResourcePathData& data) { static std::string buildIntermediateFilename(const ResourcePathData& data) { std::stringstream name; name << data.resourceDir; if (!data.configStr.empty()) { name << "-" << data.configStr; } name << "_" << data.name << "." << data.extension << ".flat"; std::string outPath = outDir; file::appendPath(&outPath, name.str()); return outPath; return name.str(); } static bool isHidden(const StringPiece& filename) { return util::stringStartsWith<char>(filename, "."); } /** * Walks the res directory structure, looking for resource files. */ static bool loadInputFilesFromDir(IAaptContext* context, const CompileOptions& options, std::vector<ResourcePathData>* outPathData) { const std::string& rootDir = options.resDir.value(); std::unique_ptr<DIR, decltype(closedir)*> d(opendir(rootDir.data()), closedir); if (!d) { context->getDiagnostics()->error(DiagMessage() << strerror(errno)); return false; } while (struct dirent* entry = readdir(d.get())) { if (isHidden(entry->d_name)) { continue; } std::string prefixPath = rootDir; file::appendPath(&prefixPath, entry->d_name); if (file::getFileType(prefixPath) != file::FileType::kDirectory) { continue; } std::unique_ptr<DIR, decltype(closedir)*> subDir(opendir(prefixPath.data()), closedir); if (!subDir) { context->getDiagnostics()->error(DiagMessage() << strerror(errno)); return false; } while (struct dirent* leafEntry = readdir(subDir.get())) { if (isHidden(leafEntry->d_name)) { continue; } std::string fullPath = prefixPath; file::appendPath(&fullPath, leafEntry->d_name); std::string errStr; Maybe<ResourcePathData> pathData = extractResourcePathData(fullPath, &errStr); if (!pathData) { context->getDiagnostics()->error(DiagMessage() << errStr); return false; } outPathData->push_back(std::move(pathData.value())); } } return true; } static bool compileTable(IAaptContext* context, const CompileOptions& options, const ResourcePathData& pathData, const std::string& outputPath) { const ResourcePathData& pathData, IArchiveWriter* writer, const std::string& outputPath) { ResourceTable table; { std::ifstream fin(pathData.source.path, std::ifstream::binary); Loading Loading @@ -150,6 +206,7 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options, // Ensure we have the compilation package at least. table.createPackage(context->getCompilationPackage()); // Assign an ID to any package that has resources. for (auto& pkg : table.packages) { if (!pkg->id) { // If no package ID was set while parsing (public identifiers), auto assign an ID. Loading @@ -172,23 +229,24 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options, return false; } // Build the output filename. std::ofstream fout(outputPath, std::ofstream::binary); if (!fout) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); if (!writer->startEntry(outputPath, 0)) { context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open"); return false; } // Write it to disk. if (!util::writeAll(fout, buffer)) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); return false; } if (writer->writeEntry(buffer)) { if (writer->finishEntry()) { return true; } } context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write"); return false; } static bool compileXml(IAaptContext* context, const CompileOptions& options, const ResourcePathData& pathData, const std::string& outputPath) { const ResourcePathData& pathData, IArchiveWriter* writer, const std::string& outputPath) { std::unique_ptr<xml::XmlResource> xmlRes; Loading @@ -214,7 +272,7 @@ static bool compileXml(IAaptContext* context, const CompileOptions& options, return false; } xmlRes->file.name = ResourceName{ {}, *parseResourceType(pathData.resourceDir), pathData.name }; xmlRes->file.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name); xmlRes->file.config = pathData.config; xmlRes->file.source = pathData.source; Loading @@ -230,25 +288,27 @@ static bool compileXml(IAaptContext* context, const CompileOptions& options, fileExportWriter.finish(); std::ofstream fout(outputPath, std::ofstream::binary); if (!fout) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); if (!writer->startEntry(outputPath, 0)) { context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open"); return false; } // Write it to disk. if (!util::writeAll(fout, buffer)) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); return false; } if (writer->writeEntry(buffer)) { if (writer->finishEntry()) { return true; } } context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write"); return false; } static bool compilePng(IAaptContext* context, const CompileOptions& options, const ResourcePathData& pathData, const std::string& outputPath) { const ResourcePathData& pathData, IArchiveWriter* writer, const std::string& outputPath) { BigBuffer buffer(4096); ResourceFile resFile; resFile.name = ResourceName{ {}, *parseResourceType(pathData.resourceDir), pathData.name }; resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name); resFile.config = pathData.config; resFile.source = pathData.source; Loading @@ -269,24 +329,27 @@ static bool compilePng(IAaptContext* context, const CompileOptions& options, fileExportWriter.finish(); std::ofstream fout(outputPath, std::ofstream::binary); if (!fout) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); if (!writer->startEntry(outputPath, 0)) { context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open"); return false; } if (!util::writeAll(fout, buffer)) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); return false; } if (writer->writeEntry(buffer)) { if (writer->finishEntry()) { return true; } } context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write"); return false; } static bool compileFile(IAaptContext* context, const CompileOptions& options, const ResourcePathData& pathData, const std::string& outputPath) { const ResourcePathData& pathData, IArchiveWriter* writer, const std::string& outputPath) { BigBuffer buffer(256); ResourceFile resFile; resFile.name = ResourceName{ {}, *parseResourceType(pathData.resourceDir), pathData.name }; resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name); resFile.config = pathData.config; resFile.source = pathData.source; Loading @@ -299,9 +362,8 @@ static bool compileFile(IAaptContext* context, const CompileOptions& options, return false; } std::ofstream fout(outputPath, std::ofstream::binary); if (!fout) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); if (!writer->startEntry(outputPath, 0)) { context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open"); return false; } Loading @@ -309,17 +371,18 @@ static bool compileFile(IAaptContext* context, const CompileOptions& options, // the buffer the entire file. fileExportWriter.getChunkHeader()->size = util::hostToDevice32(buffer.size() + f.value().getDataLength()); if (!util::writeAll(fout, buffer)) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); return false; if (writer->writeEntry(buffer)) { if (writer->writeEntry(f.value().getDataPtr(), f.value().getDataLength())) { if (writer->finishEntry()) { return true; } } } if (!fout.write((const char*) f.value().getDataPtr(), f.value().getDataLength())) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write"); return false; } return true; } class CompileContext : public IAaptContext { private: Loading Loading @@ -359,6 +422,7 @@ int compile(const std::vector<StringPiece>& args) { Flags flags = Flags() .requiredFlag("-o", "Output path", &options.outputPath) .optionalFlag("--product", "Product type to compile", &product) .optionalFlag("--dir", "Directory to scan for resources", &options.resDir) .optionalSwitch("-v", "Enables verbose logging", &options.verbose); if (!flags.parse("aapt2 compile", args, &std::cerr)) { return 1; Loading @@ -369,8 +433,24 @@ int compile(const std::vector<StringPiece>& args) { } CompileContext context; std::unique_ptr<IArchiveWriter> archiveWriter; std::vector<ResourcePathData> inputData; if (options.resDir) { if (!flags.getArgs().empty()) { // Can't have both files and a resource directory. context.getDiagnostics()->error(DiagMessage() << "files given but --dir specified"); flags.usage("aapt2 compile", &std::cerr); return 1; } if (!loadInputFilesFromDir(&context, options, &inputData)) { return 1; } archiveWriter = createZipFileArchiveWriter(context.getDiagnostics(), options.outputPath); } else { inputData.reserve(flags.getArgs().size()); // Collect data from the path for each input file. Loading @@ -384,6 +464,13 @@ int compile(const std::vector<StringPiece>& args) { } } archiveWriter = createDirectoryArchiveWriter(context.getDiagnostics(), options.outputPath); } if (!archiveWriter) { return false; } bool error = false; for (ResourcePathData& pathData : inputData) { if (options.verbose) { Loading @@ -394,32 +481,34 @@ int compile(const std::vector<StringPiece>& args) { // Overwrite the extension. pathData.extension = "arsc"; const std::string outputFilename = buildIntermediateFilename( options.outputPath, pathData); if (!compileTable(&context, options, pathData, outputFilename)) { const std::string outputFilename = buildIntermediateFilename(pathData); if (!compileTable(&context, options, pathData, archiveWriter.get(), outputFilename)) { error = true; } } else { const std::string outputFilename = buildIntermediateFilename(options.outputPath, pathData); const std::string outputFilename = buildIntermediateFilename(pathData); if (const ResourceType* type = parseResourceType(pathData.resourceDir)) { if (*type != ResourceType::kRaw) { if (pathData.extension == "xml") { if (!compileXml(&context, options, pathData, outputFilename)) { if (!compileXml(&context, options, pathData, archiveWriter.get(), outputFilename)) { error = true; } } else if (pathData.extension == "png" || pathData.extension == "9.png") { if (!compilePng(&context, options, pathData, outputFilename)) { if (!compilePng(&context, options, pathData, archiveWriter.get(), outputFilename)) { error = true; } } else { if (!compileFile(&context, options, pathData, outputFilename)) { if (!compileFile(&context, options, pathData, archiveWriter.get(), outputFilename)) { error = true; } } } else { if (!compileFile(&context, options, pathData, outputFilename)) { if (!compileFile(&context, options, pathData, archiveWriter.get(), outputFilename)) { error = true; } } Loading tools/aapt2/flatten/Archive.cpp +89 −86 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ #include "util/Files.h" #include "util/StringPiece.h" #include <fstream> #include <cstdio> #include <memory> #include <string> #include <vector> Loading @@ -30,70 +30,85 @@ namespace { struct DirectoryWriter : public IArchiveWriter { std::string mOutDir; std::vector<std::unique_ptr<ArchiveEntry>> mEntries; std::unique_ptr<FILE, decltype(fclose)*> mFile = { nullptr, fclose }; explicit DirectoryWriter(const StringPiece& outDir) : mOutDir(outDir.toString()) { bool open(IDiagnostics* diag, const StringPiece& outDir) { mOutDir = outDir.toString(); file::FileType type = file::getFileType(mOutDir); if (type == file::FileType::kNonexistant) { diag->error(DiagMessage() << "directory " << mOutDir << " does not exist"); return false; } else if (type != file::FileType::kDirectory) { diag->error(DiagMessage() << mOutDir << " is not a directory"); return false; } ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, const BigBuffer& buffer) override { std::string fullPath = mOutDir; file::appendPath(&fullPath, path); file::mkdirs(file::getStem(fullPath)); std::ofstream fout(fullPath, std::ofstream::binary); if (!fout) { return nullptr; return true; } if (!util::writeAll(fout, buffer)) { return nullptr; } mEntries.push_back(util::make_unique<ArchiveEntry>(fullPath, flags, buffer.size())); return mEntries.back().get(); bool startEntry(const StringPiece& path, uint32_t flags) override { if (mFile) { return false; } ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, android::FileMap* fileMap, size_t offset, size_t len) override { std::string fullPath = mOutDir; file::appendPath(&fullPath, path); file::mkdirs(file::getStem(fullPath)); std::ofstream fout(fullPath, std::ofstream::binary); if (!fout) { return nullptr; mFile = { fopen(fullPath.data(), "wb"), fclose }; if (!mFile) { return false; } return true; } if (!fout.write((const char*) fileMap->getDataPtr() + offset, len)) { return nullptr; bool writeEntry(const BigBuffer& buffer) override { if (!mFile) { return false; } mEntries.push_back(util::make_unique<ArchiveEntry>(fullPath, flags, len)); return mEntries.back().get(); for (const BigBuffer::Block& b : buffer) { if (fwrite(b.buffer.get(), 1, b.size, mFile.get()) != b.size) { mFile.reset(nullptr); return false; } } return true; } virtual ~DirectoryWriter() { bool writeEntry(const void* data, size_t len) override { if (fwrite(data, 1, len, mFile.get()) != len) { mFile.reset(nullptr); return false; } return true; } bool finishEntry() override { if (!mFile) { return false; } mFile.reset(nullptr); return true; } }; struct ZipFileWriter : public IArchiveWriter { FILE* mFile; std::unique_ptr<FILE, decltype(fclose)*> mFile = { nullptr, fclose }; std::unique_ptr<ZipWriter> mWriter; std::vector<std::unique_ptr<ArchiveEntry>> mEntries; explicit ZipFileWriter(const StringPiece& path) { mFile = fopen(path.data(), "w+b"); if (mFile) { mWriter = util::make_unique<ZipWriter>(mFile); bool open(IDiagnostics* diag, const StringPiece& path) { mFile = { fopen(path.data(), "w+b"), fclose }; if (!mFile) { diag->error(DiagMessage() << "failed to open " << path << ": " << strerror(errno)); return false; } mWriter = util::make_unique<ZipWriter>(mFile.get()); return true; } ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, const BigBuffer& buffer) override { bool startEntry(const StringPiece& path, uint32_t flags) override { if (!mWriter) { return nullptr; return false; } size_t zipFlags = 0; Loading @@ -107,75 +122,63 @@ struct ZipFileWriter : public IArchiveWriter { int32_t result = mWriter->StartEntry(path.data(), zipFlags); if (result != 0) { return nullptr; } for (const BigBuffer::Block& b : buffer) { result = mWriter->WriteBytes(reinterpret_cast<const uint8_t*>(b.buffer.get()), b.size); if (result != 0) { return nullptr; return false; } return true; } result = mWriter->FinishEntry(); bool writeEntry(const void* data, size_t len) override { int32_t result = mWriter->WriteBytes(data, len); if (result != 0) { return nullptr; } mEntries.push_back(util::make_unique<ArchiveEntry>(path.toString(), flags, buffer.size())); return mEntries.back().get(); return false; } ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, android::FileMap* fileMap, size_t offset, size_t len) override { if (!mWriter) { return nullptr; return true; } size_t zipFlags = 0; if (flags & ArchiveEntry::kCompress) { zipFlags |= ZipWriter::kCompress; } if (flags & ArchiveEntry::kAlign) { zipFlags |= ZipWriter::kAlign32; } int32_t result = mWriter->StartEntry(path.data(), zipFlags); bool writeEntry(const BigBuffer& buffer) override { for (const BigBuffer::Block& b : buffer) { int32_t result = mWriter->WriteBytes(b.buffer.get(), b.size); if (result != 0) { return nullptr; return false; } result = mWriter->WriteBytes((const char*) fileMap->getDataPtr() + offset, len); if (result != 0) { return nullptr; } return true; } result = mWriter->FinishEntry(); bool finishEntry() override { int32_t result = mWriter->FinishEntry(); if (result != 0) { return nullptr; return false; } mEntries.push_back(util::make_unique<ArchiveEntry>(path.toString(), flags, len)); return mEntries.back().get(); return true; } virtual ~ZipFileWriter() { if (mWriter) { mWriter->Finish(); fclose(mFile); } } }; } // namespace std::unique_ptr<IArchiveWriter> createDirectoryArchiveWriter(const StringPiece& path) { return util::make_unique<DirectoryWriter>(path); std::unique_ptr<IArchiveWriter> createDirectoryArchiveWriter(IDiagnostics* diag, const StringPiece& path) { std::unique_ptr<DirectoryWriter> writer = util::make_unique<DirectoryWriter>(); if (!writer->open(diag, path)) { return {}; } return std::move(writer); } std::unique_ptr<IArchiveWriter> createZipFileArchiveWriter(const StringPiece& path) { return util::make_unique<ZipFileWriter>(path); std::unique_ptr<IArchiveWriter> createZipFileArchiveWriter(IDiagnostics* diag, const StringPiece& path) { std::unique_ptr<ZipFileWriter> writer = util::make_unique<ZipFileWriter>(); if (!writer->open(diag, path)) { return {}; } return std::move(writer); } } // namespace aapt tools/aapt2/flatten/Archive.h +9 −6 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #ifndef AAPT_FLATTEN_ARCHIVE_H #define AAPT_FLATTEN_ARCHIVE_H #include "Diagnostics.h" #include "util/BigBuffer.h" #include "util/Files.h" #include "util/StringPiece.h" Loading @@ -42,15 +43,17 @@ struct ArchiveEntry { struct IArchiveWriter { virtual ~IArchiveWriter() = default; virtual ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, const BigBuffer& buffer) = 0; virtual ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, android::FileMap* fileMap, size_t offset, size_t len) = 0; virtual bool startEntry(const StringPiece& path, uint32_t flags) = 0; virtual bool writeEntry(const BigBuffer& buffer) = 0; virtual bool writeEntry(const void* data, size_t len) = 0; virtual bool finishEntry() = 0; }; std::unique_ptr<IArchiveWriter> createDirectoryArchiveWriter(const StringPiece& path); std::unique_ptr<IArchiveWriter> createDirectoryArchiveWriter(IDiagnostics* diag, const StringPiece& path); std::unique_ptr<IArchiveWriter> createZipFileArchiveWriter(const StringPiece& path); std::unique_ptr<IArchiveWriter> createZipFileArchiveWriter(IDiagnostics* diag, const StringPiece& path); } // namespace aapt Loading tools/aapt2/io/Data.h 0 → 100644 +85 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 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. */ #ifndef AAPT_IO_DATA_H #define AAPT_IO_DATA_H #include <utils/FileMap.h> #include <memory> namespace aapt { namespace io { /** * Interface for a block of contiguous memory. An instance of this interface owns the data. */ class IData { public: virtual ~IData() = default; virtual const void* data() const = 0; virtual size_t size() const = 0; }; /** * Implementation of IData that exposes a memory mapped file. The mmapped file is owned by this * object. */ class MmappedData : public IData { public: explicit MmappedData(android::FileMap&& map) : mMap(std::forward<android::FileMap>(map)) { } const void* data() const override { return mMap.getDataPtr(); } size_t size() const override { return mMap.getDataLength(); } private: android::FileMap mMap; }; /** * Implementation of IData that exposes a block of memory that was malloc'ed (new'ed). The * memory is owned by this object. */ class MallocData : public IData { public: MallocData(std::unique_ptr<const uint8_t[]> data, size_t size) : mData(std::move(data)), mSize(size) { } const void* data() const override { return mData.get(); } size_t size() const override { return mSize; } private: std::unique_ptr<const uint8_t[]> mData; size_t mSize; }; } // namespace io } // namespace aapt #endif /* AAPT_IO_DATA_H */ Loading
tools/aapt2/compile/Compile.cpp +154 −65 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ #include "compile/IdAssigner.h" #include "compile/Png.h" #include "compile/XmlIdCollector.h" #include "flatten/Archive.h" #include "flatten/FileExportWriter.h" #include "flatten/TableFlattener.h" #include "flatten/XmlFlattener.h" Loading @@ -31,6 +32,7 @@ #include "xml/XmlDom.h" #include "xml/XmlPullParser.h" #include <dirent.h> #include <fstream> #include <string> Loading Loading @@ -90,7 +92,7 @@ static Maybe<ResourcePathData> extractResourcePathData(const std::string& path, } return ResourcePathData{ Source{ path }, Source(path), util::utf8ToUtf16(dirStr), util::utf8ToUtf16(name), extension.toString(), Loading @@ -101,25 +103,79 @@ static Maybe<ResourcePathData> extractResourcePathData(const std::string& path, struct CompileOptions { std::string outputPath; Maybe<std::string> resDir; Maybe<std::u16string> product; bool verbose = false; }; static std::string buildIntermediateFilename(const std::string outDir, const ResourcePathData& data) { static std::string buildIntermediateFilename(const ResourcePathData& data) { std::stringstream name; name << data.resourceDir; if (!data.configStr.empty()) { name << "-" << data.configStr; } name << "_" << data.name << "." << data.extension << ".flat"; std::string outPath = outDir; file::appendPath(&outPath, name.str()); return outPath; return name.str(); } static bool isHidden(const StringPiece& filename) { return util::stringStartsWith<char>(filename, "."); } /** * Walks the res directory structure, looking for resource files. */ static bool loadInputFilesFromDir(IAaptContext* context, const CompileOptions& options, std::vector<ResourcePathData>* outPathData) { const std::string& rootDir = options.resDir.value(); std::unique_ptr<DIR, decltype(closedir)*> d(opendir(rootDir.data()), closedir); if (!d) { context->getDiagnostics()->error(DiagMessage() << strerror(errno)); return false; } while (struct dirent* entry = readdir(d.get())) { if (isHidden(entry->d_name)) { continue; } std::string prefixPath = rootDir; file::appendPath(&prefixPath, entry->d_name); if (file::getFileType(prefixPath) != file::FileType::kDirectory) { continue; } std::unique_ptr<DIR, decltype(closedir)*> subDir(opendir(prefixPath.data()), closedir); if (!subDir) { context->getDiagnostics()->error(DiagMessage() << strerror(errno)); return false; } while (struct dirent* leafEntry = readdir(subDir.get())) { if (isHidden(leafEntry->d_name)) { continue; } std::string fullPath = prefixPath; file::appendPath(&fullPath, leafEntry->d_name); std::string errStr; Maybe<ResourcePathData> pathData = extractResourcePathData(fullPath, &errStr); if (!pathData) { context->getDiagnostics()->error(DiagMessage() << errStr); return false; } outPathData->push_back(std::move(pathData.value())); } } return true; } static bool compileTable(IAaptContext* context, const CompileOptions& options, const ResourcePathData& pathData, const std::string& outputPath) { const ResourcePathData& pathData, IArchiveWriter* writer, const std::string& outputPath) { ResourceTable table; { std::ifstream fin(pathData.source.path, std::ifstream::binary); Loading Loading @@ -150,6 +206,7 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options, // Ensure we have the compilation package at least. table.createPackage(context->getCompilationPackage()); // Assign an ID to any package that has resources. for (auto& pkg : table.packages) { if (!pkg->id) { // If no package ID was set while parsing (public identifiers), auto assign an ID. Loading @@ -172,23 +229,24 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options, return false; } // Build the output filename. std::ofstream fout(outputPath, std::ofstream::binary); if (!fout) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); if (!writer->startEntry(outputPath, 0)) { context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open"); return false; } // Write it to disk. if (!util::writeAll(fout, buffer)) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); return false; } if (writer->writeEntry(buffer)) { if (writer->finishEntry()) { return true; } } context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write"); return false; } static bool compileXml(IAaptContext* context, const CompileOptions& options, const ResourcePathData& pathData, const std::string& outputPath) { const ResourcePathData& pathData, IArchiveWriter* writer, const std::string& outputPath) { std::unique_ptr<xml::XmlResource> xmlRes; Loading @@ -214,7 +272,7 @@ static bool compileXml(IAaptContext* context, const CompileOptions& options, return false; } xmlRes->file.name = ResourceName{ {}, *parseResourceType(pathData.resourceDir), pathData.name }; xmlRes->file.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name); xmlRes->file.config = pathData.config; xmlRes->file.source = pathData.source; Loading @@ -230,25 +288,27 @@ static bool compileXml(IAaptContext* context, const CompileOptions& options, fileExportWriter.finish(); std::ofstream fout(outputPath, std::ofstream::binary); if (!fout) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); if (!writer->startEntry(outputPath, 0)) { context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open"); return false; } // Write it to disk. if (!util::writeAll(fout, buffer)) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); return false; } if (writer->writeEntry(buffer)) { if (writer->finishEntry()) { return true; } } context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write"); return false; } static bool compilePng(IAaptContext* context, const CompileOptions& options, const ResourcePathData& pathData, const std::string& outputPath) { const ResourcePathData& pathData, IArchiveWriter* writer, const std::string& outputPath) { BigBuffer buffer(4096); ResourceFile resFile; resFile.name = ResourceName{ {}, *parseResourceType(pathData.resourceDir), pathData.name }; resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name); resFile.config = pathData.config; resFile.source = pathData.source; Loading @@ -269,24 +329,27 @@ static bool compilePng(IAaptContext* context, const CompileOptions& options, fileExportWriter.finish(); std::ofstream fout(outputPath, std::ofstream::binary); if (!fout) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); if (!writer->startEntry(outputPath, 0)) { context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open"); return false; } if (!util::writeAll(fout, buffer)) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); return false; } if (writer->writeEntry(buffer)) { if (writer->finishEntry()) { return true; } } context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write"); return false; } static bool compileFile(IAaptContext* context, const CompileOptions& options, const ResourcePathData& pathData, const std::string& outputPath) { const ResourcePathData& pathData, IArchiveWriter* writer, const std::string& outputPath) { BigBuffer buffer(256); ResourceFile resFile; resFile.name = ResourceName{ {}, *parseResourceType(pathData.resourceDir), pathData.name }; resFile.name = ResourceName({}, *parseResourceType(pathData.resourceDir), pathData.name); resFile.config = pathData.config; resFile.source = pathData.source; Loading @@ -299,9 +362,8 @@ static bool compileFile(IAaptContext* context, const CompileOptions& options, return false; } std::ofstream fout(outputPath, std::ofstream::binary); if (!fout) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); if (!writer->startEntry(outputPath, 0)) { context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to open"); return false; } Loading @@ -309,17 +371,18 @@ static bool compileFile(IAaptContext* context, const CompileOptions& options, // the buffer the entire file. fileExportWriter.getChunkHeader()->size = util::hostToDevice32(buffer.size() + f.value().getDataLength()); if (!util::writeAll(fout, buffer)) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); return false; if (writer->writeEntry(buffer)) { if (writer->writeEntry(f.value().getDataPtr(), f.value().getDataLength())) { if (writer->finishEntry()) { return true; } } } if (!fout.write((const char*) f.value().getDataPtr(), f.value().getDataLength())) { context->getDiagnostics()->error(DiagMessage(Source{ outputPath }) << strerror(errno)); context->getDiagnostics()->error(DiagMessage(outputPath) << "failed to write"); return false; } return true; } class CompileContext : public IAaptContext { private: Loading Loading @@ -359,6 +422,7 @@ int compile(const std::vector<StringPiece>& args) { Flags flags = Flags() .requiredFlag("-o", "Output path", &options.outputPath) .optionalFlag("--product", "Product type to compile", &product) .optionalFlag("--dir", "Directory to scan for resources", &options.resDir) .optionalSwitch("-v", "Enables verbose logging", &options.verbose); if (!flags.parse("aapt2 compile", args, &std::cerr)) { return 1; Loading @@ -369,8 +433,24 @@ int compile(const std::vector<StringPiece>& args) { } CompileContext context; std::unique_ptr<IArchiveWriter> archiveWriter; std::vector<ResourcePathData> inputData; if (options.resDir) { if (!flags.getArgs().empty()) { // Can't have both files and a resource directory. context.getDiagnostics()->error(DiagMessage() << "files given but --dir specified"); flags.usage("aapt2 compile", &std::cerr); return 1; } if (!loadInputFilesFromDir(&context, options, &inputData)) { return 1; } archiveWriter = createZipFileArchiveWriter(context.getDiagnostics(), options.outputPath); } else { inputData.reserve(flags.getArgs().size()); // Collect data from the path for each input file. Loading @@ -384,6 +464,13 @@ int compile(const std::vector<StringPiece>& args) { } } archiveWriter = createDirectoryArchiveWriter(context.getDiagnostics(), options.outputPath); } if (!archiveWriter) { return false; } bool error = false; for (ResourcePathData& pathData : inputData) { if (options.verbose) { Loading @@ -394,32 +481,34 @@ int compile(const std::vector<StringPiece>& args) { // Overwrite the extension. pathData.extension = "arsc"; const std::string outputFilename = buildIntermediateFilename( options.outputPath, pathData); if (!compileTable(&context, options, pathData, outputFilename)) { const std::string outputFilename = buildIntermediateFilename(pathData); if (!compileTable(&context, options, pathData, archiveWriter.get(), outputFilename)) { error = true; } } else { const std::string outputFilename = buildIntermediateFilename(options.outputPath, pathData); const std::string outputFilename = buildIntermediateFilename(pathData); if (const ResourceType* type = parseResourceType(pathData.resourceDir)) { if (*type != ResourceType::kRaw) { if (pathData.extension == "xml") { if (!compileXml(&context, options, pathData, outputFilename)) { if (!compileXml(&context, options, pathData, archiveWriter.get(), outputFilename)) { error = true; } } else if (pathData.extension == "png" || pathData.extension == "9.png") { if (!compilePng(&context, options, pathData, outputFilename)) { if (!compilePng(&context, options, pathData, archiveWriter.get(), outputFilename)) { error = true; } } else { if (!compileFile(&context, options, pathData, outputFilename)) { if (!compileFile(&context, options, pathData, archiveWriter.get(), outputFilename)) { error = true; } } } else { if (!compileFile(&context, options, pathData, outputFilename)) { if (!compileFile(&context, options, pathData, archiveWriter.get(), outputFilename)) { error = true; } } Loading
tools/aapt2/flatten/Archive.cpp +89 −86 Original line number Diff line number Diff line Loading @@ -18,7 +18,7 @@ #include "util/Files.h" #include "util/StringPiece.h" #include <fstream> #include <cstdio> #include <memory> #include <string> #include <vector> Loading @@ -30,70 +30,85 @@ namespace { struct DirectoryWriter : public IArchiveWriter { std::string mOutDir; std::vector<std::unique_ptr<ArchiveEntry>> mEntries; std::unique_ptr<FILE, decltype(fclose)*> mFile = { nullptr, fclose }; explicit DirectoryWriter(const StringPiece& outDir) : mOutDir(outDir.toString()) { bool open(IDiagnostics* diag, const StringPiece& outDir) { mOutDir = outDir.toString(); file::FileType type = file::getFileType(mOutDir); if (type == file::FileType::kNonexistant) { diag->error(DiagMessage() << "directory " << mOutDir << " does not exist"); return false; } else if (type != file::FileType::kDirectory) { diag->error(DiagMessage() << mOutDir << " is not a directory"); return false; } ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, const BigBuffer& buffer) override { std::string fullPath = mOutDir; file::appendPath(&fullPath, path); file::mkdirs(file::getStem(fullPath)); std::ofstream fout(fullPath, std::ofstream::binary); if (!fout) { return nullptr; return true; } if (!util::writeAll(fout, buffer)) { return nullptr; } mEntries.push_back(util::make_unique<ArchiveEntry>(fullPath, flags, buffer.size())); return mEntries.back().get(); bool startEntry(const StringPiece& path, uint32_t flags) override { if (mFile) { return false; } ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, android::FileMap* fileMap, size_t offset, size_t len) override { std::string fullPath = mOutDir; file::appendPath(&fullPath, path); file::mkdirs(file::getStem(fullPath)); std::ofstream fout(fullPath, std::ofstream::binary); if (!fout) { return nullptr; mFile = { fopen(fullPath.data(), "wb"), fclose }; if (!mFile) { return false; } return true; } if (!fout.write((const char*) fileMap->getDataPtr() + offset, len)) { return nullptr; bool writeEntry(const BigBuffer& buffer) override { if (!mFile) { return false; } mEntries.push_back(util::make_unique<ArchiveEntry>(fullPath, flags, len)); return mEntries.back().get(); for (const BigBuffer::Block& b : buffer) { if (fwrite(b.buffer.get(), 1, b.size, mFile.get()) != b.size) { mFile.reset(nullptr); return false; } } return true; } virtual ~DirectoryWriter() { bool writeEntry(const void* data, size_t len) override { if (fwrite(data, 1, len, mFile.get()) != len) { mFile.reset(nullptr); return false; } return true; } bool finishEntry() override { if (!mFile) { return false; } mFile.reset(nullptr); return true; } }; struct ZipFileWriter : public IArchiveWriter { FILE* mFile; std::unique_ptr<FILE, decltype(fclose)*> mFile = { nullptr, fclose }; std::unique_ptr<ZipWriter> mWriter; std::vector<std::unique_ptr<ArchiveEntry>> mEntries; explicit ZipFileWriter(const StringPiece& path) { mFile = fopen(path.data(), "w+b"); if (mFile) { mWriter = util::make_unique<ZipWriter>(mFile); bool open(IDiagnostics* diag, const StringPiece& path) { mFile = { fopen(path.data(), "w+b"), fclose }; if (!mFile) { diag->error(DiagMessage() << "failed to open " << path << ": " << strerror(errno)); return false; } mWriter = util::make_unique<ZipWriter>(mFile.get()); return true; } ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, const BigBuffer& buffer) override { bool startEntry(const StringPiece& path, uint32_t flags) override { if (!mWriter) { return nullptr; return false; } size_t zipFlags = 0; Loading @@ -107,75 +122,63 @@ struct ZipFileWriter : public IArchiveWriter { int32_t result = mWriter->StartEntry(path.data(), zipFlags); if (result != 0) { return nullptr; } for (const BigBuffer::Block& b : buffer) { result = mWriter->WriteBytes(reinterpret_cast<const uint8_t*>(b.buffer.get()), b.size); if (result != 0) { return nullptr; return false; } return true; } result = mWriter->FinishEntry(); bool writeEntry(const void* data, size_t len) override { int32_t result = mWriter->WriteBytes(data, len); if (result != 0) { return nullptr; } mEntries.push_back(util::make_unique<ArchiveEntry>(path.toString(), flags, buffer.size())); return mEntries.back().get(); return false; } ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, android::FileMap* fileMap, size_t offset, size_t len) override { if (!mWriter) { return nullptr; return true; } size_t zipFlags = 0; if (flags & ArchiveEntry::kCompress) { zipFlags |= ZipWriter::kCompress; } if (flags & ArchiveEntry::kAlign) { zipFlags |= ZipWriter::kAlign32; } int32_t result = mWriter->StartEntry(path.data(), zipFlags); bool writeEntry(const BigBuffer& buffer) override { for (const BigBuffer::Block& b : buffer) { int32_t result = mWriter->WriteBytes(b.buffer.get(), b.size); if (result != 0) { return nullptr; return false; } result = mWriter->WriteBytes((const char*) fileMap->getDataPtr() + offset, len); if (result != 0) { return nullptr; } return true; } result = mWriter->FinishEntry(); bool finishEntry() override { int32_t result = mWriter->FinishEntry(); if (result != 0) { return nullptr; return false; } mEntries.push_back(util::make_unique<ArchiveEntry>(path.toString(), flags, len)); return mEntries.back().get(); return true; } virtual ~ZipFileWriter() { if (mWriter) { mWriter->Finish(); fclose(mFile); } } }; } // namespace std::unique_ptr<IArchiveWriter> createDirectoryArchiveWriter(const StringPiece& path) { return util::make_unique<DirectoryWriter>(path); std::unique_ptr<IArchiveWriter> createDirectoryArchiveWriter(IDiagnostics* diag, const StringPiece& path) { std::unique_ptr<DirectoryWriter> writer = util::make_unique<DirectoryWriter>(); if (!writer->open(diag, path)) { return {}; } return std::move(writer); } std::unique_ptr<IArchiveWriter> createZipFileArchiveWriter(const StringPiece& path) { return util::make_unique<ZipFileWriter>(path); std::unique_ptr<IArchiveWriter> createZipFileArchiveWriter(IDiagnostics* diag, const StringPiece& path) { std::unique_ptr<ZipFileWriter> writer = util::make_unique<ZipFileWriter>(); if (!writer->open(diag, path)) { return {}; } return std::move(writer); } } // namespace aapt
tools/aapt2/flatten/Archive.h +9 −6 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ #ifndef AAPT_FLATTEN_ARCHIVE_H #define AAPT_FLATTEN_ARCHIVE_H #include "Diagnostics.h" #include "util/BigBuffer.h" #include "util/Files.h" #include "util/StringPiece.h" Loading @@ -42,15 +43,17 @@ struct ArchiveEntry { struct IArchiveWriter { virtual ~IArchiveWriter() = default; virtual ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, const BigBuffer& buffer) = 0; virtual ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, android::FileMap* fileMap, size_t offset, size_t len) = 0; virtual bool startEntry(const StringPiece& path, uint32_t flags) = 0; virtual bool writeEntry(const BigBuffer& buffer) = 0; virtual bool writeEntry(const void* data, size_t len) = 0; virtual bool finishEntry() = 0; }; std::unique_ptr<IArchiveWriter> createDirectoryArchiveWriter(const StringPiece& path); std::unique_ptr<IArchiveWriter> createDirectoryArchiveWriter(IDiagnostics* diag, const StringPiece& path); std::unique_ptr<IArchiveWriter> createZipFileArchiveWriter(const StringPiece& path); std::unique_ptr<IArchiveWriter> createZipFileArchiveWriter(IDiagnostics* diag, const StringPiece& path); } // namespace aapt Loading
tools/aapt2/io/Data.h 0 → 100644 +85 −0 Original line number Diff line number Diff line /* * Copyright (C) 2015 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. */ #ifndef AAPT_IO_DATA_H #define AAPT_IO_DATA_H #include <utils/FileMap.h> #include <memory> namespace aapt { namespace io { /** * Interface for a block of contiguous memory. An instance of this interface owns the data. */ class IData { public: virtual ~IData() = default; virtual const void* data() const = 0; virtual size_t size() const = 0; }; /** * Implementation of IData that exposes a memory mapped file. The mmapped file is owned by this * object. */ class MmappedData : public IData { public: explicit MmappedData(android::FileMap&& map) : mMap(std::forward<android::FileMap>(map)) { } const void* data() const override { return mMap.getDataPtr(); } size_t size() const override { return mMap.getDataLength(); } private: android::FileMap mMap; }; /** * Implementation of IData that exposes a block of memory that was malloc'ed (new'ed). The * memory is owned by this object. */ class MallocData : public IData { public: MallocData(std::unique_ptr<const uint8_t[]> data, size_t size) : mData(std::move(data)), mSize(size) { } const void* data() const override { return mData.get(); } size_t size() const override { return mSize; } private: std::unique_ptr<const uint8_t[]> mData; size_t mSize; }; } // namespace io } // namespace aapt #endif /* AAPT_IO_DATA_H */