diff options
Diffstat (limited to 'gzio.c')
-rw-r--r-- | gzio.c | 369 |
1 files changed, 210 insertions, 159 deletions
@@ -1,9 +1,9 @@ | |||
1 | /* gzio.c -- IO on .gz files | 1 | /* gzio.c -- IO on .gz files |
2 | * Copyright (C) 1995 Jean-loup Gailly. | 2 | * Copyright (C) 1995-1996 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 | ||
6 | /* $Id: gzio.c,v 1.8 1995/05/03 17:27:09 jloup Exp $ */ | 6 | /* $Id: gzio.c,v 1.12 1996/01/30 21:59:14 me Exp $ */ |
7 | 7 | ||
8 | #include <stdio.h> | 8 | #include <stdio.h> |
9 | 9 | ||
@@ -16,8 +16,7 @@ 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 | #define GZ_MAGIC_1 0x1f | 19 | static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ |
20 | #define GZ_MAGIC_2 0x8b | ||
21 | 20 | ||
22 | /* gzip flag byte */ | 21 | /* gzip flag byte */ |
23 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ | 22 | #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ |
@@ -27,10 +26,6 @@ struct internal_state {int dummy;}; /* for buggy compilers */ | |||
27 | #define COMMENT 0x10 /* bit 4 set: file comment present */ | 26 | #define COMMENT 0x10 /* bit 4 set: file comment present */ |
28 | #define RESERVED 0xE0 /* bits 5..7: reserved */ | 27 | #define RESERVED 0xE0 /* bits 5..7: reserved */ |
29 | 28 | ||
30 | #ifndef SEEK_CUR | ||
31 | # define SEEK_CUR 1 | ||
32 | #endif | ||
33 | |||
34 | typedef struct gz_stream { | 29 | typedef struct gz_stream { |
35 | z_stream stream; | 30 | z_stream stream; |
36 | int z_err; /* error code for last stream operation */ | 31 | int z_err; /* error code for last stream operation */ |
@@ -46,40 +41,12 @@ typedef struct gz_stream { | |||
46 | } gz_stream; | 41 | } gz_stream; |
47 | 42 | ||
48 | 43 | ||
49 | local int destroy OF((gz_stream *s)); | 44 | local gzFile gz_open OF((const char *path, const char *mode, int fd)); |
50 | local gzFile gz_open OF((char *path, char *mode, int fd)); | 45 | local int get_byte OF((gz_stream *s)); |
51 | local void putLong OF((FILE *file, uLong x)); | 46 | local void check_header OF((gz_stream *s)); |
52 | local uLong getLong OF((Bytef *buf)); | 47 | local int destroy OF((gz_stream *s)); |
53 | 48 | local void putLong OF((FILE *file, uLong x)); | |
54 | /* =========================================================================== | 49 | local uLong getLong OF((gz_stream *s)); |
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 | } | ||
83 | 50 | ||
84 | /* =========================================================================== | 51 | /* =========================================================================== |
85 | Opens a gzip (.gz) file for reading or writing. The mode parameter | 52 | Opens a gzip (.gz) file for reading or writing. The mode parameter |
@@ -91,15 +58,20 @@ local int destroy (s) | |||
91 | zlib error is Z_MEM_ERROR). | 58 | zlib error is Z_MEM_ERROR). |
92 | */ | 59 | */ |
93 | local gzFile gz_open (path, mode, fd) | 60 | local gzFile gz_open (path, mode, fd) |
94 | char *path; | 61 | const char *path; |
95 | char *mode; | 62 | const char *mode; |
96 | int fd; | 63 | int fd; |
97 | { | 64 | { |
98 | int err; | 65 | int err; |
99 | int level = Z_DEFAULT_COMPRESSION; /* compression level */ | 66 | int level = Z_DEFAULT_COMPRESSION; /* compression level */ |
100 | char *p = mode; | 67 | char *p = (char*)mode; |
101 | gz_stream *s = (gz_stream *)ALLOC(sizeof(gz_stream)); | 68 | gz_stream *s; |
69 | char fmode[80]; /* copy of mode, without the compression level */ | ||
70 | char *m = fmode; | ||
71 | |||
72 | if (!path || !mode) return Z_NULL; | ||
102 | 73 | ||
74 | s = (gz_stream *)ALLOC(sizeof(gz_stream)); | ||
103 | if (!s) return Z_NULL; | 75 | if (!s) return Z_NULL; |
104 | 76 | ||
105 | s->stream.zalloc = (alloc_func)0; | 77 | s->stream.zalloc = (alloc_func)0; |
@@ -124,9 +96,13 @@ local gzFile gz_open (path, mode, fd) | |||
124 | s->mode = '\0'; | 96 | s->mode = '\0'; |
125 | do { | 97 | do { |
126 | if (*p == 'r') s->mode = 'r'; | 98 | if (*p == 'r') s->mode = 'r'; |
127 | if (*p == 'w') s->mode = 'w'; | 99 | if (*p == 'w' || *p == 'a') s->mode = 'w'; |
128 | if (*p >= '1' && *p <= '9') level = *p - '0'; | 100 | if (*p >= '0' && *p <= '9') { |
129 | } while (*p++); | 101 | level = *p - '0'; |
102 | } else { | ||
103 | *m++ = *p; /* copy the mode */ | ||
104 | } | ||
105 | } while (*p++ && m != fmode + sizeof(fmode)); | ||
130 | if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; | 106 | if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; |
131 | 107 | ||
132 | if (s->mode == 'w') { | 108 | if (s->mode == 'w') { |
@@ -150,7 +126,7 @@ local gzFile gz_open (path, mode, fd) | |||
150 | s->stream.avail_out = Z_BUFSIZE; | 126 | s->stream.avail_out = Z_BUFSIZE; |
151 | 127 | ||
152 | errno = 0; | 128 | errno = 0; |
153 | s->file = fd < 0 ? FOPEN(path, mode) : (FILE*)fdopen(fd, mode); | 129 | s->file = fd < 0 ? FOPEN(path, fmode) : (FILE*)fdopen(fd, fmode); |
154 | 130 | ||
155 | if (s->file == NULL) { | 131 | if (s->file == NULL) { |
156 | return destroy(s), (gzFile)Z_NULL; | 132 | return destroy(s), (gzFile)Z_NULL; |
@@ -158,50 +134,10 @@ local gzFile gz_open (path, mode, fd) | |||
158 | if (s->mode == 'w') { | 134 | if (s->mode == 'w') { |
159 | /* Write a very simple .gz header: | 135 | /* Write a very simple .gz header: |
160 | */ | 136 | */ |
161 | fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", GZ_MAGIC_1, GZ_MAGIC_2, | 137 | fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], |
162 | Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); | 138 | Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); |
163 | } else { | 139 | } else { |
164 | /* Check and skip the header: | 140 | check_header(s); /* skip the .gz 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 | } | ||
205 | } | 141 | } |
206 | return (gzFile)s; | 142 | return (gzFile)s; |
207 | } | 143 | } |
@@ -210,26 +146,139 @@ local gzFile gz_open (path, mode, fd) | |||
210 | Opens a gzip (.gz) file for reading or writing. | 146 | Opens a gzip (.gz) file for reading or writing. |
211 | */ | 147 | */ |
212 | gzFile gzopen (path, mode) | 148 | gzFile gzopen (path, mode) |
213 | char *path; | 149 | const char *path; |
214 | char *mode; | 150 | const char *mode; |
215 | { | 151 | { |
216 | return gz_open (path, mode, -1); | 152 | return gz_open (path, mode, -1); |
217 | } | 153 | } |
218 | 154 | ||
219 | /* =========================================================================== | 155 | /* =========================================================================== |
220 | Associate a gzFile with the file descriptor fd. | 156 | Associate a gzFile with the file descriptor fd. fd is not dup'ed here |
157 | to mimic the behavio(u)r of fdopen. | ||
221 | */ | 158 | */ |
222 | gzFile gzdopen (fd, mode) | 159 | gzFile gzdopen (fd, mode) |
223 | int fd; | 160 | int fd; |
224 | char *mode; | 161 | const char *mode; |
225 | { | 162 | { |
226 | char name[20]; | 163 | char name[20]; |
164 | |||
165 | if (fd < 0) return (gzFile)Z_NULL; | ||
227 | sprintf(name, "<fd:%d>", fd); /* for debugging */ | 166 | sprintf(name, "<fd:%d>", fd); /* for debugging */ |
228 | 167 | ||
229 | return gz_open (name, mode, fd); | 168 | return gz_open (name, mode, fd); |
230 | } | 169 | } |
231 | 170 | ||
232 | /* =========================================================================== | 171 | /* =========================================================================== |
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; /* method byte */ | ||
207 | int flags; /* flags byte */ | ||
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 | /* =========================================================================== | ||
233 | Reads the given number of uncompressed bytes from the compressed file. | 282 | Reads the given number of uncompressed bytes from the compressed file. |
234 | gzread returns the number of bytes actually read (0 for end of file). | 283 | gzread returns the number of bytes actually read (0 for end of file). |
235 | */ | 284 | */ |
@@ -239,52 +288,73 @@ int gzread (file, buf, len) | |||
239 | unsigned len; | 288 | unsigned len; |
240 | { | 289 | { |
241 | gz_stream *s = (gz_stream*)file; | 290 | gz_stream *s = (gz_stream*)file; |
291 | Bytef *start = buf; /* starting point for crc computation */ | ||
292 | Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ | ||
242 | 293 | ||
243 | if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; | 294 | if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; |
244 | 295 | ||
245 | if (s->transparent) { | 296 | if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; |
246 | int n = 0; | 297 | if (s->z_err == Z_STREAM_END) return 0; /* EOF */ |
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 */ | ||
259 | 298 | ||
260 | s->stream.next_out = buf; | 299 | s->stream.next_out = next_out = buf; |
261 | s->stream.avail_out = len; | 300 | s->stream.avail_out = len; |
262 | 301 | ||
263 | while (s->stream.avail_out != 0) { | 302 | while (s->stream.avail_out != 0) { |
264 | 303 | ||
304 | if (s->transparent) { | ||
305 | /* Copy first the lookahead bytes: */ | ||
306 | uInt n = s->stream.avail_in; | ||
307 | if (n > s->stream.avail_out) n = s->stream.avail_out; | ||
308 | if (n > 0) { | ||
309 | zmemcpy(s->stream.next_out, s->stream.next_in, n); | ||
310 | next_out += n; | ||
311 | s->stream.next_out = next_out; | ||
312 | s->stream.next_in += n; | ||
313 | s->stream.avail_out -= n; | ||
314 | s->stream.avail_in -= n; | ||
315 | } | ||
316 | if (s->stream.avail_out > 0) { | ||
317 | s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, | ||
318 | s->file); | ||
319 | } | ||
320 | return (int)(len - s->stream.avail_out); | ||
321 | } | ||
265 | if (s->stream.avail_in == 0 && !s->z_eof) { | 322 | if (s->stream.avail_in == 0 && !s->z_eof) { |
266 | 323 | ||
267 | errno = 0; | 324 | errno = 0; |
268 | s->stream.avail_in = | 325 | s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); |
269 | fread(s->inbuf, 1, Z_BUFSIZE, s->file); | ||
270 | if (s->stream.avail_in == 0) { | 326 | if (s->stream.avail_in == 0) { |
271 | s->z_eof = 1; | 327 | s->z_eof = 1; |
272 | } else if (s->stream.avail_in == (uInt)EOF) { | 328 | if (ferror(s->file)) { |
273 | s->stream.avail_in = 0; | 329 | s->z_err = Z_ERRNO; |
274 | s->z_eof = 1; | 330 | break; |
275 | s->z_err = Z_ERRNO; | 331 | } |
276 | break; | ||
277 | } | 332 | } |
278 | s->stream.next_in = s->inbuf; | 333 | s->stream.next_in = s->inbuf; |
279 | } | 334 | } |
280 | s->z_err = inflate(&(s->stream), Z_NO_FLUSH); | 335 | s->z_err = inflate(&(s->stream), Z_NO_FLUSH); |
281 | 336 | ||
282 | if (s->z_err == Z_STREAM_END || | 337 | if (s->z_err == Z_STREAM_END) { |
283 | s->z_err != Z_OK || s->z_eof) break; | 338 | /* Check CRC and original size */ |
339 | s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); | ||
340 | start = s->stream.next_out; | ||
341 | |||
342 | if (getLong(s) != s->crc || getLong(s) != s->stream.total_out) { | ||
343 | s->z_err = Z_DATA_ERROR; | ||
344 | } else { | ||
345 | /* Check for concatenated .gz files: */ | ||
346 | check_header(s); | ||
347 | if (s->z_err == Z_OK) { | ||
348 | inflateReset(&(s->stream)); | ||
349 | s->crc = crc32(0L, Z_NULL, 0); | ||
350 | } | ||
351 | } | ||
352 | } | ||
353 | if (s->z_err != Z_OK || s->z_eof) break; | ||
284 | } | 354 | } |
285 | len -= s->stream.avail_out; | 355 | s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); |
286 | s->crc = crc32(s->crc, buf, len); | 356 | |
287 | return (int)len; | 357 | return (int)(len - s->stream.avail_out); |
288 | } | 358 | } |
289 | 359 | ||
290 | /* =========================================================================== | 360 | /* =========================================================================== |
@@ -293,7 +363,7 @@ int gzread (file, buf, len) | |||
293 | */ | 363 | */ |
294 | int gzwrite (file, buf, len) | 364 | int gzwrite (file, buf, len) |
295 | gzFile file; | 365 | gzFile file; |
296 | voidp buf; | 366 | const voidp buf; |
297 | unsigned len; | 367 | unsigned len; |
298 | { | 368 | { |
299 | gz_stream *s = (gz_stream*)file; | 369 | gz_stream *s = (gz_stream*)file; |
@@ -344,7 +414,7 @@ int gzflush (file, flush) | |||
344 | len = Z_BUFSIZE - s->stream.avail_out; | 414 | len = Z_BUFSIZE - s->stream.avail_out; |
345 | 415 | ||
346 | if (len != 0) { | 416 | if (len != 0) { |
347 | if (fwrite(s->outbuf, 1, len, s->file) != len) { | 417 | if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { |
348 | s->z_err = Z_ERRNO; | 418 | s->z_err = Z_ERRNO; |
349 | return Z_ERRNO; | 419 | return Z_ERRNO; |
350 | } | 420 | } |
@@ -380,18 +450,19 @@ local void putLong (file, x) | |||
380 | } | 450 | } |
381 | 451 | ||
382 | /* =========================================================================== | 452 | /* =========================================================================== |
383 | Reads a long in LSB order from the given buffer | 453 | Reads a long in LSB order from the given gz_stream. Sets |
384 | */ | 454 | */ |
385 | local uLong getLong (buf) | 455 | local uLong getLong (s) |
386 | Bytef *buf; | 456 | gz_stream *s; |
387 | { | 457 | { |
388 | uLong x = 0; | 458 | uLong x = (uLong)get_byte(s); |
389 | Bytef *p = buf+4; | 459 | int c; |
390 | 460 | ||
391 | do { | 461 | x += ((uLong)get_byte(s))<<8; |
392 | x <<= 8; | 462 | x += ((uLong)get_byte(s))<<16; |
393 | x |= *--p; | 463 | c = get_byte(s); |
394 | } while (p != buf); | 464 | if (c == EOF) s->z_err = Z_DATA_ERROR; |
465 | x += ((uLong)c)<<24; | ||
395 | return x; | 466 | return x; |
396 | } | 467 | } |
397 | 468 | ||
@@ -402,7 +473,6 @@ local uLong getLong (buf) | |||
402 | int gzclose (file) | 473 | int gzclose (file) |
403 | gzFile file; | 474 | gzFile file; |
404 | { | 475 | { |
405 | uInt n; | ||
406 | int err; | 476 | int err; |
407 | gz_stream *s = (gz_stream*)file; | 477 | gz_stream *s = (gz_stream*)file; |
408 | 478 | ||
@@ -415,25 +485,6 @@ int gzclose (file) | |||
415 | putLong (s->file, s->crc); | 485 | putLong (s->file, s->crc); |
416 | putLong (s->file, s->stream.total_in); | 486 | putLong (s->file, s->stream.total_in); |
417 | 487 | ||
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 | } | ||
437 | } | 488 | } |
438 | return destroy(file); | 489 | return destroy(file); |
439 | } | 490 | } |
@@ -454,14 +505,14 @@ char* gzerror (file, errnum) | |||
454 | 505 | ||
455 | if (s == NULL) { | 506 | if (s == NULL) { |
456 | *errnum = Z_STREAM_ERROR; | 507 | *errnum = Z_STREAM_ERROR; |
457 | return z_errmsg[1-Z_STREAM_ERROR]; | 508 | return ERR_MSG(Z_STREAM_ERROR); |
458 | } | 509 | } |
459 | *errnum = s->z_err; | 510 | *errnum = s->z_err; |
460 | if (*errnum == Z_OK) return ""; | 511 | if (*errnum == Z_OK) return (char*)""; |
461 | 512 | ||
462 | m = *errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg; | 513 | m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); |
463 | 514 | ||
464 | if (m == NULL || *m == '\0') m = z_errmsg[1-s->z_err]; | 515 | if (m == NULL || *m == '\0') m = ERR_MSG(s->z_err); |
465 | 516 | ||
466 | TRYFREE(s->msg); | 517 | TRYFREE(s->msg); |
467 | s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); | 518 | s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); |