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