1a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski/* 2a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * Copyright (C) 2015 The Android Open Source Project 3a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * 4a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 5a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * you may not use this file except in compliance with the License. 6a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * You may obtain a copy of the License at 7a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * 8a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 9a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * 10a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * Unless required by applicable law or agreed to in writing, software 11a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 12a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * See the License for the specific language governing permissions and 14a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski * limitations under the License. 15a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski */ 16a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 17a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski#include "Source.h" 18a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski#include "io/ZipArchive.h" 19a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski#include "util/Util.h" 20a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 21a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski#include <utils/FileMap.h> 22a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski#include <ziparchive/zip_archive.h> 23a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 24a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinskinamespace aapt { 25a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinskinamespace io { 26a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 27a6fe345be955368a13aea76aefb4db821aad11dfAdam LesinskiZipFile::ZipFile(ZipArchiveHandle handle, const ZipEntry& entry, const Source& source) : 28a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski mZipHandle(handle), mZipEntry(entry), mSource(source) { 29a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 30a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 31a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinskistd::unique_ptr<IData> ZipFile::openAsData() { 32a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (mZipEntry.method == kCompressStored) { 33a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski int fd = GetFileDescriptor(mZipHandle); 34a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 35a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski android::FileMap fileMap; 36a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski bool result = fileMap.create(nullptr, fd, mZipEntry.offset, 37a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski mZipEntry.uncompressed_length, true); 38a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (!result) { 39a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return {}; 40a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } 41a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return util::make_unique<MmappedData>(std::move(fileMap)); 42a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 43a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } else { 44a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski std::unique_ptr<uint8_t[]> data = std::unique_ptr<uint8_t[]>( 45a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski new uint8_t[mZipEntry.uncompressed_length]); 46a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski int32_t result = ExtractToMemory(mZipHandle, &mZipEntry, data.get(), 47a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski static_cast<uint32_t>(mZipEntry.uncompressed_length)); 48a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (result != 0) { 49a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return {}; 50a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } 51a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return util::make_unique<MallocData>(std::move(data), mZipEntry.uncompressed_length); 52a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } 53a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 54a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 55a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinskiconst Source& ZipFile::getSource() const { 56a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return mSource; 57a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 58a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 59a6fe345be955368a13aea76aefb4db821aad11dfAdam LesinskiZipFileCollectionIterator::ZipFileCollectionIterator(ZipFileCollection* collection) : 60a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski mCurrent(collection->mFiles.begin()), mEnd(collection->mFiles.end()) { 61a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 62a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 63a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinskibool ZipFileCollectionIterator::hasNext() { 64a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return mCurrent != mEnd; 65a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 66a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 67a6fe345be955368a13aea76aefb4db821aad11dfAdam LesinskiIFile* ZipFileCollectionIterator::next() { 68a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski IFile* result = mCurrent->second.get(); 69a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski ++mCurrent; 70a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return result; 71a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 72a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 73a6fe345be955368a13aea76aefb4db821aad11dfAdam LesinskiZipFileCollection::ZipFileCollection() : mHandle(nullptr) { 74a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 75a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 76a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinskistd::unique_ptr<ZipFileCollection> ZipFileCollection::create(const StringPiece& path, 77a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski std::string* outError) { 78c446a733b82872ce25dcba2c4185f924aa766349Adam Lesinski constexpr static const int32_t kEmptyArchive = -6; 79c446a733b82872ce25dcba2c4185f924aa766349Adam Lesinski 80a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski std::unique_ptr<ZipFileCollection> collection = std::unique_ptr<ZipFileCollection>( 81a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski new ZipFileCollection()); 82a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 83a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski int32_t result = OpenArchive(path.data(), &collection->mHandle); 84a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (result != 0) { 85c446a733b82872ce25dcba2c4185f924aa766349Adam Lesinski // If a zip is empty, result will be an error code. This is fine and we should 86c446a733b82872ce25dcba2c4185f924aa766349Adam Lesinski // return an empty ZipFileCollection. 87c446a733b82872ce25dcba2c4185f924aa766349Adam Lesinski if (result == kEmptyArchive) { 88c446a733b82872ce25dcba2c4185f924aa766349Adam Lesinski return collection; 89c446a733b82872ce25dcba2c4185f924aa766349Adam Lesinski } 90c446a733b82872ce25dcba2c4185f924aa766349Adam Lesinski 91a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (outError) *outError = ErrorCodeString(result); 92a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return {}; 93a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } 94a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 95a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski void* cookie = nullptr; 9664587af8179affd38ee26543b748f2d63b7f67bbAdam Lesinski result = StartIteration(collection->mHandle, &cookie, nullptr, nullptr); 97a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (result != 0) { 98a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (outError) *outError = ErrorCodeString(result); 99a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return {}; 100a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } 101a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 102a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski using IterationEnder = std::unique_ptr<void, decltype(EndIteration)*>; 103a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski IterationEnder iterationEnder(cookie, EndIteration); 104a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 105a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski ZipString zipEntryName; 106a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski ZipEntry zipData; 107a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski while ((result = Next(cookie, &zipData, &zipEntryName)) == 0) { 108a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski std::string zipEntryPath = std::string(reinterpret_cast<const char*>(zipEntryName.name), 109a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski zipEntryName.name_length); 110a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski std::string nestedPath = path.toString() + "@" + zipEntryPath; 111a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski collection->mFiles[zipEntryPath] = util::make_unique<ZipFile>(collection->mHandle, 112a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski zipData, 113a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski Source(nestedPath)); 114a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } 115a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 116a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (result != -1) { 117a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (outError) *outError = ErrorCodeString(result); 118a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return {}; 119a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } 120a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return collection; 121a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 122a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 123a6fe345be955368a13aea76aefb4db821aad11dfAdam LesinskiIFile* ZipFileCollection::findFile(const StringPiece& path) { 124a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski auto iter = mFiles.find(path.toString()); 125a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (iter != mFiles.end()) { 126a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return iter->second.get(); 127a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } 128a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return nullptr; 129a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 130a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 131a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinskistd::unique_ptr<IFileCollectionIterator> ZipFileCollection::iterator() { 132a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski return util::make_unique<ZipFileCollectionIterator>(this); 133a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 134a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 135a6fe345be955368a13aea76aefb4db821aad11dfAdam LesinskiZipFileCollection::~ZipFileCollection() { 136a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski if (mHandle) { 137a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski CloseArchive(mHandle); 138a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski } 139a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} 140a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski 141a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} // namespace io 142a6fe345be955368a13aea76aefb4db821aad11dfAdam Lesinski} // namespace aapt 143