OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / libs / utils / ZipUtils.cpp
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 //
18 // Misc zip/gzip utility functions.
19 //
20
21 #define LOG_TAG "ziputil"
22
23 #include <utils/ZipUtils.h>
24 #include <utils/ZipFileRO.h>
25 #include <utils/Log.h>
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30
31 #include <zlib.h>
32
33 using namespace android;
34
35 /*
36  * Utility function that expands zip/gzip "deflate" compressed data
37  * into a buffer.
38  *
39  * "fd" is an open file positioned at the start of the "deflate" data
40  * "buf" must hold at least "uncompressedLen" bytes.
41  */
42 /*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
43     long uncompressedLen, long compressedLen)
44 {
45     bool result = false;
46         const unsigned long kReadBufSize = 32768;
47         unsigned char* readBuf = NULL;
48     z_stream zstream;
49     int zerr;
50     unsigned long compRemaining;
51
52     assert(uncompressedLen >= 0);
53     assert(compressedLen >= 0);
54
55         readBuf = new unsigned char[kReadBufSize];
56         if (readBuf == NULL)
57         goto bail;
58     compRemaining = compressedLen;
59
60     /*
61      * Initialize the zlib stream.
62      */
63         memset(&zstream, 0, sizeof(zstream));
64     zstream.zalloc = Z_NULL;
65     zstream.zfree = Z_NULL;
66     zstream.opaque = Z_NULL;
67     zstream.next_in = NULL;
68     zstream.avail_in = 0;
69     zstream.next_out = (Bytef*) buf;
70     zstream.avail_out = uncompressedLen;
71     zstream.data_type = Z_UNKNOWN;
72
73         /*
74          * Use the undocumented "negative window bits" feature to tell zlib
75          * that there's no zlib header waiting for it.
76          */
77     zerr = inflateInit2(&zstream, -MAX_WBITS);
78     if (zerr != Z_OK) {
79         if (zerr == Z_VERSION_ERROR) {
80             LOGE("Installed zlib is not compatible with linked version (%s)\n",
81                 ZLIB_VERSION);
82         } else {
83             LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
84         }
85         goto bail;
86     }
87
88     /*
89      * Loop while we have data.
90      */
91     do {
92         unsigned long getSize;
93
94         /* read as much as we can */
95         if (zstream.avail_in == 0) {
96             getSize = (compRemaining > kReadBufSize) ?
97                         kReadBufSize : compRemaining;
98             LOGV("+++ reading %ld bytes (%ld left)\n",
99                 getSize, compRemaining);
100
101             int cc = read(fd, readBuf, getSize);
102             if (cc != (int) getSize) {
103                 LOGD("inflate read failed (%d vs %ld)\n",
104                     cc, getSize);
105                 goto z_bail;
106             }
107
108             compRemaining -= getSize;
109
110             zstream.next_in = readBuf;
111             zstream.avail_in = getSize;
112         }
113
114         /* uncompress the data */
115         zerr = inflate(&zstream, Z_NO_FLUSH);
116         if (zerr != Z_OK && zerr != Z_STREAM_END) {
117             LOGD("zlib inflate call failed (zerr=%d)\n", zerr);
118             goto z_bail;
119         }
120
121                 /* output buffer holds all, so no need to write the output */
122     } while (zerr == Z_OK);
123
124     assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
125
126     if ((long) zstream.total_out != uncompressedLen) {
127         LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
128             zstream.total_out, uncompressedLen);
129         goto z_bail;
130     }
131
132     // success!
133     result = true;
134
135 z_bail:
136     inflateEnd(&zstream);        /* free up any allocated structures */
137
138 bail:
139         delete[] readBuf;
140     return result;
141 }
142
143 /*
144  * Utility function that expands zip/gzip "deflate" compressed data
145  * into a buffer.
146  *
147  * (This is a clone of the previous function, but it takes a FILE* instead
148  * of an fd.  We could pass fileno(fd) to the above, but we can run into
149  * trouble when "fp" has a different notion of what fd's file position is.)
150  *
151  * "fp" is an open file positioned at the start of the "deflate" data
152  * "buf" must hold at least "uncompressedLen" bytes.
153  */
154 /*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
155     long uncompressedLen, long compressedLen)
156 {
157     bool result = false;
158         const unsigned long kReadBufSize = 32768;
159         unsigned char* readBuf = NULL;
160     z_stream zstream;
161     int zerr;
162     unsigned long compRemaining;
163
164     assert(uncompressedLen >= 0);
165     assert(compressedLen >= 0);
166
167         readBuf = new unsigned char[kReadBufSize];
168         if (readBuf == NULL)
169         goto bail;
170     compRemaining = compressedLen;
171
172     /*
173      * Initialize the zlib stream.
174      */
175         memset(&zstream, 0, sizeof(zstream));
176     zstream.zalloc = Z_NULL;
177     zstream.zfree = Z_NULL;
178     zstream.opaque = Z_NULL;
179     zstream.next_in = NULL;
180     zstream.avail_in = 0;
181     zstream.next_out = (Bytef*) buf;
182     zstream.avail_out = uncompressedLen;
183     zstream.data_type = Z_UNKNOWN;
184
185         /*
186          * Use the undocumented "negative window bits" feature to tell zlib
187          * that there's no zlib header waiting for it.
188          */
189     zerr = inflateInit2(&zstream, -MAX_WBITS);
190     if (zerr != Z_OK) {
191         if (zerr == Z_VERSION_ERROR) {
192             LOGE("Installed zlib is not compatible with linked version (%s)\n",
193                 ZLIB_VERSION);
194         } else {
195             LOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
196         }
197         goto bail;
198     }
199
200     /*
201      * Loop while we have data.
202      */
203     do {
204         unsigned long getSize;
205
206         /* read as much as we can */
207         if (zstream.avail_in == 0) {
208             getSize = (compRemaining > kReadBufSize) ?
209                         kReadBufSize : compRemaining;
210             LOGV("+++ reading %ld bytes (%ld left)\n",
211                 getSize, compRemaining);
212
213             int cc = fread(readBuf, 1, getSize, fp);
214             if (cc != (int) getSize) {
215                 LOGD("inflate read failed (%d vs %ld)\n",
216                     cc, getSize);
217                 goto z_bail;
218             }
219
220             compRemaining -= getSize;
221
222             zstream.next_in = readBuf;
223             zstream.avail_in = getSize;
224         }
225
226         /* uncompress the data */
227         zerr = inflate(&zstream, Z_NO_FLUSH);
228         if (zerr != Z_OK && zerr != Z_STREAM_END) {
229             LOGD("zlib inflate call failed (zerr=%d)\n", zerr);
230             goto z_bail;
231         }
232
233                 /* output buffer holds all, so no need to write the output */
234     } while (zerr == Z_OK);
235
236     assert(zerr == Z_STREAM_END);       /* other errors should've been caught */
237
238     if ((long) zstream.total_out != uncompressedLen) {
239         LOGW("Size mismatch on inflated file (%ld vs %ld)\n",
240             zstream.total_out, uncompressedLen);
241         goto z_bail;
242     }
243
244     // success!
245     result = true;
246
247 z_bail:
248     inflateEnd(&zstream);        /* free up any allocated structures */
249
250 bail:
251         delete[] readBuf;
252     return result;
253 }
254
255 /*
256  * Look at the contents of a gzip archive.  We want to know where the
257  * data starts, and how long it will be after it is uncompressed.
258  *
259  * We expect to find the CRC and length as the last 8 bytes on the file.
260  * This is a pretty reasonable thing to expect for locally-compressed
261  * files, but there's a small chance that some extra padding got thrown
262  * on (the man page talks about compressed data written to tape).  We
263  * don't currently deal with that here.  If "gzip -l" whines, we're going
264  * to fail too.
265  *
266  * On exit, "fp" is pointing at the start of the compressed data.
267  */
268 /*static*/ bool ZipUtils::examineGzip(FILE* fp, int* pCompressionMethod,
269     long* pUncompressedLen, long* pCompressedLen, unsigned long* pCRC32)
270 {
271     enum {  // flags
272         FTEXT       = 0x01,
273         FHCRC       = 0x02,
274         FEXTRA      = 0x04,
275         FNAME       = 0x08,
276         FCOMMENT    = 0x10,
277     };
278     int ic;
279     int method, flags;
280     int i;
281
282     ic = getc(fp);
283     if (ic != 0x1f || getc(fp) != 0x8b)
284         return false;       // not gzip
285     method = getc(fp);
286     flags = getc(fp);
287
288     /* quick sanity checks */
289     if (method == EOF || flags == EOF)
290         return false;
291     if (method != ZipFileRO::kCompressDeflated)
292         return false;
293
294     /* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */
295     for (i = 0; i < 6; i++)
296         (void) getc(fp);
297     /* consume "extra" field, if present */
298     if ((flags & FEXTRA) != 0) {
299         int len;
300
301         len = getc(fp);
302         len |= getc(fp) << 8;
303         while (len-- && getc(fp) != EOF)
304             ;
305     }
306     /* consume filename, if present */
307     if ((flags & FNAME) != 0) {
308         do {
309             ic = getc(fp);
310         } while (ic != 0 && ic != EOF);
311     }
312     /* consume comment, if present */
313     if ((flags & FCOMMENT) != 0) {
314         do {
315             ic = getc(fp);
316         } while (ic != 0 && ic != EOF);
317     }
318     /* consume 16-bit header CRC, if present */
319     if ((flags & FHCRC) != 0) {
320         (void) getc(fp);
321         (void) getc(fp);
322     }
323
324     if (feof(fp) || ferror(fp))
325         return false;
326
327     /* seek to the end; CRC and length are in the last 8 bytes */
328     long curPosn = ftell(fp);
329     unsigned char buf[8];
330     fseek(fp, -8, SEEK_END);
331     *pCompressedLen = ftell(fp) - curPosn;
332
333     if (fread(buf, 1, 8, fp) != 8)
334         return false;
335     /* seek back to start of compressed data */
336     fseek(fp, curPosn, SEEK_SET);
337
338     *pCompressionMethod = method;
339     *pCRC32 = ZipFileRO::get4LE(&buf[0]);
340     *pUncompressedLen = ZipFileRO::get4LE(&buf[4]);
341
342     return true;
343 }