blob: 6db13b86fbfa49f0967fc5bf8de1dac2ef2523ca [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
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 <fstream>
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::vector<std::unique_ptr<ArchiveEntry>> mEntries;
34
35 explicit DirectoryWriter(const StringPiece& outDir) : mOutDir(outDir.toString()) {
36 }
37
38 ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags,
39 const BigBuffer& buffer) override {
40 std::string fullPath = mOutDir;
41 file::appendPath(&fullPath, path);
42 file::mkdirs(file::getStem(fullPath));
43
44 std::ofstream fout(fullPath, std::ofstream::binary);
45 if (!fout) {
46 return nullptr;
47 }
48
49 if (!util::writeAll(fout, buffer)) {
50 return nullptr;
51 }
52
53 mEntries.push_back(util::make_unique<ArchiveEntry>(fullPath, flags, buffer.size()));
54 return mEntries.back().get();
55 }
56
57 ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, android::FileMap* fileMap,
58 size_t offset, size_t len) override {
59 std::string fullPath = mOutDir;
60 file::appendPath(&fullPath, path);
61 file::mkdirs(file::getStem(fullPath));
62
63 std::ofstream fout(fullPath, std::ofstream::binary);
64 if (!fout) {
65 return nullptr;
66 }
67
68 if (!fout.write((const char*) fileMap->getDataPtr() + offset, len)) {
69 return nullptr;
70 }
71
72 mEntries.push_back(util::make_unique<ArchiveEntry>(fullPath, flags, len));
73 return mEntries.back().get();
74 }
75
76 virtual ~DirectoryWriter() {
77
78 }
79};
80
81struct ZipFileWriter : public IArchiveWriter {
82 FILE* mFile;
83 std::unique_ptr<ZipWriter> mWriter;
84 std::vector<std::unique_ptr<ArchiveEntry>> mEntries;
85
86 explicit ZipFileWriter(const StringPiece& path) {
87 mFile = fopen(path.data(), "w+b");
88 if (mFile) {
89 mWriter = util::make_unique<ZipWriter>(mFile);
90 }
91 }
92
93 ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags,
94 const BigBuffer& buffer) override {
95 if (!mWriter) {
96 return nullptr;
97 }
98
99 size_t zipFlags = 0;
100 if (flags & ArchiveEntry::kCompress) {
101 zipFlags |= ZipWriter::kCompress;
102 }
103
104 if (flags & ArchiveEntry::kAlign) {
105 zipFlags |= ZipWriter::kAlign32;
106 }
107
108 int32_t result = mWriter->StartEntry(path.data(), zipFlags);
109 if (result != 0) {
110 return nullptr;
111 }
112
113 for (const BigBuffer::Block& b : buffer) {
114 result = mWriter->WriteBytes(reinterpret_cast<const uint8_t*>(b.buffer.get()), b.size);
115 if (result != 0) {
116 return nullptr;
117 }
118 }
119
120 result = mWriter->FinishEntry();
121 if (result != 0) {
122 return nullptr;
123 }
124
125 mEntries.push_back(util::make_unique<ArchiveEntry>(path.toString(), flags, buffer.size()));
126 return mEntries.back().get();
127 }
128
129 ArchiveEntry* writeEntry(const StringPiece& path, uint32_t flags, android::FileMap* fileMap,
130 size_t offset, size_t len) override {
131 if (!mWriter) {
132 return nullptr;
133 }
134
135 size_t zipFlags = 0;
136 if (flags & ArchiveEntry::kCompress) {
137 zipFlags |= ZipWriter::kCompress;
138 }
139
140 if (flags & ArchiveEntry::kAlign) {
141 zipFlags |= ZipWriter::kAlign32;
142 }
143
144 int32_t result = mWriter->StartEntry(path.data(), zipFlags);
145 if (result != 0) {
146 return nullptr;
147 }
148
149 result = mWriter->WriteBytes((const char*) fileMap->getDataPtr() + offset, len);
150 if (result != 0) {
151 return nullptr;
152 }
153
154 result = mWriter->FinishEntry();
155 if (result != 0) {
156 return nullptr;
157 }
158
159 mEntries.push_back(util::make_unique<ArchiveEntry>(path.toString(), flags, len));
160 return mEntries.back().get();
161 }
162
163 virtual ~ZipFileWriter() {
164 if (mWriter) {
165 mWriter->Finish();
166 fclose(mFile);
167 }
168 }
169};
170
171} // namespace
172
173std::unique_ptr<IArchiveWriter> createDirectoryArchiveWriter(const StringPiece& path) {
174 return util::make_unique<DirectoryWriter>(path);
175}
176
177std::unique_ptr<IArchiveWriter> createZipFileArchiveWriter(const StringPiece& path) {
178 return util::make_unique<ZipFileWriter>(path);
179}
180
181} // namespace aapt