summaryrefslogtreecommitdiff
path: root/gzio.c
diff options
context:
space:
mode:
Diffstat (limited to 'gzio.c')
-rw-r--r--gzio.c369
1 files changed, 210 insertions, 159 deletions
diff --git a/gzio.c b/gzio.c
index 03a4674..6f6832b 100644
--- a/gzio.c
+++ b/gzio.c
@@ -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 19static 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
34typedef struct gz_stream { 29typedef 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
49local int destroy OF((gz_stream *s)); 44local gzFile gz_open OF((const char *path, const char *mode, int fd));
50local gzFile gz_open OF((char *path, char *mode, int fd)); 45local int get_byte OF((gz_stream *s));
51local void putLong OF((FILE *file, uLong x)); 46local void check_header OF((gz_stream *s));
52local uLong getLong OF((Bytef *buf)); 47local int destroy OF((gz_stream *s));
53 48local void putLong OF((FILE *file, uLong x));
54 /* =========================================================================== 49local uLong getLong OF((gz_stream *s));
55 * Cleanup then free the given gz_stream. Return a zlib error code.
56 */
57local 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*/
93local gzFile gz_open (path, mode, fd) 60local 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*/
212gzFile gzopen (path, mode) 148gzFile 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*/
222gzFile gzdopen (fd, mode) 159gzFile 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*/
176local 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*/
203local 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 */
253local 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*/
294int gzwrite (file, buf, len) 364int 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*/
385local uLong getLong (buf) 455local 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)
402int gzclose (file) 473int 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);