diff options
Diffstat (limited to 'gzio.c')
-rw-r--r-- | gzio.c | 370 |
1 files changed, 210 insertions, 160 deletions
@@ -1,5 +1,5 @@ | |||
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 | ||
@@ -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,44 +41,16 @@ 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 |
86 | is as in fopen ("rb" or "wb"). The file is given either by file descritor | 53 | is as in fopen ("rb" or "wb"). The file is given either by file descriptor |
87 | or path name (if fd == -1). | 54 | or path name (if fd == -1). |
88 | gz_open return NULL if the file could not be opened or if there was | 55 | gz_open return NULL if the file could not be opened or if there was |
89 | insufficient memory to allocate the (de)compression state; errno | 56 | insufficient memory to allocate the (de)compression state; errno |
@@ -91,19 +58,25 @@ 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; |
106 | s->stream.zfree = (free_func)0; | 78 | s->stream.zfree = (free_func)0; |
79 | s->stream.opaque = (voidpf)0; | ||
107 | s->stream.next_in = s->inbuf = Z_NULL; | 80 | s->stream.next_in = s->inbuf = Z_NULL; |
108 | s->stream.next_out = s->outbuf = Z_NULL; | 81 | s->stream.next_out = s->outbuf = Z_NULL; |
109 | s->stream.avail_in = s->stream.avail_out = 0; | 82 | s->stream.avail_in = s->stream.avail_out = 0; |
@@ -123,14 +96,18 @@ local gzFile gz_open (path, mode, fd) | |||
123 | s->mode = '\0'; | 96 | s->mode = '\0'; |
124 | do { | 97 | do { |
125 | if (*p == 'r') s->mode = 'r'; | 98 | if (*p == 'r') s->mode = 'r'; |
126 | if (*p == 'w') s->mode = 'w'; | 99 | if (*p == 'w' || *p == 'a') s->mode = 'w'; |
127 | if (*p >= '1' && *p <= '9') level = *p - '0'; | 100 | if (*p >= '0' && *p <= '9') { |
128 | } while (*p++); | 101 | level = *p - '0'; |
102 | } else { | ||
103 | *m++ = *p; /* copy the mode */ | ||
104 | } | ||
105 | } while (*p++ && m != fmode + sizeof(fmode)); | ||
129 | if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; | 106 | if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; |
130 | 107 | ||
131 | if (s->mode == 'w') { | 108 | if (s->mode == 'w') { |
132 | err = deflateInit2(&(s->stream), level, | 109 | err = deflateInit2(&(s->stream), level, |
133 | DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0); | 110 | Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0); |
134 | /* windowBits is passed < 0 to suppress zlib header */ | 111 | /* windowBits is passed < 0 to suppress zlib header */ |
135 | 112 | ||
136 | s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); | 113 | s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); |
@@ -149,7 +126,7 @@ local gzFile gz_open (path, mode, fd) | |||
149 | s->stream.avail_out = Z_BUFSIZE; | 126 | s->stream.avail_out = Z_BUFSIZE; |
150 | 127 | ||
151 | errno = 0; | 128 | errno = 0; |
152 | s->file = fd < 0 ? FOPEN(path, mode) : fdopen(fd, mode); | 129 | s->file = fd < 0 ? FOPEN(path, fmode) : (FILE*)fdopen(fd, fmode); |
153 | 130 | ||
154 | if (s->file == NULL) { | 131 | if (s->file == NULL) { |
155 | return destroy(s), (gzFile)Z_NULL; | 132 | return destroy(s), (gzFile)Z_NULL; |
@@ -157,50 +134,10 @@ local gzFile gz_open (path, mode, fd) | |||
157 | if (s->mode == 'w') { | 134 | if (s->mode == 'w') { |
158 | /* Write a very simple .gz header: | 135 | /* Write a very simple .gz header: |
159 | */ | 136 | */ |
160 | 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], |
161 | 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); |
162 | } else { | 139 | } else { |
163 | /* Check and skip the header: | 140 | check_header(s); /* skip the .gz header */ |
164 | */ | ||
165 | Byte c1 = 0, c2 = 0; | ||
166 | Byte method = 0; | ||
167 | Byte flags = 0; | ||
168 | Byte xflags = 0; | ||
169 | Byte time[4]; | ||
170 | Byte osCode; | ||
171 | int c; | ||
172 | |||
173 | s->stream.avail_in = fread(s->inbuf, 1, 2, s->file); | ||
174 | if (s->stream.avail_in != 2 || s->inbuf[0] != GZ_MAGIC_1 | ||
175 | || s->inbuf[1] != GZ_MAGIC_2) { | ||
176 | s->transparent = 1; | ||
177 | return (gzFile)s; | ||
178 | } | ||
179 | s->stream.avail_in = 0; | ||
180 | fscanf(s->file,"%c%c%4c%c%c", &method, &flags, time, &xflags, &osCode); | ||
181 | |||
182 | if (method != DEFLATED || feof(s->file) || (flags & RESERVED) != 0) { | ||
183 | s->z_err = Z_DATA_ERROR; | ||
184 | return (gzFile)s; | ||
185 | } | ||
186 | if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ | ||
187 | long len; | ||
188 | fscanf(s->file, "%c%c", &c1, &c2); | ||
189 | len = c1 + ((long)c2<<8); | ||
190 | fseek(s->file, len, SEEK_CUR); | ||
191 | } | ||
192 | if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ | ||
193 | while ((c = getc(s->file)) != 0 && c != EOF) ; | ||
194 | } | ||
195 | if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ | ||
196 | while ((c = getc(s->file)) != 0 && c != EOF) ; | ||
197 | } | ||
198 | if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ | ||
199 | fscanf(s->file, "%c%c", &c1, &c2); | ||
200 | } | ||
201 | if (feof(s->file)) { | ||
202 | s->z_err = Z_DATA_ERROR; | ||
203 | } | ||
204 | } | 141 | } |
205 | return (gzFile)s; | 142 | return (gzFile)s; |
206 | } | 143 | } |
@@ -209,26 +146,139 @@ local gzFile gz_open (path, mode, fd) | |||
209 | Opens a gzip (.gz) file for reading or writing. | 146 | Opens a gzip (.gz) file for reading or writing. |
210 | */ | 147 | */ |
211 | gzFile gzopen (path, mode) | 148 | gzFile gzopen (path, mode) |
212 | char *path; | 149 | const char *path; |
213 | char *mode; | 150 | const char *mode; |
214 | { | 151 | { |
215 | return gz_open (path, mode, -1); | 152 | return gz_open (path, mode, -1); |
216 | } | 153 | } |
217 | 154 | ||
218 | /* =========================================================================== | 155 | /* =========================================================================== |
219 | 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. | ||
220 | */ | 158 | */ |
221 | gzFile gzdopen (fd, mode) | 159 | gzFile gzdopen (fd, mode) |
222 | int fd; | 160 | int fd; |
223 | char *mode; | 161 | const char *mode; |
224 | { | 162 | { |
225 | char name[20]; | 163 | char name[20]; |
164 | |||
165 | if (fd < 0) return (gzFile)Z_NULL; | ||
226 | sprintf(name, "<fd:%d>", fd); /* for debugging */ | 166 | sprintf(name, "<fd:%d>", fd); /* for debugging */ |
227 | 167 | ||
228 | return gz_open (name, mode, fd); | 168 | return gz_open (name, mode, fd); |
229 | } | 169 | } |
230 | 170 | ||
231 | /* =========================================================================== | 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 = 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 | /* =========================================================================== | ||
232 | Reads the given number of uncompressed bytes from the compressed file. | 282 | Reads the given number of uncompressed bytes from the compressed file. |
233 | 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). |
234 | */ | 284 | */ |
@@ -238,52 +288,71 @@ int gzread (file, buf, len) | |||
238 | unsigned len; | 288 | unsigned len; |
239 | { | 289 | { |
240 | gz_stream *s = (gz_stream*)file; | 290 | gz_stream *s = (gz_stream*)file; |
291 | Byte *start = buf; /* starting point for crc computation */ | ||
241 | 292 | ||
242 | if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; | 293 | if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; |
243 | 294 | ||
244 | if (s->transparent) { | 295 | if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; |
245 | int n = 0; | 296 | if (s->z_err == Z_STREAM_END) return 0; /* EOF */ |
246 | Byte *b = (Byte*)buf; | ||
247 | /* Copy the first two (non-magic) bytes if not done already */ | ||
248 | while (s->stream.avail_in > 0 && len > 0) { | ||
249 | *b++ = *s->stream.next_in++; | ||
250 | s->stream.avail_in--; | ||
251 | len--; n++; | ||
252 | } | ||
253 | if (len == 0) return n; | ||
254 | return n + fread(b, 1, len, s->file); | ||
255 | } | ||
256 | if (s->z_err == Z_DATA_ERROR) return -1; /* bad .gz file */ | ||
257 | if (s->z_err == Z_STREAM_END) return 0; /* don't read crc as data */ | ||
258 | 297 | ||
259 | s->stream.next_out = buf; | 298 | s->stream.next_out = buf; |
260 | s->stream.avail_out = len; | 299 | s->stream.avail_out = len; |
261 | 300 | ||
262 | while (s->stream.avail_out != 0) { | 301 | while (s->stream.avail_out != 0) { |
263 | 302 | ||
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 | } | ||
264 | if (s->stream.avail_in == 0 && !s->z_eof) { | 320 | if (s->stream.avail_in == 0 && !s->z_eof) { |
265 | 321 | ||
266 | errno = 0; | 322 | errno = 0; |
267 | s->stream.avail_in = | 323 | s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); |
268 | fread(s->inbuf, 1, Z_BUFSIZE, s->file); | ||
269 | if (s->stream.avail_in == 0) { | 324 | if (s->stream.avail_in == 0) { |
270 | s->z_eof = 1; | 325 | s->z_eof = 1; |
271 | } else if (s->stream.avail_in == (uInt)EOF) { | 326 | if (ferror(s->file)) { |
272 | s->stream.avail_in = 0; | 327 | s->z_err = Z_ERRNO; |
273 | s->z_eof = 1; | 328 | break; |
274 | s->z_err = Z_ERRNO; | 329 | } |
275 | break; | ||
276 | } | 330 | } |
277 | s->stream.next_in = s->inbuf; | 331 | s->stream.next_in = s->inbuf; |
278 | } | 332 | } |
279 | s->z_err = inflate(&(s->stream), Z_NO_FLUSH); | 333 | s->z_err = inflate(&(s->stream), Z_NO_FLUSH); |
280 | 334 | ||
281 | if (s->z_err == Z_STREAM_END || | 335 | if (s->z_err == Z_STREAM_END) { |
282 | s->z_err != Z_OK || s->z_eof) break; | 336 | /* Check CRC and original size */ |
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; | ||
283 | } | 352 | } |
284 | len -= s->stream.avail_out; | 353 | s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); |
285 | s->crc = crc32(s->crc, buf, len); | 354 | |
286 | return (int)len; | 355 | return (int)(len - s->stream.avail_out); |
287 | } | 356 | } |
288 | 357 | ||
289 | /* =========================================================================== | 358 | /* =========================================================================== |
@@ -292,7 +361,7 @@ int gzread (file, buf, len) | |||
292 | */ | 361 | */ |
293 | int gzwrite (file, buf, len) | 362 | int gzwrite (file, buf, len) |
294 | gzFile file; | 363 | gzFile file; |
295 | voidp buf; | 364 | const voidp buf; |
296 | unsigned len; | 365 | unsigned len; |
297 | { | 366 | { |
298 | gz_stream *s = (gz_stream*)file; | 367 | gz_stream *s = (gz_stream*)file; |
@@ -343,7 +412,7 @@ int gzflush (file, flush) | |||
343 | len = Z_BUFSIZE - s->stream.avail_out; | 412 | len = Z_BUFSIZE - s->stream.avail_out; |
344 | 413 | ||
345 | if (len != 0) { | 414 | if (len != 0) { |
346 | if (fwrite(s->outbuf, 1, len, s->file) != len) { | 415 | if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { |
347 | s->z_err = Z_ERRNO; | 416 | s->z_err = Z_ERRNO; |
348 | return Z_ERRNO; | 417 | return Z_ERRNO; |
349 | } | 418 | } |
@@ -379,18 +448,19 @@ local void putLong (file, x) | |||
379 | } | 448 | } |
380 | 449 | ||
381 | /* =========================================================================== | 450 | /* =========================================================================== |
382 | Reads a long in LSB order from the given buffer | 451 | Reads a long in LSB order from the given gz_stream. Sets |
383 | */ | 452 | */ |
384 | local uLong getLong (buf) | 453 | local uLong getLong (s) |
385 | Bytef *buf; | 454 | gz_stream *s; |
386 | { | 455 | { |
387 | uLong x = 0; | 456 | uLong x = (uLong)get_byte(s); |
388 | Bytef *p = buf+4; | 457 | int c; |
389 | 458 | ||
390 | do { | 459 | x += ((uLong)get_byte(s))<<8; |
391 | x <<= 8; | 460 | x += ((uLong)get_byte(s))<<16; |
392 | x |= *--p; | 461 | c = get_byte(s); |
393 | } while (p != buf); | 462 | if (c == EOF) s->z_err = Z_DATA_ERROR; |
463 | x += ((uLong)c)<<24; | ||
394 | return x; | 464 | return x; |
395 | } | 465 | } |
396 | 466 | ||
@@ -401,7 +471,6 @@ local uLong getLong (buf) | |||
401 | int gzclose (file) | 471 | int gzclose (file) |
402 | gzFile file; | 472 | gzFile file; |
403 | { | 473 | { |
404 | uInt n; | ||
405 | int err; | 474 | int err; |
406 | gz_stream *s = (gz_stream*)file; | 475 | gz_stream *s = (gz_stream*)file; |
407 | 476 | ||
@@ -414,25 +483,6 @@ int gzclose (file) | |||
414 | putLong (s->file, s->crc); | 483 | putLong (s->file, s->crc); |
415 | putLong (s->file, s->stream.total_in); | 484 | putLong (s->file, s->stream.total_in); |
416 | 485 | ||
417 | } else if (s->mode == 'r' && s->z_err == Z_STREAM_END) { | ||
418 | |||
419 | /* slide CRC and original size if they are at the end of inbuf */ | ||
420 | if ((n = s->stream.avail_in) < 8 && !s->z_eof) { | ||
421 | Byte *p = s->inbuf; | ||
422 | Bytef *q = s->stream.next_in; | ||
423 | while (n--) { *p++ = *q++; }; | ||
424 | |||
425 | n = s->stream.avail_in; | ||
426 | n += fread(p, 1, 8, s->file); | ||
427 | s->stream.next_in = s->inbuf; | ||
428 | } | ||
429 | /* check CRC and original size */ | ||
430 | if (n < 8 || | ||
431 | getLong(s->stream.next_in) != s->crc || | ||
432 | getLong(s->stream.next_in + 4) != s->stream.total_out) { | ||
433 | |||
434 | s->z_err = Z_DATA_ERROR; | ||
435 | } | ||
436 | } | 486 | } |
437 | return destroy(file); | 487 | return destroy(file); |
438 | } | 488 | } |
@@ -453,14 +503,14 @@ char* gzerror (file, errnum) | |||
453 | 503 | ||
454 | if (s == NULL) { | 504 | if (s == NULL) { |
455 | *errnum = Z_STREAM_ERROR; | 505 | *errnum = Z_STREAM_ERROR; |
456 | return z_errmsg[1-Z_STREAM_ERROR]; | 506 | return ERR_MSG(Z_STREAM_ERROR); |
457 | } | 507 | } |
458 | *errnum = s->z_err; | 508 | *errnum = s->z_err; |
459 | if (*errnum == Z_OK) return ""; | 509 | if (*errnum == Z_OK) return (char*)""; |
460 | 510 | ||
461 | m = *errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg; | 511 | m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); |
462 | 512 | ||
463 | if (m == NULL || *m == '\0') m = z_errmsg[1-s->z_err]; | 513 | if (m == NULL || *m == '\0') m = (char*)z_errmsg[1-s->z_err]; |
464 | 514 | ||
465 | TRYFREE(s->msg); | 515 | TRYFREE(s->msg); |
466 | s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); | 516 | s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); |