1/* 2 * Copyright (C) 2015 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 17#include "flatten/Archive.h" 18#include "util/Files.h" 19#include "util/StringPiece.h" 20 21#include <cstdio> 22#include <memory> 23#include <string> 24#include <vector> 25#include <ziparchive/zip_writer.h> 26 27namespace aapt { 28 29namespace { 30 31struct DirectoryWriter : public IArchiveWriter { 32 std::string mOutDir; 33 std::unique_ptr<FILE, decltype(fclose)*> mFile = { nullptr, fclose }; 34 35 bool open(IDiagnostics* diag, const StringPiece& outDir) { 36 mOutDir = outDir.toString(); 37 file::FileType type = file::getFileType(mOutDir); 38 if (type == file::FileType::kNonexistant) { 39 diag->error(DiagMessage() << "directory " << mOutDir << " does not exist"); 40 return false; 41 } else if (type != file::FileType::kDirectory) { 42 diag->error(DiagMessage() << mOutDir << " is not a directory"); 43 return false; 44 } 45 return true; 46 } 47 48 bool startEntry(const StringPiece& path, uint32_t flags) override { 49 if (mFile) { 50 return false; 51 } 52 53 std::string fullPath = mOutDir; 54 file::appendPath(&fullPath, path); 55 file::mkdirs(file::getStem(fullPath)); 56 57 mFile = { fopen(fullPath.data(), "wb"), fclose }; 58 if (!mFile) { 59 return false; 60 } 61 return true; 62 } 63 64 bool writeEntry(const BigBuffer& buffer) override { 65 if (!mFile) { 66 return false; 67 } 68 69 for (const BigBuffer::Block& b : buffer) { 70 if (fwrite(b.buffer.get(), 1, b.size, mFile.get()) != b.size) { 71 mFile.reset(nullptr); 72 return false; 73 } 74 } 75 return true; 76 } 77 78 bool writeEntry(const void* data, size_t len) override { 79 if (fwrite(data, 1, len, mFile.get()) != len) { 80 mFile.reset(nullptr); 81 return false; 82 } 83 return true; 84 } 85 86 bool finishEntry() override { 87 if (!mFile) { 88 return false; 89 } 90 mFile.reset(nullptr); 91 return true; 92 } 93}; 94 95struct ZipFileWriter : public IArchiveWriter { 96 std::unique_ptr<FILE, decltype(fclose)*> mFile = { nullptr, fclose }; 97 std::unique_ptr<ZipWriter> mWriter; 98 99 bool open(IDiagnostics* diag, const StringPiece& path) { 100 mFile = { fopen(path.data(), "w+b"), fclose }; 101 if (!mFile) { 102 diag->error(DiagMessage() << "failed to open " << path << ": " << strerror(errno)); 103 return false; 104 } 105 mWriter = util::make_unique<ZipWriter>(mFile.get()); 106 return true; 107 } 108 109 bool startEntry(const StringPiece& path, uint32_t flags) override { 110 if (!mWriter) { 111 return false; 112 } 113 114 size_t zipFlags = 0; 115 if (flags & ArchiveEntry::kCompress) { 116 zipFlags |= ZipWriter::kCompress; 117 } 118 119 if (flags & ArchiveEntry::kAlign) { 120 zipFlags |= ZipWriter::kAlign32; 121 } 122 123 int32_t result = mWriter->StartEntry(path.data(), zipFlags); 124 if (result != 0) { 125 return false; 126 } 127 return true; 128 } 129 130 bool writeEntry(const void* data, size_t len) override { 131 int32_t result = mWriter->WriteBytes(data, len); 132 if (result != 0) { 133 return false; 134 } 135 return true; 136 } 137 138 bool writeEntry(const BigBuffer& buffer) override { 139 for (const BigBuffer::Block& b : buffer) { 140 int32_t result = mWriter->WriteBytes(b.buffer.get(), b.size); 141 if (result != 0) { 142 return false; 143 } 144 } 145 return true; 146 } 147 148 bool finishEntry() override { 149 int32_t result = mWriter->FinishEntry(); 150 if (result != 0) { 151 return false; 152 } 153 return true; 154 } 155 156 virtual ~ZipFileWriter() { 157 if (mWriter) { 158 mWriter->Finish(); 159 } 160 } 161}; 162 163} // namespace 164 165std::unique_ptr<IArchiveWriter> createDirectoryArchiveWriter(IDiagnostics* diag, 166 const StringPiece& path) { 167 168 std::unique_ptr<DirectoryWriter> writer = util::make_unique<DirectoryWriter>(); 169 if (!writer->open(diag, path)) { 170 return {}; 171 } 172 return std::move(writer); 173} 174 175std::unique_ptr<IArchiveWriter> createZipFileArchiveWriter(IDiagnostics* diag, 176 const StringPiece& path) { 177 std::unique_ptr<ZipFileWriter> writer = util::make_unique<ZipFileWriter>(); 178 if (!writer->open(diag, path)) { 179 return {}; 180 } 181 return std::move(writer); 182} 183 184} // namespace aapt 185