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
44466b22b76e438b3419cedbe782ab71b8ade18260Christopher Tatestatic inline size_t min_of(size_t a, size_t b) { return (a < b) ? a : b; }
45b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
46b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tateusing namespace android;
47b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
48b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate/*
49b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * Streaming access to compressed asset data in an open fd
50b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate */
51ddb76c4644756b31be948d70aaa8ee541dd94999Kenny RootStreamingZipInflater::StreamingZipInflater(int fd, off64_t compDataStart,
52b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        size_t uncompSize, size_t compSize) {
53b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mFd = fd;
54b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mDataMap = NULL;
55b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInFileStart = compDataStart;
56b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutTotalSize = uncompSize;
57b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInTotalSize = compSize;
58b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
59b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInBufSize = StreamingZipInflater::INPUT_CHUNK_SIZE;
60b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInBuf = new uint8_t[mInBufSize];
61b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
62b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutBufSize = StreamingZipInflater::OUTPUT_CHUNK_SIZE;
63b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutBuf = new uint8_t[mOutBufSize];
64b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
65b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    initInflateState();
66b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
67b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
68b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate/*
69b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * Streaming access to compressed data held in an mmapped region of memory
70b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate */
71b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher TateStreamingZipInflater::StreamingZipInflater(FileMap* dataMap, size_t uncompSize) {
72b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mFd = -1;
73b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mDataMap = dataMap;
74b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutTotalSize = uncompSize;
75b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInTotalSize = dataMap->getDataLength();
76b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
77b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInBuf = (uint8_t*) dataMap->getDataPtr();
78b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInBufSize = mInTotalSize;
79b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
80b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutBufSize = StreamingZipInflater::OUTPUT_CHUNK_SIZE;
81b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutBuf = new uint8_t[mOutBufSize];
82b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
83b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    initInflateState();
84b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
85b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
86b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher TateStreamingZipInflater::~StreamingZipInflater() {
87b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    // tear down the in-flight zip state just in case
88b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    ::inflateEnd(&mInflateState);
89b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
90b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    if (mDataMap == NULL) {
91b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        delete [] mInBuf;
92b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    }
93b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    delete [] mOutBuf;
94b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
95b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
96b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tatevoid StreamingZipInflater::initInflateState() {
9771f2cf116aab893e224056c38ab146bd1538dd3eSteve Block    ALOGV("Initializing inflate state");
98b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
99b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    memset(&mInflateState, 0, sizeof(mInflateState));
100b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.zalloc = Z_NULL;
101b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.zfree = Z_NULL;
102b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.opaque = Z_NULL;
103b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.next_in = (Bytef*)mInBuf;
104b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.next_out = (Bytef*) mOutBuf;
105b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.avail_out = mOutBufSize;
106b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInflateState.data_type = Z_UNKNOWN;
107b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
108b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mOutLastDecoded = mOutDeliverable = mOutCurPosition = 0;
109b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mInNextChunkOffset = 0;
110b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    mStreamNeedsInit = true;
111b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
112b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    if (mDataMap == NULL) {
113b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        ::lseek(mFd, mInFileStart, SEEK_SET);
114b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        mInflateState.avail_in = 0; // set when a chunk is read in
115b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    } else {
116b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        mInflateState.avail_in = mInBufSize;
117b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    }
118b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
119b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
120b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate/*
121b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * Basic approach:
122b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *
123b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * 1. If we have undelivered uncompressed data, send it.  At this point
124b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    either we've satisfied the request, or we've exhausted the available
125b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    output data in mOutBuf.
126b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *
127b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate * 2. While we haven't sent enough data to satisfy the request:
128b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    0. if the request is for more data than exists, bail.
129b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    a. if there is no input data to decode, read some into the input buffer
130b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *       and readjust the z_stream input pointers
131b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    b. point the output to the start of the output buffer and decode what we can
132b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate *    c. deliver whatever output data we can
133b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate */
134b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tatessize_t StreamingZipInflater::read(void* outBuf, size_t count) {
135b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    uint8_t* dest = (uint8_t*) outBuf;
136b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    size_t bytesRead = 0;
137466b22b76e438b3419cedbe782ab71b8ade18260Christopher Tate    size_t toRead = min_of(count, size_t(mOutTotalSize - mOutCurPosition));
138b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    while (toRead > 0) {
139b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        // First, write from whatever we already have decoded and ready to go
140466b22b76e438b3419cedbe782ab71b8ade18260Christopher Tate        size_t deliverable = min_of(toRead, mOutLastDecoded - mOutDeliverable);
141b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        if (deliverable > 0) {
142b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            if (outBuf != NULL) memcpy(dest, mOutBuf + mOutDeliverable, deliverable);
143b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            mOutDeliverable += deliverable;
144b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            mOutCurPosition += deliverable;
145b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            dest += deliverable;
146b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            bytesRead += deliverable;
147b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            toRead -= deliverable;
148b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        }
149b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
150b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        // need more data?  time to decode some.
151b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        if (toRead > 0) {
152b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            // if we don't have any data to decode, read some in.  If we're working
153b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            // from mmapped data this won't happen, because the clipping to total size
154b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            // will prevent reading off the end of the mapped input chunk.
155c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root            if ((mInflateState.avail_in == 0) && (mDataMap == NULL)) {
156b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                int err = readNextChunk();
157b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                if (err < 0) {
1583762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                    ALOGE("Unable to access asset data: %d", err);
159b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    if (!mStreamNeedsInit) {
160b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                        ::inflateEnd(&mInflateState);
161b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                        initInflateState();
162b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    }
163b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    return -1;
164b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                }
165b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            }
166b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            // we know we've drained whatever is in the out buffer now, so just
167b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            // start from scratch there, reading all the input we have at present.
168b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            mInflateState.next_out = (Bytef*) mOutBuf;
169b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            mInflateState.avail_out = mOutBufSize;
170b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
171b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            /*
17271f2cf116aab893e224056c38ab146bd1538dd3eSteve Block            ALOGV("Inflating to outbuf: avail_in=%u avail_out=%u next_in=%p next_out=%p",
173b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    mInflateState.avail_in, mInflateState.avail_out,
174b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    mInflateState.next_in, mInflateState.next_out);
175b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            */
176b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            int result = Z_OK;
177b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            if (mStreamNeedsInit) {
17871f2cf116aab893e224056c38ab146bd1538dd3eSteve Block                ALOGV("Initializing zlib to inflate");
179b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                result = inflateInit2(&mInflateState, -MAX_WBITS);
180b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mStreamNeedsInit = false;
181b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            }
182b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            if (result == Z_OK) result = ::inflate(&mInflateState, Z_SYNC_FLUSH);
183b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            if (result < 0) {
184b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                // Whoops, inflation failed
1853762c311729fe9f3af085c14c5c1fb471d994c03Steve Block                ALOGE("Error inflating asset: %d", result);
186b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                ::inflateEnd(&mInflateState);
187b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                initInflateState();
188b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                return -1;
189b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            } else {
190b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                if (result == Z_STREAM_END) {
191b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    // we know we have to have reached the target size here and will
192b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    // not try to read any further, so just wind things up.
193b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                    ::inflateEnd(&mInflateState);
194b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                }
195b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
196b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                // Note how much data we got, and off we go
197b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mOutDeliverable = 0;
198b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mOutLastDecoded = mOutBufSize - mInflateState.avail_out;
199b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            }
200b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        }
201b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    }
202b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    return bytesRead;
203b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
204b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
205b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tateint StreamingZipInflater::readNextChunk() {
206b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    assert(mDataMap == NULL);
207b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
208b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    if (mInNextChunkOffset < mInTotalSize) {
209466b22b76e438b3419cedbe782ab71b8ade18260Christopher Tate        size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset);
210b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        if (toRead > 0) {
211c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root            ssize_t didRead = TEMP_FAILURE_RETRY(::read(mFd, mInBuf, toRead));
21271f2cf116aab893e224056c38ab146bd1538dd3eSteve Block            //ALOGV("Reading input chunk, size %08x didread %08x", toRead, didRead);
213b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            if (didRead < 0) {
214c6e35cb47a90a43b5a0009f526b695b2b5c87465Kenny Root                ALOGE("Error reading asset data: %s", strerror(errno));
215b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                return didRead;
216b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            } else {
217b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mInNextChunkOffset += didRead;
218b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mInflateState.next_in = (Bytef*) mInBuf;
219b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate                mInflateState.avail_in = didRead;
220b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            }
221b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        }
222b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    }
223b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    return 0;
224b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
225b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate
226b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate// seeking backwards requires uncompressing fom the beginning, so is very
227b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate// expensive.  seeking forwards only requires uncompressing from the current
228b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate// position to the destination.
229ddb76c4644756b31be948d70aaa8ee541dd94999Kenny Rootoff64_t StreamingZipInflater::seekAbsolute(off64_t absoluteInputPosition) {
230b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    if (absoluteInputPosition < mOutCurPosition) {
231b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        // rewind and reprocess the data from the beginning
232b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        if (!mStreamNeedsInit) {
233b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate            ::inflateEnd(&mInflateState);
234b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        }
235b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        initInflateState();
236b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        read(NULL, absoluteInputPosition);
237b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    } else if (absoluteInputPosition > mOutCurPosition) {
238b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate        read(NULL, absoluteInputPosition - mOutCurPosition);
239b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    }
240b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    // else if the target position *is* our current position, do nothing
241b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate    return absoluteInputPosition;
242b100cbf178e91d6652ebbad3ed36684cacb9d10eChristopher Tate}
243