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 "io/ZipArchive.h" 18 19 #include "utils/FileMap.h" 20 #include "ziparchive/zip_archive.h" 21 22 #include "Source.h" 23 #include "util/Util.h" 24 25 using ::android::StringPiece; 26 27 namespace aapt { 28 namespace io { 29 30 ZipFile::ZipFile(ZipArchiveHandle handle, const ZipEntry& entry, 31 const Source& source) 32 : zip_handle_(handle), zip_entry_(entry), source_(source) {} 33 34 std::unique_ptr<IData> ZipFile::OpenAsData() { 35 if (zip_entry_.method == kCompressStored) { 36 int fd = GetFileDescriptor(zip_handle_); 37 38 android::FileMap file_map; 39 bool result = file_map.create(nullptr, fd, zip_entry_.offset, 40 zip_entry_.uncompressed_length, true); 41 if (!result) { 42 return {}; 43 } 44 return util::make_unique<MmappedData>(std::move(file_map)); 45 46 } else { 47 std::unique_ptr<uint8_t[]> data = 48 std::unique_ptr<uint8_t[]>(new uint8_t[zip_entry_.uncompressed_length]); 49 int32_t result = 50 ExtractToMemory(zip_handle_, &zip_entry_, data.get(), 51 static_cast<uint32_t>(zip_entry_.uncompressed_length)); 52 if (result != 0) { 53 return {}; 54 } 55 return util::make_unique<MallocData>(std::move(data), 56 zip_entry_.uncompressed_length); 57 } 58 } 59 60 std::unique_ptr<io::InputStream> ZipFile::OpenInputStream() { 61 return OpenAsData(); 62 } 63 64 const Source& ZipFile::GetSource() const { 65 return source_; 66 } 67 68 bool ZipFile::WasCompressed() { 69 return zip_entry_.method != kCompressStored; 70 } 71 72 ZipFileCollectionIterator::ZipFileCollectionIterator( 73 ZipFileCollection* collection) 74 : current_(collection->files_.begin()), end_(collection->files_.end()) {} 75 76 bool ZipFileCollectionIterator::HasNext() { 77 return current_ != end_; 78 } 79 80 IFile* ZipFileCollectionIterator::Next() { 81 IFile* result = current_->get(); 82 ++current_; 83 return result; 84 } 85 86 ZipFileCollection::ZipFileCollection() : handle_(nullptr) {} 87 88 std::unique_ptr<ZipFileCollection> ZipFileCollection::Create( 89 const StringPiece& path, std::string* out_error) { 90 constexpr static const int32_t kEmptyArchive = -6; 91 92 std::unique_ptr<ZipFileCollection> collection = 93 std::unique_ptr<ZipFileCollection>(new ZipFileCollection()); 94 95 int32_t result = OpenArchive(path.data(), &collection->handle_); 96 if (result != 0) { 97 // If a zip is empty, result will be an error code. This is fine and we 98 // should 99 // return an empty ZipFileCollection. 100 if (result == kEmptyArchive) { 101 return collection; 102 } 103 104 if (out_error) *out_error = ErrorCodeString(result); 105 return {}; 106 } 107 108 void* cookie = nullptr; 109 result = StartIteration(collection->handle_, &cookie, nullptr, nullptr); 110 if (result != 0) { 111 if (out_error) *out_error = ErrorCodeString(result); 112 return {}; 113 } 114 115 using IterationEnder = std::unique_ptr<void, decltype(EndIteration)*>; 116 IterationEnder iteration_ender(cookie, EndIteration); 117 118 ZipString zip_entry_name; 119 ZipEntry zip_data; 120 while ((result = Next(cookie, &zip_data, &zip_entry_name)) == 0) { 121 std::string zip_entry_path = 122 std::string(reinterpret_cast<const char*>(zip_entry_name.name), 123 zip_entry_name.name_length); 124 std::string nested_path = path.to_string() + "@" + zip_entry_path; 125 std::unique_ptr<IFile> file = 126 util::make_unique<ZipFile>(collection->handle_, zip_data, Source(nested_path)); 127 collection->files_by_name_[zip_entry_path] = file.get(); 128 collection->files_.push_back(std::move(file)); 129 } 130 131 if (result != -1) { 132 if (out_error) *out_error = ErrorCodeString(result); 133 return {}; 134 } 135 return collection; 136 } 137 138 IFile* ZipFileCollection::FindFile(const StringPiece& path) { 139 auto iter = files_by_name_.find(path.to_string()); 140 if (iter != files_by_name_.end()) { 141 return iter->second; 142 } 143 return nullptr; 144 } 145 146 std::unique_ptr<IFileCollectionIterator> ZipFileCollection::Iterator() { 147 return util::make_unique<ZipFileCollectionIterator>(this); 148 } 149 150 ZipFileCollection::~ZipFileCollection() { 151 if (handle_) { 152 CloseArchive(handle_); 153 } 154 } 155 156 } // namespace io 157 } // namespace aapt 158