summaryrefslogtreecommitdiff
path: root/gzio.c
diff options
context:
space:
mode:
Diffstat (limited to 'gzio.c')
-rw-r--r--gzio.c363
1 files changed, 157 insertions, 206 deletions
diff --git a/gzio.c b/gzio.c
index 13c7289..03a4674 100644
--- a/gzio.c
+++ b/gzio.c
@@ -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
19static 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
29typedef struct gz_stream { 34typedef 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
44local gzFile gz_open OF((const char *path, const char *mode, int fd)); 49local int destroy OF((gz_stream *s));
45local int get_byte OF((gz_stream *s)); 50local gzFile gz_open OF((char *path, char *mode, int fd));
46local void check_header OF((gz_stream *s)); 51local void putLong OF((FILE *file, uLong x));
47local int destroy OF((gz_stream *s)); 52local uLong getLong OF((Bytef *buf));
48local void putLong OF((FILE *file, uLong x)); 53
49local uLong getLong OF((gz_stream *s)); 54 /* ===========================================================================
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}
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*/
60local gzFile gz_open (path, mode, fd) 93local 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*/
148gzFile gzopen (path, mode) 212gzFile 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*/
159gzFile gzdopen (fd, mode) 222gzFile 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*/
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 = 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 */
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/* ===========================================================================
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*/
362int gzwrite (file, buf, len) 294int 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*/
453local uLong getLong (s) 385local 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)
471int gzclose (file) 402int 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);