AAPT2: Separate out the various steps
An early refactor. Some ideas became clearer as
development continued. Now the various phases are much
clearer and more easily reusable.
Also added a ton of tests!
Change-Id: Ic8f0a70c8222370352e63533b329c40457c0903e
diff --git a/tools/aapt2/flatten/Archive.cpp b/tools/aapt2/flatten/Archive.cpp
new file mode 100644
index 0000000..6db13b8
--- /dev/null
+++ b/tools/aapt2/flatten/Archive.cpp
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+#include "flatten/Archive.h"
+#include "util/Files.h"
+#include "util/StringPiece.h"
+
+#include <fstream>
+#include <memory>
+#include <string>
+#include <vector>
+#include <ziparchive/zip_writer.h>
+
+namespace aapt {
+
+namespace {
+
+struct DirectoryWriter : public IArchiveWriter {
+ std::string mOutDir;
+ std::vector<std::unique_ptr<ArchiveEntry>> mEntries;
+
+ explicit DirectoryWriter(const StringPiece& outDir) : mOutDir(outDir.toString()) {
+ }
+
+ 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;
+ }
+
+ if (!util::writeAll(fout, buffer)) {
+ return nullptr;
+ }
+
+ mEntries.push_back(util::make_unique<ArchiveEntry>(fullPath, flags, buffer.size()));
+ return mEntries.back().get();
+ }
+
+ 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;
+ }
+
+ if (!fout.write((const char*) fileMap->getDataPtr() + offset, len)) {
+ return nullptr;
+ }
+
+ mEntries.push_back(util::make_unique<ArchiveEntry>(fullPath, flags, len));
+ return mEntries.back().get();
+ }
+
+ virtual ~DirectoryWriter() {
+
+ }
+};
+
+struct ZipFileWriter : public IArchiveWriter {
+ FILE* mFile;
+ 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);
+ }
+ }
+
+ ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags,
+ const BigBuffer& buffer) override {
+ if (!mWriter) {
+ return nullptr;
+ }
+
+ 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);
+ 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;
+ }
+ }
+
+ result = mWriter->FinishEntry();
+ if (result != 0) {
+ return nullptr;
+ }
+
+ mEntries.push_back(util::make_unique<ArchiveEntry>(path.toString(), flags, buffer.size()));
+ return mEntries.back().get();
+ }
+
+ ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, android::FileMap* fileMap,
+ size_t offset, size_t len) override {
+ if (!mWriter) {
+ return nullptr;
+ }
+
+ 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);
+ if (result != 0) {
+ return nullptr;
+ }
+
+ result = mWriter->WriteBytes((const char*) fileMap->getDataPtr() + offset, len);
+ if (result != 0) {
+ return nullptr;
+ }
+
+ result = mWriter->FinishEntry();
+ if (result != 0) {
+ return nullptr;
+ }
+
+ mEntries.push_back(util::make_unique<ArchiveEntry>(path.toString(), flags, len));
+ return mEntries.back().get();
+ }
+
+ 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> createZipFileArchiveWriter(const StringPiece& path) {
+ return util::make_unique<ZipFileWriter>(path);
+}
+
+} // namespace aapt