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