1e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris/*
2e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris * Copyright (C) 2015 The Android Open Source Project
3e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris *
4e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris * Licensed under the Apache License, Version 2.0 (the "License");
5e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris * you may not use this file except in compliance with the License.
6e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris * You may obtain a copy of the License at
7e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris *
8e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris *    http://www.apache.org/licenses/LICENSE-2.0
9e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris *
10e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris * Unless required by applicable law or agreed to in writing, software
11e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris * distributed under the License is distributed on an "AS IS" BASIS,
12e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris * See the License for the specific language governing permissions and
14e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris * limitations under the License.
15e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris */
16e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
17ff2dcd9af994a23ed483939a416b48bdc10eefd5Mark Salyzyn#define LOG_TAG "ZIPARCHIVE"
18ff2dcd9af994a23ed483939a416b48bdc10eefd5Mark Salyzyn
19e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris// Read-only stream access to Zip Archive entries.
20e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include <errno.h>
21e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include <inttypes.h>
22e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include <string.h>
23e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include <sys/types.h>
24e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include <unistd.h>
25e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
26e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include <memory>
27e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include <vector>
28e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
29e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include <android-base/file.h>
3030f991f251940be3ed11566fb71139852286f68aMark Salyzyn#include <log/log.h>
3130f991f251940be3ed11566fb71139852286f68aMark Salyzyn
32e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include <ziparchive/zip_archive.h>
33e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include <ziparchive/zip_archive_stream_entry.h>
34e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include <zlib.h>
35e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
36e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#include "zip_archive_private.h"
37e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
38e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisstatic constexpr size_t kBufSize = 65535;
39e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
40e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisbool ZipArchiveStreamEntry::Init(const ZipEntry& entry) {
41e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
42e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  off64_t data_offset = entry.offset;
4318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu  if (!archive->mapped_zip.SeekToOffset(data_offset)) {
44e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    ALOGW("lseek to data at %" PRId64 " failed: %s", data_offset, strerror(errno));
45e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    return false;
46e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
47e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  crc32_ = entry.crc32;
48e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return true;
49e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
50e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
51e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisclass ZipArchiveStreamEntryUncompressed : public ZipArchiveStreamEntry {
52e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris public:
533a114e0a81a482dbf48e8ff6b6310edd7c215fcfChih-Hung Hsieh  explicit ZipArchiveStreamEntryUncompressed(ZipArchiveHandle handle)
543a114e0a81a482dbf48e8ff6b6310edd7c215fcfChih-Hung Hsieh      : ZipArchiveStreamEntry(handle) {}
55e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  virtual ~ZipArchiveStreamEntryUncompressed() {}
56e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
57e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  const std::vector<uint8_t>* Read() override;
58e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
59e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  bool Verify() override;
60e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
61e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris protected:
62e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  bool Init(const ZipEntry& entry) override;
63e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
64e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  uint32_t length_;
65e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
66e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris private:
67e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  std::vector<uint8_t> data_;
68e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  uint32_t computed_crc32_;
69e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris};
70e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
71e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisbool ZipArchiveStreamEntryUncompressed::Init(const ZipEntry& entry) {
72e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (!ZipArchiveStreamEntry::Init(entry)) {
73e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    return false;
74e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
75e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
76e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  length_ = entry.uncompressed_length;
77e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
78e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  data_.resize(kBufSize);
79e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  computed_crc32_ = 0;
80e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
81e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return true;
82e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
83e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
84e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisconst std::vector<uint8_t>* ZipArchiveStreamEntryUncompressed::Read() {
85e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (length_ == 0) {
86e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    return nullptr;
87e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
88e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
89e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  size_t bytes = (length_ > data_.size()) ? data_.size() : length_;
90e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
91e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  errno = 0;
9218c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu  if (!archive->mapped_zip.ReadData(data_.data(), bytes)) {
93e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    if (errno != 0) {
94e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      ALOGE("Error reading from archive fd: %s", strerror(errno));
95e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    } else {
96e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      ALOGE("Short read of zip file, possibly corrupted zip?");
97e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    }
98e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    length_ = 0;
99e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    return nullptr;
100e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
101e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
102e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (bytes < data_.size()) {
103e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    data_.resize(bytes);
104e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
105e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  computed_crc32_ = crc32(computed_crc32_, data_.data(), data_.size());
106e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  length_ -= bytes;
107e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return &data_;
108e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
109e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
110e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisbool ZipArchiveStreamEntryUncompressed::Verify() {
111e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return length_ == 0 && crc32_ == computed_crc32_;
112e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
113e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
114e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisclass ZipArchiveStreamEntryCompressed : public ZipArchiveStreamEntry {
115e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris public:
1163a114e0a81a482dbf48e8ff6b6310edd7c215fcfChih-Hung Hsieh  explicit ZipArchiveStreamEntryCompressed(ZipArchiveHandle handle)
1173a114e0a81a482dbf48e8ff6b6310edd7c215fcfChih-Hung Hsieh      : ZipArchiveStreamEntry(handle) {}
118e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  virtual ~ZipArchiveStreamEntryCompressed();
119e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
120e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  const std::vector<uint8_t>* Read() override;
121e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
122e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  bool Verify() override;
123e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
124e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris protected:
125e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  bool Init(const ZipEntry& entry) override;
126e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
127e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris private:
128e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  bool z_stream_init_ = false;
129e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  z_stream z_stream_;
130e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  std::vector<uint8_t> in_;
131e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  std::vector<uint8_t> out_;
132e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  uint32_t uncompressed_length_;
133e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  uint32_t compressed_length_;
134e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  uint32_t computed_crc32_;
135e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris};
136e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
137e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris// This method is using libz macros with old-style-casts
138e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#pragma GCC diagnostic push
139e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#pragma GCC diagnostic ignored "-Wold-style-cast"
140e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisstatic inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
141e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return inflateInit2(stream, window_bits);
142e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
143e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris#pragma GCC diagnostic pop
144e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
145e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisbool ZipArchiveStreamEntryCompressed::Init(const ZipEntry& entry) {
146e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (!ZipArchiveStreamEntry::Init(entry)) {
147e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    return false;
148e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
149e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
150e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  // Initialize the zlib stream struct.
151e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  memset(&z_stream_, 0, sizeof(z_stream_));
152e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  z_stream_.zalloc = Z_NULL;
153e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  z_stream_.zfree = Z_NULL;
154e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  z_stream_.opaque = Z_NULL;
155e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  z_stream_.next_in = nullptr;
156e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  z_stream_.avail_in = 0;
157e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  z_stream_.avail_out = 0;
158e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  z_stream_.data_type = Z_UNKNOWN;
159e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
160e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  // Use the undocumented "negative window bits" feature to tell zlib
161e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  // that there's no zlib header waiting for it.
162e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  int zerr = zlib_inflateInit2(&z_stream_, -MAX_WBITS);
163e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (zerr != Z_OK) {
164e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    if (zerr == Z_VERSION_ERROR) {
165e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      ALOGE("Installed zlib is not compatible with linked version (%s)",
166e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris        ZLIB_VERSION);
167e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    } else {
168e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      ALOGE("Call to inflateInit2 failed (zerr=%d)", zerr);
169e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    }
170e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
171e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    return false;
172e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
173e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
174e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  z_stream_init_ = true;
175e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
176e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  uncompressed_length_ = entry.uncompressed_length;
177e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  compressed_length_ = entry.compressed_length;
178e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
179e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  out_.resize(kBufSize);
180e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  in_.resize(kBufSize);
181e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
182e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  computed_crc32_ = 0;
183e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
184e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return true;
185e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
186e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
187e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher FerrisZipArchiveStreamEntryCompressed::~ZipArchiveStreamEntryCompressed() {
188e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (z_stream_init_) {
189e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    inflateEnd(&z_stream_);
190e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    z_stream_init_ = false;
191e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
192e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
193e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
194e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisbool ZipArchiveStreamEntryCompressed::Verify() {
195e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return z_stream_init_ && uncompressed_length_ == 0 && compressed_length_ == 0 &&
196e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      crc32_ == computed_crc32_;
197e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
198e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
199e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisconst std::vector<uint8_t>* ZipArchiveStreamEntryCompressed::Read() {
200e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (z_stream_.avail_out == 0) {
201e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    z_stream_.next_out = out_.data();
202e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    z_stream_.avail_out = out_.size();;
203e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
204e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
205e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  while (true) {
206e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    if (z_stream_.avail_in == 0) {
207e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      if (compressed_length_ == 0) {
208e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris        return nullptr;
209e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      }
210e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      size_t bytes = (compressed_length_ > in_.size()) ? in_.size() : compressed_length_;
211e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle_);
212e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      errno = 0;
21318c25920c285bf2894b5a05868b79f1202c3a264Tianjie Xu      if (!archive->mapped_zip.ReadData(in_.data(), bytes)) {
214e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris        if (errno != 0) {
215e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris          ALOGE("Error reading from archive fd: %s", strerror(errno));
216e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris        } else {
217e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris          ALOGE("Short read of zip file, possibly corrupted zip?");
218e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris        }
219e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris        return nullptr;
220e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      }
221e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
222e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      compressed_length_ -= bytes;
223e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      z_stream_.next_in = in_.data();
224e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      z_stream_.avail_in = bytes;
225e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    }
226e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
227e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    int zerr = inflate(&z_stream_, Z_NO_FLUSH);
228e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    if (zerr != Z_OK && zerr != Z_STREAM_END) {
229e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      ALOGE("inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
230e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris          zerr, z_stream_.next_in, z_stream_.avail_in,
231e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris          z_stream_.next_out, z_stream_.avail_out);
232e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      return nullptr;
233e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    }
234e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
235e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    if (z_stream_.avail_out == 0) {
236e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      uncompressed_length_ -= out_.size();
237e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      computed_crc32_ = crc32(computed_crc32_, out_.data(), out_.size());
238e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      return &out_;
239e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    }
240e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    if (zerr == Z_STREAM_END) {
241e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      if (z_stream_.avail_out != 0) {
242e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris        // Resize the vector down to the actual size of the data.
243e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris        out_.resize(out_.size() - z_stream_.avail_out);
244e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris        computed_crc32_ = crc32(computed_crc32_, out_.data(), out_.size());
245e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris        uncompressed_length_ -= out_.size();
246e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris        return &out_;
247e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      }
248e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      return nullptr;
249e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    }
250e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
251e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return nullptr;
252e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
253e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
254e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisclass ZipArchiveStreamEntryRawCompressed : public ZipArchiveStreamEntryUncompressed {
255e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris public:
2563a114e0a81a482dbf48e8ff6b6310edd7c215fcfChih-Hung Hsieh  explicit ZipArchiveStreamEntryRawCompressed(ZipArchiveHandle handle)
257e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris      : ZipArchiveStreamEntryUncompressed(handle) {}
258e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  virtual ~ZipArchiveStreamEntryRawCompressed() {}
259e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
260e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  bool Verify() override;
261e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
262e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris protected:
263e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  bool Init(const ZipEntry& entry) override;
264e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris};
265e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
266e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisbool ZipArchiveStreamEntryRawCompressed::Init(const ZipEntry& entry) {
267e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (!ZipArchiveStreamEntryUncompressed::Init(entry)) {
268e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    return false;
269e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
270e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  length_ = entry.compressed_length;
271e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
272e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return true;
273e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
274e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
275e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferrisbool ZipArchiveStreamEntryRawCompressed::Verify() {
276e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return length_ == 0;
277e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
278e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
279e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher FerrisZipArchiveStreamEntry* ZipArchiveStreamEntry::Create(
280e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    ZipArchiveHandle handle, const ZipEntry& entry) {
281e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  ZipArchiveStreamEntry* stream = nullptr;
282e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (entry.method != kCompressStored) {
283e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    stream = new ZipArchiveStreamEntryCompressed(handle);
284e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  } else {
285e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    stream = new ZipArchiveStreamEntryUncompressed(handle);
286e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
287e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (stream && !stream->Init(entry)) {
288e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    delete stream;
289e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    stream = nullptr;
290e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
291e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
292e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return stream;
293e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
294e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris
295e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher FerrisZipArchiveStreamEntry* ZipArchiveStreamEntry::CreateRaw(
296e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    ZipArchiveHandle handle, const ZipEntry& entry) {
297e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  ZipArchiveStreamEntry* stream = nullptr;
298e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (entry.method == kCompressStored) {
299e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    // Not compressed, don't need to do anything special.
300e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    stream = new ZipArchiveStreamEntryUncompressed(handle);
301e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  } else {
302e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    stream = new ZipArchiveStreamEntryRawCompressed(handle);
303e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
304e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  if (stream && !stream->Init(entry)) {
305e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    delete stream;
306e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris    stream = nullptr;
307e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  }
308e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris  return stream;
309e6884ce56f07933d7292eb0ada1ff752f9c69e7aChristopher Ferris}
310