1b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate/*
2b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * Copyright (C) 2010 The Android Open Source Project
3b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *
4b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * Licensed under the Apache License, Version 2.0 (the "License");
5b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * you may not use this file except in compliance with the License.
6b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * You may obtain a copy of the License at
7b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *
8b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *      http://www.apache.org/licenses/LICENSE-2.0
9b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *
10b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * Unless required by applicable law or agreed to in writing, software
11b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * distributed under the License is distributed on an "AS IS" BASIS,
12b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * See the License for the specific language governing permissions and
14b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * limitations under the License.
15b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate */
16b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
175fd2169eabd77e6bfafaf456e58051a3bafb2bcaDianne Hackborn//#define LOG_NDEBUG 0
18b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate#define LOG_TAG "szipinf"
19b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate#include <utils/Log.h>
20b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
21b13b9bdad2baf6ad1ec2e56b6b7598fa20f55fc4Mathias Agopian#include <androidfw/StreamingZipInflater.h>
22b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate#include <utils/FileMap.h>
23b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate#include <string.h>
24a4879bad704981da014206380eca93163f4c5a2bKenny Root#include <stddef.h>
25b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate#include <assert.h>
26c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root#include <unistd.h>
27c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root#include <errno.h>
28c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root
29c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root/*
30c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
31c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
32c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root * not already defined, then define it here.
33c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root */
34c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root#ifndef TEMP_FAILURE_RETRY
35c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root/* Used to retry syscalls that can return EINTR. */
36c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root#define TEMP_FAILURE_RETRY(exp) ({         \
37c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root    typeof (exp) _rc;                      \
38c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root    do {                                   \
39c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root        _rc = (exp);                       \
40c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root    } while (_rc == -1 && errno == EINTR); \
41c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root    _rc; })
42c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root#endif
43b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
442204f0bf56af53b588a01701b8cf9cd05b1b3ff9Andreas Gampestatic const bool kIsDebug = false;
452204f0bf56af53b588a01701b8cf9cd05b1b3ff9Andreas Gampe
46466b22b76e438b3419cedbe782ab71b8ade18260Christopher Tatestatic inline size_t min_of(size_t a, size_t b) { return (a < b) ? a : b; }
47b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
48b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tateusing namespace android;
49b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
50b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate/*
51b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * Streaming access to compressed asset data in an open fd
52b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate */
53ddb76c4644756b31be948d70aaa8ee541dd94999Kenny RootStreamingZipInflater::StreamingZipInflater(int fd, off64_t compDataStart,
54b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        size_t uncompSize, size_t compSize) {
55b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mFd = fd;
56b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mDataMap = NULL;
57b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInFileStart = compDataStart;
58b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutTotalSize = uncompSize;
59b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInTotalSize = compSize;
60b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
61b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInBufSize = StreamingZipInflater::INPUT_CHUNK_SIZE;
62b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInBuf = new uint8_t[mInBufSize];
63b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
64b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutBufSize = StreamingZipInflater::OUTPUT_CHUNK_SIZE;
65b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutBuf = new uint8_t[mOutBufSize];
66b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
67b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    initInflateState();
68b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
69b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
70b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate/*
71b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * Streaming access to compressed data held in an mmapped region of memory
72b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate */
73b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher TateStreamingZipInflater::StreamingZipInflater(FileMap* dataMap, size_t uncompSize) {
74b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mFd = -1;
75b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mDataMap = dataMap;
76b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutTotalSize = uncompSize;
77b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInTotalSize = dataMap->getDataLength();
78b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
79b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInBuf = (uint8_t*) dataMap->getDataPtr();
80b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInBufSize = mInTotalSize;
81b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
82b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutBufSize = StreamingZipInflater::OUTPUT_CHUNK_SIZE;
83b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutBuf = new uint8_t[mOutBufSize];
84b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
85b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    initInflateState();
86b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
87b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
88b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher TateStreamingZipInflater::~StreamingZipInflater() {
89b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    // tear down the in-flight zip state just in case
90b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    ::inflateEnd(&mInflateState);
91b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
92b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    if (mDataMap == NULL) {
93b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        delete [] mInBuf;
94b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    }
95b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    delete [] mOutBuf;
96b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
97b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
98b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tatevoid StreamingZipInflater::initInflateState() {
9971f2cf116aab893e224056c38ab146bd1538dd3eSteve Block    ALOGV("Initializing inflate state");
100b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
101b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    memset(&mInflateState, 0, sizeof(mInflateState));
102b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.zalloc = Z_NULL;
103b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.zfree = Z_NULL;
104b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.opaque = Z_NULL;
105b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.next_in = (Bytef*)mInBuf;
106b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.next_out = (Bytef*) mOutBuf;
107b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.avail_out = mOutBufSize;
108b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.data_type = Z_UNKNOWN;
109b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
110b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutLastDecoded = mOutDeliverable = mOutCurPosition = 0;
111b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInNextChunkOffset = 0;
112b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mStreamNeedsInit = true;
113b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
114b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    if (mDataMap == NULL) {
115b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        ::lseek(mFd, mInFileStart, SEEK_SET);
116b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        mInflateState.avail_in = 0; // set when a chunk is read in
117b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    } else {
118b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        mInflateState.avail_in = mInBufSize;
119b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    }
120b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
121b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
122b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate/*
123b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * Basic approach:
124b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *
125b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * 1. If we have undelivered uncompressed data, send it.  At this point
126b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    either we've satisfied the request, or we've exhausted the available
127b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    output data in mOutBuf.
128b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *
129b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * 2. While we haven't sent enough data to satisfy the request:
130b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    0. if the request is for more data than exists, bail.
131b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    a. if there is no input data to decode, read some into the input buffer
132b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *       and readjust the z_stream input pointers
133b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    b. point the output to the start of the output buffer and decode what we can
134b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    c. deliver whatever output data we can
135b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate */
136b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tatessize_t StreamingZipInflater::read(void* outBuf, size_t count) {
137b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    uint8_t* dest = (uint8_t*) outBuf;
138b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    size_t bytesRead = 0;
139466b22b76e438b3419cedbe782ab71b8ade18260Christopher Tate    size_t toRead = min_of(count, size_t(mOutTotalSize - mOutCurPosition));
140b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    while (toRead > 0) {
141b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        // First, write from whatever we already have decoded and ready to go
142466b22b76e438b3419cedbe782ab71b8ade18260Christopher Tate        size_t deliverable = min_of(toRead, mOutLastDecoded - mOutDeliverable);
143b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        if (deliverable > 0) {
144b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            if (outBuf != NULL) memcpy(dest, mOutBuf + mOutDeliverable, deliverable);
145b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            mOutDeliverable += deliverable;
146b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            mOutCurPosition += deliverable;
147b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            dest += deliverable;
148b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            bytesRead += deliverable;
149b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            toRead -= deliverable;
150b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        }
151b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
152b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        // need more data?  time to decode some.
153b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        if (toRead > 0) {
154b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            // if we don't have any data to decode, read some in.  If we're working
155b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            // from mmapped data this won't happen, because the clipping to total size
156b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            // will prevent reading off the end of the mapped input chunk.
157c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root            if ((mInflateState.avail_in == 0) && (mDataMap == NULL)) {
158b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                int err = readNextChunk();
159b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                if (err < 0) {
1603762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                    ALOGE("Unable to access asset data: %d", err);
161b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    if (!mStreamNeedsInit) {
162b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                        ::inflateEnd(&mInflateState);
163b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                        initInflateState();
164b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    }
165b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    return -1;
166b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                }
167b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            }
168b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            // we know we've drained whatever is in the out buffer now, so just
169b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            // start from scratch there, reading all the input we have at present.
170b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            mInflateState.next_out = (Bytef*) mOutBuf;
171b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            mInflateState.avail_out = mOutBufSize;
172b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
173b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            /*
17471f2cf116aab893e224056c38ab146bd1538dd3eSteve Block            ALOGV("Inflating to outbuf: avail_in=%u avail_out=%u next_in=%p next_out=%p",
175b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    mInflateState.avail_in, mInflateState.avail_out,
176b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    mInflateState.next_in, mInflateState.next_out);
177b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            */
178b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            int result = Z_OK;
179b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            if (mStreamNeedsInit) {
18071f2cf116aab893e224056c38ab146bd1538dd3eSteve Block                ALOGV("Initializing zlib to inflate");
181b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                result = inflateInit2(&mInflateState, -MAX_WBITS);
182b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mStreamNeedsInit = false;
183b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            }
184b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            if (result == Z_OK) result = ::inflate(&mInflateState, Z_SYNC_FLUSH);
185b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            if (result < 0) {
186b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                // Whoops, inflation failed
1873762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("Error inflating asset: %d", result);
188b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                ::inflateEnd(&mInflateState);
189b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                initInflateState();
190b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                return -1;
191b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            } else {
192b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                if (result == Z_STREAM_END) {
193b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    // we know we have to have reached the target size here and will
194b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    // not try to read any further, so just wind things up.
195b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    ::inflateEnd(&mInflateState);
196b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                }
197b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
198b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                // Note how much data we got, and off we go
199b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mOutDeliverable = 0;
200b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mOutLastDecoded = mOutBufSize - mInflateState.avail_out;
201b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            }
202b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        }
203b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    }
204b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    return bytesRead;
205b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
206b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
207b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tateint StreamingZipInflater::readNextChunk() {
208b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    assert(mDataMap == NULL);
209b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
210b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    if (mInNextChunkOffset < mInTotalSize) {
211466b22b76e438b3419cedbe782ab71b8ade18260Christopher Tate        size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset);
212b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        if (toRead > 0) {
213c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root            ssize_t didRead = TEMP_FAILURE_RETRY(::read(mFd, mInBuf, toRead));
2142204f0bf56af53b588a01701b8cf9cd05b1b3ff9Andreas Gampe            if (kIsDebug) {
2152204f0bf56af53b588a01701b8cf9cd05b1b3ff9Andreas Gampe                ALOGV("Reading input chunk, size %08zx didread %08zx", toRead, didRead);
2162204f0bf56af53b588a01701b8cf9cd05b1b3ff9Andreas Gampe            }
217b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            if (didRead < 0) {
218c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root                ALOGE("Error reading asset data: %s", strerror(errno));
219b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                return didRead;
220b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            } else {
221b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mInNextChunkOffset += didRead;
222b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mInflateState.next_in = (Bytef*) mInBuf;
223b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mInflateState.avail_in = didRead;
224b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            }
225b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        }
226b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    }
227b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    return 0;
228b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
229b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
230b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate// seeking backwards requires uncompressing fom the beginning, so is very
231b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate// expensive.  seeking forwards only requires uncompressing from the current
232b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate// position to the destination.
233ddb76c4644756b31be948d70aaa8ee541dd94999Kenny Rootoff64_t StreamingZipInflater::seekAbsolute(off64_t absoluteInputPosition) {
234b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    if (absoluteInputPosition < mOutCurPosition) {
235b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        // rewind and reprocess the data from the beginning
236b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        if (!mStreamNeedsInit) {
237b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            ::inflateEnd(&mInflateState);
238b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        }
239b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        initInflateState();
240b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        read(NULL, absoluteInputPosition);
241b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    } else if (absoluteInputPosition > mOutCurPosition) {
242b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        read(NULL, absoluteInputPosition - mOutCurPosition);
243b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    }
244b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    // else if the target position *is* our current position, do nothing
245b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    return absoluteInputPosition;
246b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
247