• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
openaapt::__anon56ee19d50111::DirectoryWriter35     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 
startEntryaapt::__anon56ee19d50111::DirectoryWriter48     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 
writeEntryaapt::__anon56ee19d50111::DirectoryWriter64     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 
writeEntryaapt::__anon56ee19d50111::DirectoryWriter78     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 
finishEntryaapt::__anon56ee19d50111::DirectoryWriter86     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 
openaapt::__anon56ee19d50111::ZipFileWriter99     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 
startEntryaapt::__anon56ee19d50111::ZipFileWriter109     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 
writeEntryaapt::__anon56ee19d50111::ZipFileWriter130     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 
writeEntryaapt::__anon56ee19d50111::ZipFileWriter138     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 
finishEntryaapt::__anon56ee19d50111::ZipFileWriter148     bool finishEntry() override {
149         int32_t result = mWriter->FinishEntry();
150         if (result != 0) {
151             return false;
152         }
153         return true;
154     }
155 
~ZipFileWriteraapt::__anon56ee19d50111::ZipFileWriter156     virtual ~ZipFileWriter() {
157         if (mWriter) {
158             mWriter->Finish();
159         }
160     }
161 };
162 
163 } // namespace
164 
createDirectoryArchiveWriter(IDiagnostics * diag,const StringPiece & path)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 
createZipFileArchiveWriter(IDiagnostics * diag,const StringPiece & path)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