blob: 427dc92505d458e2f987e3bba828d40294ab8e8c [file] [log] [blame]
Adam Lesinskia6fe3452015-12-09 15:20:52 -08001/*
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
Adam Lesinskia6fe3452015-12-09 15:20:52 -080017#include "io/ZipArchive.h"
Adam Lesinskia6fe3452015-12-09 15:20:52 -080018
Adam Lesinskice5e56e2016-10-21 17:56:45 -070019#include "utils/FileMap.h"
20#include "ziparchive/zip_archive.h"
21
22#include "Source.h"
Ryan Mitchellf3649d62018-08-02 16:16:45 -070023#include "util/Files.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070024#include "util/Util.h"
Adam Lesinskia6fe3452015-12-09 15:20:52 -080025
Adam Lesinski00451162017-10-03 07:44:08 -070026using ::android::StringPiece;
Adam Lesinskid5083f62017-01-16 15:07:21 -080027
Adam Lesinskia6fe3452015-12-09 15:20:52 -080028namespace aapt {
29namespace io {
30
Adam Lesinskice5e56e2016-10-21 17:56:45 -070031ZipFile::ZipFile(ZipArchiveHandle handle, const ZipEntry& entry,
32 const Source& source)
33 : zip_handle_(handle), zip_entry_(entry), source_(source) {}
Adam Lesinskia6fe3452015-12-09 15:20:52 -080034
Adam Lesinskice5e56e2016-10-21 17:56:45 -070035std::unique_ptr<IData> ZipFile::OpenAsData() {
Ryan Mitchellf6fe9b62018-09-24 12:13:31 -070036 // The file will fail to be mmaped if it is empty
37 if (zip_entry_.uncompressed_length == 0) {
38 return util::make_unique<EmptyData>();
39 }
40
Adam Lesinskice5e56e2016-10-21 17:56:45 -070041 if (zip_entry_.method == kCompressStored) {
42 int fd = GetFileDescriptor(zip_handle_);
Adam Lesinskia6fe3452015-12-09 15:20:52 -080043
Adam Lesinskice5e56e2016-10-21 17:56:45 -070044 android::FileMap file_map;
45 bool result = file_map.create(nullptr, fd, zip_entry_.offset,
46 zip_entry_.uncompressed_length, true);
47 if (!result) {
48 return {};
Adam Lesinskia6fe3452015-12-09 15:20:52 -080049 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070050 return util::make_unique<MmappedData>(std::move(file_map));
Adam Lesinskia6fe3452015-12-09 15:20:52 -080051
Adam Lesinskice5e56e2016-10-21 17:56:45 -070052 } else {
53 std::unique_ptr<uint8_t[]> data =
54 std::unique_ptr<uint8_t[]>(new uint8_t[zip_entry_.uncompressed_length]);
55 int32_t result =
56 ExtractToMemory(zip_handle_, &zip_entry_, data.get(),
57 static_cast<uint32_t>(zip_entry_.uncompressed_length));
Adam Lesinskia6fe3452015-12-09 15:20:52 -080058 if (result != 0) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070059 return {};
Adam Lesinskia6fe3452015-12-09 15:20:52 -080060 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070061 return util::make_unique<MallocData>(std::move(data),
62 zip_entry_.uncompressed_length);
63 }
Adam Lesinskia6fe3452015-12-09 15:20:52 -080064}
65
Adam Lesinski00451162017-10-03 07:44:08 -070066std::unique_ptr<io::InputStream> ZipFile::OpenInputStream() {
67 return OpenAsData();
68}
69
70const Source& ZipFile::GetSource() const {
71 return source_;
72}
Adam Lesinskice5e56e2016-10-21 17:56:45 -070073
Pierre Lecesne970732d2017-02-02 23:13:58 +000074bool ZipFile::WasCompressed() {
75 return zip_entry_.method != kCompressStored;
76}
77
Adam Lesinskice5e56e2016-10-21 17:56:45 -070078ZipFileCollectionIterator::ZipFileCollectionIterator(
79 ZipFileCollection* collection)
80 : current_(collection->files_.begin()), end_(collection->files_.end()) {}
81
Adam Lesinski00451162017-10-03 07:44:08 -070082bool ZipFileCollectionIterator::HasNext() {
83 return current_ != end_;
84}
Adam Lesinskice5e56e2016-10-21 17:56:45 -070085
86IFile* ZipFileCollectionIterator::Next() {
Pierre Lecesne880d65b2017-02-02 22:33:17 +000087 IFile* result = current_->get();
Adam Lesinskice5e56e2016-10-21 17:56:45 -070088 ++current_;
89 return result;
Adam Lesinskia6fe3452015-12-09 15:20:52 -080090}
91
Adam Lesinskice5e56e2016-10-21 17:56:45 -070092ZipFileCollection::ZipFileCollection() : handle_(nullptr) {}
93
94std::unique_ptr<ZipFileCollection> ZipFileCollection::Create(
95 const StringPiece& path, std::string* out_error) {
96 constexpr static const int32_t kEmptyArchive = -6;
97
98 std::unique_ptr<ZipFileCollection> collection =
99 std::unique_ptr<ZipFileCollection>(new ZipFileCollection());
100
101 int32_t result = OpenArchive(path.data(), &collection->handle_);
102 if (result != 0) {
103 // If a zip is empty, result will be an error code. This is fine and we
104 // should
105 // return an empty ZipFileCollection.
106 if (result == kEmptyArchive) {
107 return collection;
108 }
109
110 if (out_error) *out_error = ErrorCodeString(result);
111 return {};
112 }
113
114 void* cookie = nullptr;
115 result = StartIteration(collection->handle_, &cookie, nullptr, nullptr);
116 if (result != 0) {
117 if (out_error) *out_error = ErrorCodeString(result);
118 return {};
119 }
120
121 using IterationEnder = std::unique_ptr<void, decltype(EndIteration)*>;
122 IterationEnder iteration_ender(cookie, EndIteration);
123
124 ZipString zip_entry_name;
125 ZipEntry zip_data;
126 while ((result = Next(cookie, &zip_data, &zip_entry_name)) == 0) {
127 std::string zip_entry_path =
128 std::string(reinterpret_cast<const char*>(zip_entry_name.name),
129 zip_entry_name.name_length);
Ryan Mitchellf3649d62018-08-02 16:16:45 -0700130
131 // Do not add folders to the file collection
132 if (util::EndsWith(zip_entry_path, "/")) {
133 continue;
134 }
135
136 std::unique_ptr<IFile> file = util::make_unique<ZipFile>(collection->handle_, zip_data,
137 Source(zip_entry_path, path.to_string()));
Pierre Lecesne880d65b2017-02-02 22:33:17 +0000138 collection->files_by_name_[zip_entry_path] = file.get();
139 collection->files_.push_back(std::move(file));
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700140 }
141
142 if (result != -1) {
143 if (out_error) *out_error = ErrorCodeString(result);
144 return {};
145 }
Ryan Mitchellf3649d62018-08-02 16:16:45 -0700146
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700147 return collection;
148}
149
150IFile* ZipFileCollection::FindFile(const StringPiece& path) {
Pierre Lecesne880d65b2017-02-02 22:33:17 +0000151 auto iter = files_by_name_.find(path.to_string());
152 if (iter != files_by_name_.end()) {
153 return iter->second;
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700154 }
155 return nullptr;
156}
157
158std::unique_ptr<IFileCollectionIterator> ZipFileCollection::Iterator() {
159 return util::make_unique<ZipFileCollectionIterator>(this);
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800160}
161
Ryan Mitchell0ce89732018-10-03 09:20:57 -0700162char ZipFileCollection::GetDirSeparator() {
163 // According to the zip file specification, section 4.4.17.1:
164 // "All slashes MUST be forward slashes '/' as opposed to backwards slashes '\' for compatibility
165 // with Amiga and UNIX file systems etc."
166 return '/';
167}
168
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800169ZipFileCollection::~ZipFileCollection() {
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700170 if (handle_) {
171 CloseArchive(handle_);
172 }
Adam Lesinskia6fe3452015-12-09 15:20:52 -0800173}
174
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700175} // namespace io
176} // namespace aapt