Home | History | Annotate | Download | only in flatten
      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 
     27 namespace aapt {
     28 
     29 namespace {
     30 
     31 struct 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 
     95 struct 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 
    165 std::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 
    175 std::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