diff options
Diffstat (limited to 'gzio.c')
-rw-r--r-- | gzio.c | 363 |
1 files changed, 157 insertions, 206 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* gzio.c -- IO on .gz files | 1 | /* gzio.c -- IO on .gz files |
2 | * Copyright (C) 1995-1996 Jean-loup Gailly. | 2 | * Copyright (C) 1995 Jean-loup Gailly. |
3 | * For conditions of distribution and use, see copyright notice in zlib.h | 3 | * For conditions of distribution and use, see copyright notice in zlib.h |
4 | */ | 4 | */ |
5 | 5 | ||
@@ -16,7 +16,8 @@ struct internal_state {int dummy;}; /* for buggy compilers */ | |||
16 | #define ALLOC(size) malloc(size) | 16 | #define ALLOC(size) malloc(size) |
17 | #define TRYFREE(p) {if (p) free(p);} | 17 | #define TRYFREE(p) {if (p) free(p);} |
18 | 18 | ||
19 | static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ | 19 | #define GZ_MAGIC_1 0x1f |
20 | #define GZ_MAGIC_2 0x8b | ||
20 | 21 | ||
21 | /* gzip flag byte */ | 22 | /* gzip flag byte */ |
22 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ | 23 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ |
@@ -26,6 +27,10 @@ static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ | |||
26 | #define COMMENT 0x10 /* bit 4 set: file comment present */ | 27 | #define COMMENT 0x10 /* bit 4 set: file comment present */ |
27 | #define RESERVED 0xE0 /* bits 5..7: reserved */ | 28 | #define RESERVED 0xE0 /* bits 5..7: reserved */ |
28 | 29 | ||
30 | #ifndef SEEK_CUR | ||
31 | # define SEEK_CUR 1 | ||
32 | #endif | ||
33 | |||
29 | typedef struct gz_stream { | 34 | typedef struct gz_stream { |
30 | z_stream stream; | 35 | z_stream stream; |
31 | int z_err; /* error code for last stream operation */ | 36 | int z_err; /* error code for last stream operation */ |
@@ -41,12 +46,40 @@ typedef struct gz_stream { | |||
41 | } gz_stream; | 46 | } gz_stream; |
42 | 47 | ||
43 | 48 | ||
44 | local gzFile gz_open OF((const char *path, const char *mode, int fd)); | 49 | local int destroy OF((gz_stream *s)); |
45 | local int get_byte OF((gz_stream *s)); | 50 | local gzFile gz_open OF((char *path, char *mode, int fd)); |
46 | local void check_header OF((gz_stream *s)); | 51 | local void putLong OF((FILE *file, uLong x)); |
47 | local int destroy OF((gz_stream *s)); | 52 | local uLong getLong OF((Bytef *buf)); |
48 | local void putLong OF((FILE *file, uLong x)); | 53 | |
49 | local uLong getLong OF((gz_stream *s)); | 54 | /* =========================================================================== |
55 | * Cleanup then free the given gz_stream. Return a zlib error code. | ||
56 | */ | ||
57 | local int destroy (s) | ||
58 | gz_stream *s; | ||
59 | { | ||
60 | int err = Z_OK; | ||
61 | |||
62 | if (!s) return Z_STREAM_ERROR; | ||
63 | |||
64 | TRYFREE(s->inbuf); | ||
65 | TRYFREE(s->outbuf); | ||
66 | TRYFREE(s->path); | ||
67 | TRYFREE(s->msg); | ||
68 | |||
69 | if (s->stream.state != NULL) { | ||
70 | if (s->mode == 'w') { | ||
71 | err = deflateEnd(&(s->stream)); | ||
72 | } else if (s->mode == 'r') { | ||
73 | err = inflateEnd(&(s->stream)); | ||
74 | } | ||
75 | } | ||
76 | if (s->file != NULL && fclose(s->file)) { | ||
77 | err = Z_ERRNO; | ||
78 | } | ||
79 | if (s->z_err < 0) err = s->z_err; | ||
80 | TRYFREE(s); | ||
81 | return err; | ||
82 | } | ||
50 | 83 | ||
51 | /* =========================================================================== | 84 | /* =========================================================================== |
52 | Opens a gzip (.gz) file for reading or writing. The mode parameter | 85 | Opens a gzip (.gz) file for reading or writing. The mode parameter |
@@ -58,20 +91,15 @@ local uLong getLong OF((gz_stream *s)); | |||
58 | zlib error is Z_MEM_ERROR). | 91 | zlib error is Z_MEM_ERROR). |
59 | */ | 92 | */ |
60 | local gzFile gz_open (path, mode, fd) | 93 | local gzFile gz_open (path, mode, fd) |
61 | const char *path; | 94 | char *path; |
62 | const char *mode; | 95 | char *mode; |
63 | int fd; | 96 | int fd; |
64 | { | 97 | { |
65 | int err; | 98 | int err; |
66 | int level = Z_DEFAULT_COMPRESSION; /* compression level */ | 99 | int level = Z_DEFAULT_COMPRESSION; /* compression level */ |
67 | char *p = (char*)mode; | 100 | char *p = mode; |
68 | gz_stream *s; | 101 | gz_stream *s = (gz_stream *)ALLOC(sizeof(gz_stream)); |
69 | char fmode[80]; /* copy of mode, without the compression level */ | ||
70 | char *m = fmode; | ||
71 | |||
72 | if (!path || !mode) return Z_NULL; | ||
73 | 102 | ||
74 | s = (gz_stream *)ALLOC(sizeof(gz_stream)); | ||
75 | if (!s) return Z_NULL; | 103 | if (!s) return Z_NULL; |
76 | 104 | ||
77 | s->stream.zalloc = (alloc_func)0; | 105 | s->stream.zalloc = (alloc_func)0; |
@@ -96,13 +124,9 @@ local gzFile gz_open (path, mode, fd) | |||
96 | s->mode = '\0'; | 124 | s->mode = '\0'; |
97 | do { | 125 | do { |
98 | if (*p == 'r') s->mode = 'r'; | 126 | if (*p == 'r') s->mode = 'r'; |
99 | if (*p == 'w' || *p == 'a') s->mode = 'w'; | 127 | if (*p == 'w') s->mode = 'w'; |
100 | if (*p >= '0' && *p <= '9') { | 128 | if (*p >= '1' && *p <= '9') level = *p - '0'; |
101 | level = *p - '0'; | 129 | } while (*p++); |
102 | } else { | ||
103 | *m++ = *p; /* copy the mode */ | ||
104 | } | ||
105 | } while (*p++ && m != fmode + sizeof(fmode)); | ||
106 | if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; | 130 | if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; |
107 | 131 | ||
108 | if (s->mode == 'w') { | 132 | if (s->mode == 'w') { |
@@ -126,7 +150,7 @@ local gzFile gz_open (path, mode, fd) | |||
126 | s->stream.avail_out = Z_BUFSIZE; | 150 | s->stream.avail_out = Z_BUFSIZE; |
127 | 151 | ||
128 | errno = 0; | 152 | errno = 0; |
129 | s->file = fd < 0 ? FOPEN(path, fmode) : (FILE*)fdopen(fd, fmode); | 153 | s->file = fd < 0 ? FOPEN(path, mode) : (FILE*)fdopen(fd, mode); |
130 | 154 | ||
131 | if (s->file == NULL) { | 155 | if (s->file == NULL) { |
132 | return destroy(s), (gzFile)Z_NULL; | 156 | return destroy(s), (gzFile)Z_NULL; |
@@ -134,10 +158,50 @@ local gzFile gz_open (path, mode, fd) | |||
134 | if (s->mode == 'w') { | 158 | if (s->mode == 'w') { |
135 | /* Write a very simple .gz header: | 159 | /* Write a very simple .gz header: |
136 | */ | 160 | */ |
137 | fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], | 161 | fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", GZ_MAGIC_1, GZ_MAGIC_2, |
138 | Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); | 162 | Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); |
139 | } else { | 163 | } else { |
140 | check_header(s); /* skip the .gz header */ | 164 | /* Check and skip the header: |
165 | */ | ||
166 | Byte c1 = 0, c2 = 0; | ||
167 | Byte method = 0; | ||
168 | Byte flags = 0; | ||
169 | Byte xflags = 0; | ||
170 | Byte time[4]; | ||
171 | Byte osCode; | ||
172 | int c; | ||
173 | |||
174 | s->stream.avail_in = fread(s->inbuf, 1, 2, s->file); | ||
175 | if (s->stream.avail_in != 2 || s->inbuf[0] != GZ_MAGIC_1 | ||
176 | || s->inbuf[1] != GZ_MAGIC_2) { | ||
177 | s->transparent = 1; | ||
178 | return (gzFile)s; | ||
179 | } | ||
180 | s->stream.avail_in = 0; | ||
181 | fscanf(s->file,"%c%c%4c%c%c", &method, &flags, time, &xflags, &osCode); | ||
182 | |||
183 | if (method != Z_DEFLATED || feof(s->file) || (flags & RESERVED) != 0) { | ||
184 | s->z_err = Z_DATA_ERROR; | ||
185 | return (gzFile)s; | ||
186 | } | ||
187 | if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ | ||
188 | long len; | ||
189 | fscanf(s->file, "%c%c", &c1, &c2); | ||
190 | len = c1 + ((long)c2<<8); | ||
191 | fseek(s->file, len, SEEK_CUR); | ||
192 | } | ||
193 | if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ | ||
194 | while ((c = getc(s->file)) != 0 && c != EOF) ; | ||
195 | } | ||
196 | if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ | ||
197 | while ((c = getc(s->file)) != 0 && c != EOF) ; | ||
198 | } | ||
199 | if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ | ||
200 | fscanf(s->file, "%c%c", &c1, &c2); | ||
201 | } | ||
202 | if (feof(s->file)) { | ||
203 | s->z_err = Z_DATA_ERROR; | ||
204 | } | ||
141 | } | 205 | } |
142 | return (gzFile)s; | 206 | return (gzFile)s; |
143 | } | 207 | } |
@@ -146,139 +210,26 @@ local gzFile gz_open (path, mode, fd) | |||
146 | Opens a gzip (.gz) file for reading or writing. | 210 | Opens a gzip (.gz) file for reading or writing. |
147 | */ | 211 | */ |
148 | gzFile gzopen (path, mode) | 212 | gzFile gzopen (path, mode) |
149 | const char *path; | 213 | char *path; |
150 | const char *mode; | 214 | char *mode; |
151 | { | 215 | { |
152 | return gz_open (path, mode, -1); | 216 | return gz_open (path, mode, -1); |
153 | } | 217 | } |
154 | 218 | ||
155 | /* =========================================================================== | 219 | /* =========================================================================== |
156 | Associate a gzFile with the file descriptor fd. fd is not dup'ed here | 220 | Associate a gzFile with the file descriptor fd. |
157 | to mimic the behavio(u)r of fdopen. | ||
158 | */ | 221 | */ |
159 | gzFile gzdopen (fd, mode) | 222 | gzFile gzdopen (fd, mode) |
160 | int fd; | 223 | int fd; |
161 | const char *mode; | 224 | char *mode; |
162 | { | 225 | { |
163 | char name[20]; | 226 | char name[20]; |
164 | |||
165 | if (fd < 0) return (gzFile)Z_NULL; | ||
166 | sprintf(name, "<fd:%d>", fd); /* for debugging */ | 227 | sprintf(name, "<fd:%d>", fd); /* for debugging */ |
167 | 228 | ||
168 | return gz_open (name, mode, fd); | 229 | return gz_open (name, mode, fd); |
169 | } | 230 | } |
170 | 231 | ||
171 | /* =========================================================================== | 232 | /* =========================================================================== |
172 | Read a byte from a gz_stream; update next_in and avail_in. Return EOF | ||
173 | for end of file. | ||
174 | IN assertion: the stream s has been sucessfully opened for reading. | ||
175 | */ | ||
176 | local int get_byte(s) | ||
177 | gz_stream *s; | ||
178 | { | ||
179 | if (s->z_eof) return EOF; | ||
180 | if (s->stream.avail_in == 0) { | ||
181 | errno = 0; | ||
182 | s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); | ||
183 | if (s->stream.avail_in == 0) { | ||
184 | s->z_eof = 1; | ||
185 | if (ferror(s->file)) s->z_err = Z_ERRNO; | ||
186 | return EOF; | ||
187 | } | ||
188 | s->stream.next_in = s->inbuf; | ||
189 | } | ||
190 | s->stream.avail_in--; | ||
191 | return *(s->stream.next_in)++; | ||
192 | } | ||
193 | |||
194 | /* =========================================================================== | ||
195 | Check the gzip header of a gz_stream opened for reading. Set the stream | ||
196 | mode to transparent if the gzip magic header is not present; set s->err | ||
197 | to Z_DATA_ERROR if the magic header is present but the rest of the header | ||
198 | is incorrect. | ||
199 | IN assertion: the stream s has already been created sucessfully; | ||
200 | s->stream.avail_in is zero for the first time, but may be non-zero | ||
201 | for concatenated .gz files. | ||
202 | */ | ||
203 | local void check_header(s) | ||
204 | gz_stream *s; | ||
205 | { | ||
206 | int method = 0; | ||
207 | int flags = 0; | ||
208 | uInt len; | ||
209 | int c; | ||
210 | |||
211 | /* Check the gzip magic header */ | ||
212 | for (len = 0; len < 2; len++) { | ||
213 | c = get_byte(s); | ||
214 | if (c != gz_magic[len]) { | ||
215 | s->transparent = 1; | ||
216 | if (c != EOF) s->stream.avail_in++, s->stream.next_in--; | ||
217 | s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; | ||
218 | return; | ||
219 | } | ||
220 | } | ||
221 | method = get_byte(s); | ||
222 | flags = get_byte(s); | ||
223 | if (method != Z_DEFLATED || (flags & RESERVED) != 0) { | ||
224 | s->z_err = Z_DATA_ERROR; | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | /* Discard time, xflags and OS code: */ | ||
229 | for (len = 0; len < 6; len++) (void)get_byte(s); | ||
230 | |||
231 | if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ | ||
232 | len = (uInt)get_byte(s); | ||
233 | len += ((uInt)get_byte(s))<<8; | ||
234 | /* len is garbage if EOF but the loop below will quit anyway */ | ||
235 | while (len-- != 0 && get_byte(s) != EOF) ; | ||
236 | } | ||
237 | if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ | ||
238 | while ((c = get_byte(s)) != 0 && c != EOF) ; | ||
239 | } | ||
240 | if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ | ||
241 | while ((c = get_byte(s)) != 0 && c != EOF) ; | ||
242 | } | ||
243 | if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ | ||
244 | for (len = 0; len < 2; len++) (void)get_byte(s); | ||
245 | } | ||
246 | s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; | ||
247 | } | ||
248 | |||
249 | /* =========================================================================== | ||
250 | * Cleanup then free the given gz_stream. Return a zlib error code. | ||
251 | Try freeing in the reverse order of allocations. | ||
252 | */ | ||
253 | local int destroy (s) | ||
254 | gz_stream *s; | ||
255 | { | ||
256 | int err = Z_OK; | ||
257 | |||
258 | if (!s) return Z_STREAM_ERROR; | ||
259 | |||
260 | TRYFREE(s->msg); | ||
261 | |||
262 | if (s->stream.state != NULL) { | ||
263 | if (s->mode == 'w') { | ||
264 | err = deflateEnd(&(s->stream)); | ||
265 | } else if (s->mode == 'r') { | ||
266 | err = inflateEnd(&(s->stream)); | ||
267 | } | ||
268 | } | ||
269 | if (s->file != NULL && fclose(s->file)) { | ||
270 | err = Z_ERRNO; | ||
271 | } | ||
272 | if (s->z_err < 0) err = s->z_err; | ||
273 | |||
274 | TRYFREE(s->inbuf); | ||
275 | TRYFREE(s->outbuf); | ||
276 | TRYFREE(s->path); | ||
277 | TRYFREE(s); | ||
278 | return err; | ||
279 | } | ||
280 | |||
281 | /* =========================================================================== | ||
282 | Reads the given number of uncompressed bytes from the compressed file. | 233 | Reads the given number of uncompressed bytes from the compressed file. |
283 | gzread returns the number of bytes actually read (0 for end of file). | 234 | gzread returns the number of bytes actually read (0 for end of file). |
284 | */ | 235 | */ |
@@ -288,71 +239,52 @@ int gzread (file, buf, len) | |||
288 | unsigned len; | 239 | unsigned len; |
289 | { | 240 | { |
290 | gz_stream *s = (gz_stream*)file; | 241 | gz_stream *s = (gz_stream*)file; |
291 | Byte *start = buf; /* starting point for crc computation */ | ||
292 | 242 | ||
293 | if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; | 243 | if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; |
294 | 244 | ||
295 | if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; | 245 | if (s->transparent) { |
296 | if (s->z_err == Z_STREAM_END) return 0; /* EOF */ | 246 | int n = 0; |
247 | Byte *b = (Byte*)buf; | ||
248 | /* Copy the first two (non-magic) bytes if not done already */ | ||
249 | while (s->stream.avail_in > 0 && len > 0) { | ||
250 | *b++ = *s->stream.next_in++; | ||
251 | s->stream.avail_in--; | ||
252 | len--; n++; | ||
253 | } | ||
254 | if (len == 0) return n; | ||
255 | return n + fread(b, 1, len, s->file); | ||
256 | } | ||
257 | if (s->z_err == Z_DATA_ERROR) return -1; /* bad .gz file */ | ||
258 | if (s->z_err == Z_STREAM_END) return 0; /* don't read crc as data */ | ||
297 | 259 | ||
298 | s->stream.next_out = buf; | 260 | s->stream.next_out = buf; |
299 | s->stream.avail_out = len; | 261 | s->stream.avail_out = len; |
300 | 262 | ||
301 | while (s->stream.avail_out != 0) { | 263 | while (s->stream.avail_out != 0) { |
302 | 264 | ||
303 | if (s->transparent) { | ||
304 | /* Copy first the lookahead bytes: */ | ||
305 | uInt n = s->stream.avail_in; | ||
306 | if (n > s->stream.avail_out) n = s->stream.avail_out; | ||
307 | if (n > 0) { | ||
308 | zmemcpy(s->stream.next_out, s->stream.next_in, n); | ||
309 | s->stream.next_out += n; | ||
310 | s->stream.next_in += n; | ||
311 | s->stream.avail_out -= n; | ||
312 | s->stream.avail_in -= n; | ||
313 | } | ||
314 | if (s->stream.avail_out > 0) { | ||
315 | s->stream.avail_out -= fread(s->stream.next_out, | ||
316 | 1, s->stream.avail_out, s->file); | ||
317 | } | ||
318 | return (int)(len - s->stream.avail_out); | ||
319 | } | ||
320 | if (s->stream.avail_in == 0 && !s->z_eof) { | 265 | if (s->stream.avail_in == 0 && !s->z_eof) { |
321 | 266 | ||
322 | errno = 0; | 267 | errno = 0; |
323 | s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); | 268 | s->stream.avail_in = |
269 | fread(s->inbuf, 1, Z_BUFSIZE, s->file); | ||
324 | if (s->stream.avail_in == 0) { | 270 | if (s->stream.avail_in == 0) { |
325 | s->z_eof = 1; | 271 | s->z_eof = 1; |
326 | if (ferror(s->file)) { | 272 | } else if (s->stream.avail_in == (uInt)EOF) { |
327 | s->z_err = Z_ERRNO; | 273 | s->stream.avail_in = 0; |
328 | break; | 274 | s->z_eof = 1; |
329 | } | 275 | s->z_err = Z_ERRNO; |
276 | break; | ||
330 | } | 277 | } |
331 | s->stream.next_in = s->inbuf; | 278 | s->stream.next_in = s->inbuf; |
332 | } | 279 | } |
333 | s->z_err = inflate(&(s->stream), Z_NO_FLUSH); | 280 | s->z_err = inflate(&(s->stream), Z_NO_FLUSH); |
334 | 281 | ||
335 | if (s->z_err == Z_STREAM_END) { | 282 | if (s->z_err == Z_STREAM_END || |
336 | /* Check CRC and original size */ | 283 | s->z_err != Z_OK || s->z_eof) break; |
337 | s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); | ||
338 | start = s->stream.next_out; | ||
339 | |||
340 | if (getLong(s) != s->crc || getLong(s) != s->stream.total_out) { | ||
341 | s->z_err = Z_DATA_ERROR; | ||
342 | } else { | ||
343 | /* Check for concatenated .gz files: */ | ||
344 | check_header(s); | ||
345 | if (s->z_err == Z_OK) { | ||
346 | inflateReset(&(s->stream)); | ||
347 | s->crc = crc32(0L, Z_NULL, 0); | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | if (s->z_err != Z_OK || s->z_eof) break; | ||
352 | } | 284 | } |
353 | s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); | 285 | len -= s->stream.avail_out; |
354 | 286 | s->crc = crc32(s->crc, buf, len); | |
355 | return (int)(len - s->stream.avail_out); | 287 | return (int)len; |
356 | } | 288 | } |
357 | 289 | ||
358 | /* =========================================================================== | 290 | /* =========================================================================== |
@@ -361,7 +293,7 @@ int gzread (file, buf, len) | |||
361 | */ | 293 | */ |
362 | int gzwrite (file, buf, len) | 294 | int gzwrite (file, buf, len) |
363 | gzFile file; | 295 | gzFile file; |
364 | const voidp buf; | 296 | voidp buf; |
365 | unsigned len; | 297 | unsigned len; |
366 | { | 298 | { |
367 | gz_stream *s = (gz_stream*)file; | 299 | gz_stream *s = (gz_stream*)file; |
@@ -412,7 +344,7 @@ int gzflush (file, flush) | |||
412 | len = Z_BUFSIZE - s->stream.avail_out; | 344 | len = Z_BUFSIZE - s->stream.avail_out; |
413 | 345 | ||
414 | if (len != 0) { | 346 | if (len != 0) { |
415 | if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { | 347 | if (fwrite(s->outbuf, 1, len, s->file) != len) { |
416 | s->z_err = Z_ERRNO; | 348 | s->z_err = Z_ERRNO; |
417 | return Z_ERRNO; | 349 | return Z_ERRNO; |
418 | } | 350 | } |
@@ -448,19 +380,18 @@ local void putLong (file, x) | |||
448 | } | 380 | } |
449 | 381 | ||
450 | /* =========================================================================== | 382 | /* =========================================================================== |
451 | Reads a long in LSB order from the given gz_stream. Sets | 383 | Reads a long in LSB order from the given buffer |
452 | */ | 384 | */ |
453 | local uLong getLong (s) | 385 | local uLong getLong (buf) |
454 | gz_stream *s; | 386 | Bytef *buf; |
455 | { | 387 | { |
456 | uLong x = (uLong)get_byte(s); | 388 | uLong x = 0; |
457 | int c; | 389 | Bytef *p = buf+4; |
458 | 390 | ||
459 | x += ((uLong)get_byte(s))<<8; | 391 | do { |
460 | x += ((uLong)get_byte(s))<<16; | 392 | x <<= 8; |
461 | c = get_byte(s); | 393 | x |= *--p; |
462 | if (c == EOF) s->z_err = Z_DATA_ERROR; | 394 | } while (p != buf); |
463 | x += ((uLong)c)<<24; | ||
464 | return x; | 395 | return x; |
465 | } | 396 | } |
466 | 397 | ||
@@ -471,6 +402,7 @@ local uLong getLong (s) | |||
471 | int gzclose (file) | 402 | int gzclose (file) |
472 | gzFile file; | 403 | gzFile file; |
473 | { | 404 | { |
405 | uInt n; | ||
474 | int err; | 406 | int err; |
475 | gz_stream *s = (gz_stream*)file; | 407 | gz_stream *s = (gz_stream*)file; |
476 | 408 | ||
@@ -483,6 +415,25 @@ int gzclose (file) | |||
483 | putLong (s->file, s->crc); | 415 | putLong (s->file, s->crc); |
484 | putLong (s->file, s->stream.total_in); | 416 | putLong (s->file, s->stream.total_in); |
485 | 417 | ||
418 | } else if (s->mode == 'r' && s->z_err == Z_STREAM_END) { | ||
419 | |||
420 | /* slide CRC and original size if they are at the end of inbuf */ | ||
421 | if ((n = s->stream.avail_in) < 8 && !s->z_eof) { | ||
422 | Byte *p = s->inbuf; | ||
423 | Bytef *q = s->stream.next_in; | ||
424 | while (n--) { *p++ = *q++; }; | ||
425 | |||
426 | n = s->stream.avail_in; | ||
427 | n += fread(p, 1, 8, s->file); | ||
428 | s->stream.next_in = s->inbuf; | ||
429 | } | ||
430 | /* check CRC and original size */ | ||
431 | if (n < 8 || | ||
432 | getLong(s->stream.next_in) != s->crc || | ||
433 | getLong(s->stream.next_in + 4) != s->stream.total_out) { | ||
434 | |||
435 | s->z_err = Z_DATA_ERROR; | ||
436 | } | ||
486 | } | 437 | } |
487 | return destroy(file); | 438 | return destroy(file); |
488 | } | 439 | } |
@@ -503,14 +454,14 @@ char* gzerror (file, errnum) | |||
503 | 454 | ||
504 | if (s == NULL) { | 455 | if (s == NULL) { |
505 | *errnum = Z_STREAM_ERROR; | 456 | *errnum = Z_STREAM_ERROR; |
506 | return ERR_MSG(Z_STREAM_ERROR); | 457 | return z_errmsg[1-Z_STREAM_ERROR]; |
507 | } | 458 | } |
508 | *errnum = s->z_err; | 459 | *errnum = s->z_err; |
509 | if (*errnum == Z_OK) return (char*)""; | 460 | if (*errnum == Z_OK) return ""; |
510 | 461 | ||
511 | m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); | 462 | m = *errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg; |
512 | 463 | ||
513 | if (m == NULL || *m == '\0') m = (char*)z_errmsg[1-s->z_err]; | 464 | if (m == NULL || *m == '\0') m = z_errmsg[1-s->z_err]; |
514 | 465 | ||
515 | TRYFREE(s->msg); | 466 | TRYFREE(s->msg); |
516 | s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); | 467 | s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); |