116c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Copyright (C) 2010 The Android Open Source Project
316c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Licensed under the Apache License, Version 2.0 (the "License");
516c4d154dca43c662571129af31b27433b919a32Adam Lesinski * you may not use this file except in compliance with the License.
616c4d154dca43c662571129af31b27433b919a32Adam Lesinski * You may obtain a copy of the License at
716c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
816c4d154dca43c662571129af31b27433b919a32Adam Lesinski *      http://www.apache.org/licenses/LICENSE-2.0
916c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
1016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Unless required by applicable law or agreed to in writing, software
1116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * distributed under the License is distributed on an "AS IS" BASIS,
1216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1316c4d154dca43c662571129af31b27433b919a32Adam Lesinski * See the License for the specific language governing permissions and
1416c4d154dca43c662571129af31b27433b919a32Adam Lesinski * limitations under the License.
1516c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
1616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
1716c4d154dca43c662571129af31b27433b919a32Adam Lesinski//#define LOG_NDEBUG 0
1816c4d154dca43c662571129af31b27433b919a32Adam Lesinski#define LOG_TAG "szipinf"
1916c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <utils/Log.h>
2016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
2116c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <androidfw/StreamingZipInflater.h>
2216c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <utils/FileMap.h>
2316c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <string.h>
2416c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <stddef.h>
2516c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <assert.h>
2616c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <unistd.h>
2716c4d154dca43c662571129af31b27433b919a32Adam Lesinski#include <errno.h>
2816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
2916c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
3016c4d154dca43c662571129af31b27433b919a32Adam Lesinski * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
3116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
3216c4d154dca43c662571129af31b27433b919a32Adam Lesinski * not already defined, then define it here.
3316c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
3416c4d154dca43c662571129af31b27433b919a32Adam Lesinski#ifndef TEMP_FAILURE_RETRY
3516c4d154dca43c662571129af31b27433b919a32Adam Lesinski/* Used to retry syscalls that can return EINTR. */
3616c4d154dca43c662571129af31b27433b919a32Adam Lesinski#define TEMP_FAILURE_RETRY(exp) ({         \
3716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    typeof (exp) _rc;                      \
3816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    do {                                   \
3916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        _rc = (exp);                       \
4016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    } while (_rc == -1 && errno == EINTR); \
4116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    _rc; })
4216c4d154dca43c662571129af31b27433b919a32Adam Lesinski#endif
4316c4d154dca43c662571129af31b27433b919a32Adam Lesinski
4416c4d154dca43c662571129af31b27433b919a32Adam Lesinskistatic inline size_t min_of(size_t a, size_t b) { return (a < b) ? a : b; }
4516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
4616c4d154dca43c662571129af31b27433b919a32Adam Lesinskiusing namespace android;
4716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
4816c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
4916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Streaming access to compressed asset data in an open fd
5016c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
5116c4d154dca43c662571129af31b27433b919a32Adam LesinskiStreamingZipInflater::StreamingZipInflater(int fd, off64_t compDataStart,
5216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        size_t uncompSize, size_t compSize) {
5316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mFd = fd;
5416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mDataMap = NULL;
5516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInFileStart = compDataStart;
5616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mOutTotalSize = uncompSize;
5716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInTotalSize = compSize;
5816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
5916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInBufSize = StreamingZipInflater::INPUT_CHUNK_SIZE;
6016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInBuf = new uint8_t[mInBufSize];
6116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
6216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mOutBufSize = StreamingZipInflater::OUTPUT_CHUNK_SIZE;
6316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mOutBuf = new uint8_t[mOutBufSize];
6416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
6516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    initInflateState();
6616c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
6716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
6816c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
6916c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Streaming access to compressed data held in an mmapped region of memory
7016c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
7116c4d154dca43c662571129af31b27433b919a32Adam LesinskiStreamingZipInflater::StreamingZipInflater(FileMap* dataMap, size_t uncompSize) {
7216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mFd = -1;
7316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mDataMap = dataMap;
7416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mOutTotalSize = uncompSize;
7516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInTotalSize = dataMap->getDataLength();
7616c4d154dca43c662571129af31b27433b919a32Adam Lesinski
7716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInBuf = (uint8_t*) dataMap->getDataPtr();
7816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInBufSize = mInTotalSize;
7916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
8016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mOutBufSize = StreamingZipInflater::OUTPUT_CHUNK_SIZE;
8116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mOutBuf = new uint8_t[mOutBufSize];
8216c4d154dca43c662571129af31b27433b919a32Adam Lesinski
8316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    initInflateState();
8416c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
8516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
8616c4d154dca43c662571129af31b27433b919a32Adam LesinskiStreamingZipInflater::~StreamingZipInflater() {
8716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // tear down the in-flight zip state just in case
8816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ::inflateEnd(&mInflateState);
8916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
9016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mDataMap == NULL) {
9116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        delete [] mInBuf;
9216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
9316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    delete [] mOutBuf;
9416c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
9516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
9616c4d154dca43c662571129af31b27433b919a32Adam Lesinskivoid StreamingZipInflater::initInflateState() {
9716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    ALOGV("Initializing inflate state");
9816c4d154dca43c662571129af31b27433b919a32Adam Lesinski
9916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    memset(&mInflateState, 0, sizeof(mInflateState));
10016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInflateState.zalloc = Z_NULL;
10116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInflateState.zfree = Z_NULL;
10216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInflateState.opaque = Z_NULL;
10316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInflateState.next_in = (Bytef*)mInBuf;
10416c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInflateState.next_out = (Bytef*) mOutBuf;
10516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInflateState.avail_out = mOutBufSize;
10616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInflateState.data_type = Z_UNKNOWN;
10716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
10816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mOutLastDecoded = mOutDeliverable = mOutCurPosition = 0;
10916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mInNextChunkOffset = 0;
11016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    mStreamNeedsInit = true;
11116c4d154dca43c662571129af31b27433b919a32Adam Lesinski
11216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mDataMap == NULL) {
11316c4d154dca43c662571129af31b27433b919a32Adam Lesinski        ::lseek(mFd, mInFileStart, SEEK_SET);
11416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        mInflateState.avail_in = 0; // set when a chunk is read in
11516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    } else {
11616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        mInflateState.avail_in = mInBufSize;
11716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
11816c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
11916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
12016c4d154dca43c662571129af31b27433b919a32Adam Lesinski/*
12116c4d154dca43c662571129af31b27433b919a32Adam Lesinski * Basic approach:
12216c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
12316c4d154dca43c662571129af31b27433b919a32Adam Lesinski * 1. If we have undelivered uncompressed data, send it.  At this point
12416c4d154dca43c662571129af31b27433b919a32Adam Lesinski *    either we've satisfied the request, or we've exhausted the available
12516c4d154dca43c662571129af31b27433b919a32Adam Lesinski *    output data in mOutBuf.
12616c4d154dca43c662571129af31b27433b919a32Adam Lesinski *
12716c4d154dca43c662571129af31b27433b919a32Adam Lesinski * 2. While we haven't sent enough data to satisfy the request:
12816c4d154dca43c662571129af31b27433b919a32Adam Lesinski *    0. if the request is for more data than exists, bail.
12916c4d154dca43c662571129af31b27433b919a32Adam Lesinski *    a. if there is no input data to decode, read some into the input buffer
13016c4d154dca43c662571129af31b27433b919a32Adam Lesinski *       and readjust the z_stream input pointers
13116c4d154dca43c662571129af31b27433b919a32Adam Lesinski *    b. point the output to the start of the output buffer and decode what we can
13216c4d154dca43c662571129af31b27433b919a32Adam Lesinski *    c. deliver whatever output data we can
13316c4d154dca43c662571129af31b27433b919a32Adam Lesinski */
13416c4d154dca43c662571129af31b27433b919a32Adam Lesinskissize_t StreamingZipInflater::read(void* outBuf, size_t count) {
13516c4d154dca43c662571129af31b27433b919a32Adam Lesinski    uint8_t* dest = (uint8_t*) outBuf;
13616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    size_t bytesRead = 0;
13716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    size_t toRead = min_of(count, size_t(mOutTotalSize - mOutCurPosition));
13816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    while (toRead > 0) {
13916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        // First, write from whatever we already have decoded and ready to go
14016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        size_t deliverable = min_of(toRead, mOutLastDecoded - mOutDeliverable);
14116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (deliverable > 0) {
14216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (outBuf != NULL) memcpy(dest, mOutBuf + mOutDeliverable, deliverable);
14316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            mOutDeliverable += deliverable;
14416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            mOutCurPosition += deliverable;
14516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            dest += deliverable;
14616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            bytesRead += deliverable;
14716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            toRead -= deliverable;
14816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
14916c4d154dca43c662571129af31b27433b919a32Adam Lesinski
15016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        // need more data?  time to decode some.
15116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (toRead > 0) {
15216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            // if we don't have any data to decode, read some in.  If we're working
15316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            // from mmapped data this won't happen, because the clipping to total size
15416c4d154dca43c662571129af31b27433b919a32Adam Lesinski            // will prevent reading off the end of the mapped input chunk.
15516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if ((mInflateState.avail_in == 0) && (mDataMap == NULL)) {
15616c4d154dca43c662571129af31b27433b919a32Adam Lesinski                int err = readNextChunk();
15716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                if (err < 0) {
15816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    ALOGE("Unable to access asset data: %d", err);
15916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    if (!mStreamNeedsInit) {
16016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                        ::inflateEnd(&mInflateState);
16116c4d154dca43c662571129af31b27433b919a32Adam Lesinski                        initInflateState();
16216c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    }
16316c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    return -1;
16416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                }
16516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
16616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            // we know we've drained whatever is in the out buffer now, so just
16716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            // start from scratch there, reading all the input we have at present.
16816c4d154dca43c662571129af31b27433b919a32Adam Lesinski            mInflateState.next_out = (Bytef*) mOutBuf;
16916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            mInflateState.avail_out = mOutBufSize;
17016c4d154dca43c662571129af31b27433b919a32Adam Lesinski
17116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            /*
17216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ALOGV("Inflating to outbuf: avail_in=%u avail_out=%u next_in=%p next_out=%p",
17316c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    mInflateState.avail_in, mInflateState.avail_out,
17416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    mInflateState.next_in, mInflateState.next_out);
17516c4d154dca43c662571129af31b27433b919a32Adam Lesinski            */
17616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            int result = Z_OK;
17716c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (mStreamNeedsInit) {
17816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                ALOGV("Initializing zlib to inflate");
17916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                result = inflateInit2(&mInflateState, -MAX_WBITS);
18016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                mStreamNeedsInit = false;
18116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
18216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (result == Z_OK) result = ::inflate(&mInflateState, Z_SYNC_FLUSH);
18316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (result < 0) {
18416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                // Whoops, inflation failed
18516c4d154dca43c662571129af31b27433b919a32Adam Lesinski                ALOGE("Error inflating asset: %d", result);
18616c4d154dca43c662571129af31b27433b919a32Adam Lesinski                ::inflateEnd(&mInflateState);
18716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                initInflateState();
18816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                return -1;
18916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            } else {
19016c4d154dca43c662571129af31b27433b919a32Adam Lesinski                if (result == Z_STREAM_END) {
19116c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    // we know we have to have reached the target size here and will
19216c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    // not try to read any further, so just wind things up.
19316c4d154dca43c662571129af31b27433b919a32Adam Lesinski                    ::inflateEnd(&mInflateState);
19416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                }
19516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
19616c4d154dca43c662571129af31b27433b919a32Adam Lesinski                // Note how much data we got, and off we go
19716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                mOutDeliverable = 0;
19816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                mOutLastDecoded = mOutBufSize - mInflateState.avail_out;
19916c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
20016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
20116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
20216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return bytesRead;
20316c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
20416c4d154dca43c662571129af31b27433b919a32Adam Lesinski
20516c4d154dca43c662571129af31b27433b919a32Adam Lesinskiint StreamingZipInflater::readNextChunk() {
20616c4d154dca43c662571129af31b27433b919a32Adam Lesinski    assert(mDataMap == NULL);
20716c4d154dca43c662571129af31b27433b919a32Adam Lesinski
20816c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (mInNextChunkOffset < mInTotalSize) {
20916c4d154dca43c662571129af31b27433b919a32Adam Lesinski        size_t toRead = min_of(mInBufSize, mInTotalSize - mInNextChunkOffset);
21016c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (toRead > 0) {
21116c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ssize_t didRead = TEMP_FAILURE_RETRY(::read(mFd, mInBuf, toRead));
21216c4d154dca43c662571129af31b27433b919a32Adam Lesinski            //ALOGV("Reading input chunk, size %08x didread %08x", toRead, didRead);
21316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            if (didRead < 0) {
21416c4d154dca43c662571129af31b27433b919a32Adam Lesinski                ALOGE("Error reading asset data: %s", strerror(errno));
21516c4d154dca43c662571129af31b27433b919a32Adam Lesinski                return didRead;
21616c4d154dca43c662571129af31b27433b919a32Adam Lesinski            } else {
21716c4d154dca43c662571129af31b27433b919a32Adam Lesinski                mInNextChunkOffset += didRead;
21816c4d154dca43c662571129af31b27433b919a32Adam Lesinski                mInflateState.next_in = (Bytef*) mInBuf;
21916c4d154dca43c662571129af31b27433b919a32Adam Lesinski                mInflateState.avail_in = didRead;
22016c4d154dca43c662571129af31b27433b919a32Adam Lesinski            }
22116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
22216c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
22316c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return 0;
22416c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
22516c4d154dca43c662571129af31b27433b919a32Adam Lesinski
22616c4d154dca43c662571129af31b27433b919a32Adam Lesinski// seeking backwards requires uncompressing fom the beginning, so is very
22716c4d154dca43c662571129af31b27433b919a32Adam Lesinski// expensive.  seeking forwards only requires uncompressing from the current
22816c4d154dca43c662571129af31b27433b919a32Adam Lesinski// position to the destination.
22916c4d154dca43c662571129af31b27433b919a32Adam Lesinskioff64_t StreamingZipInflater::seekAbsolute(off64_t absoluteInputPosition) {
23016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    if (absoluteInputPosition < mOutCurPosition) {
23116c4d154dca43c662571129af31b27433b919a32Adam Lesinski        // rewind and reprocess the data from the beginning
23216c4d154dca43c662571129af31b27433b919a32Adam Lesinski        if (!mStreamNeedsInit) {
23316c4d154dca43c662571129af31b27433b919a32Adam Lesinski            ::inflateEnd(&mInflateState);
23416c4d154dca43c662571129af31b27433b919a32Adam Lesinski        }
23516c4d154dca43c662571129af31b27433b919a32Adam Lesinski        initInflateState();
23616c4d154dca43c662571129af31b27433b919a32Adam Lesinski        read(NULL, absoluteInputPosition);
23716c4d154dca43c662571129af31b27433b919a32Adam Lesinski    } else if (absoluteInputPosition > mOutCurPosition) {
23816c4d154dca43c662571129af31b27433b919a32Adam Lesinski        read(NULL, absoluteInputPosition - mOutCurPosition);
23916c4d154dca43c662571129af31b27433b919a32Adam Lesinski    }
24016c4d154dca43c662571129af31b27433b919a32Adam Lesinski    // else if the target position *is* our current position, do nothing
24116c4d154dca43c662571129af31b27433b919a32Adam Lesinski    return absoluteInputPosition;
24216c4d154dca43c662571129af31b27433b919a32Adam Lesinski}
243