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 const Source& ZipFile::GetSource() const { return source_; } 61 62 bool ZipFile::WasCompressed() { 63 return zip_entry_.method != kCompressStored; 64 } 65 66 ZipFileCollectionIterator::ZipFileCollectionIterator( 67 ZipFileCollection* collection) 68 : current_(collection->files_.begin()), end_(collection->files_.end()) {} 69 70 bool ZipFileCollectionIterator::HasNext() { return current_ != end_; } 71 72 IFile* ZipFileCollectionIterator::Next() { 73 IFile* result = current_->get(); 74 ++current_; 75 return result; 76 } 77 78 ZipFileCollection::ZipFileCollection() : handle_(nullptr) {} 79 80 std::unique_ptr<ZipFileCollection> ZipFileCollection::Create( 81 const StringPiece& path, std::string* out_error) { 82 constexpr static const int32_t kEmptyArchive = -6; 83 84 std::unique_ptr<ZipFileCollection> collection = 85 std::unique_ptr<ZipFileCollection>(new ZipFileCollection()); 86 87 int32_t result = OpenArchive(path.data(), &collection->handle_); 88 if (result != 0) { 89 // If a zip is empty, result will be an error code. This is fine and we 90 // should 91 // return an empty ZipFileCollection. 92 if (result == kEmptyArchive) { 93 return collection; 94 } 95 96 if (out_error) *out_error = ErrorCodeString(result); 97 return {}; 98 } 99 100 void* cookie = nullptr; 101 result = StartIteration(collection->handle_, &cookie, nullptr, nullptr); 102 if (result != 0) { 103 if (out_error) *out_error = ErrorCodeString(result); 104 return {}; 105 } 106 107 using IterationEnder = std::unique_ptr<void, decltype(EndIteration)*>; 108 IterationEnder iteration_ender(cookie, EndIteration); 109 110 ZipString zip_entry_name; 111 ZipEntry zip_data; 112 while ((result = Next(cookie, &zip_data, &zip_entry_name)) == 0) { 113 std::string zip_entry_path = 114 std::string(reinterpret_cast<const char*>(zip_entry_name.name), 115 zip_entry_name.name_length); 116 std::string nested_path = path.to_string() + "@" + zip_entry_path; 117 std::unique_ptr<IFile> file = 118 util::make_unique<ZipFile>(collection->handle_, zip_data, Source(nested_path)); 119 collection->files_by_name_[zip_entry_path] = file.get(); 120 collection->files_.push_back(std::move(file)); 121 } 122 123 if (result != -1) { 124 if (out_error) *out_error = ErrorCodeString(result); 125 return {}; 126 } 127 return collection; 128 } 129 130 IFile* ZipFileCollection::FindFile(const StringPiece& path) { 131 auto iter = files_by_name_.find(path.to_string()); 132 if (iter != files_by_name_.end()) { 133 return iter->second; 134 } 135 return nullptr; 136 } 137 138 std::unique_ptr<IFileCollectionIterator> ZipFileCollection::Iterator() { 139 return util::make_unique<ZipFileCollectionIterator>(this); 140 } 141 142 ZipFileCollection::~ZipFileCollection() { 143 if (handle_) { 144 CloseArchive(handle_); 145 } 146 } 147 148 } // namespace io 149 } // namespace aapt 150