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