3
|
1 /* gzio.c -- IO on .gz files
|
|
2 * Copyright (C) 1995 Jean-loup Gailly.
|
|
3 * For conditions of distribution and use, see copyright notice in zlib.h
|
|
4 */
|
|
5
|
|
6 /* $Id: gzio.c,v 1.1.1.1 1997/12/06 05:41:36 darius Exp $ */
|
|
7
|
|
8 #include <stdio.h>
|
|
9
|
|
10 #include "zutil.h"
|
|
11
|
|
12 struct internal_state {int dummy;}; /* for buggy compilers */
|
|
13
|
|
14 #define Z_BUFSIZE 4096
|
|
15
|
|
16 #define ALLOC(size) zcalloc((voidp)0, 1, size)
|
|
17 #define TRYFREE(p) {if (p) zcfree((voidp)0, p);}
|
|
18
|
|
19 #define GZ_MAGIC_1 0x1f
|
|
20 #define GZ_MAGIC_2 0x8b
|
|
21
|
|
22 /* gzip flag byte */
|
|
23 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
|
|
24 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
|
|
25 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
|
|
26 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
|
|
27 #define COMMENT 0x10 /* bit 4 set: file comment present */
|
|
28 #define RESERVED 0xE0 /* bits 5..7: reserved */
|
|
29
|
|
30 #ifndef SEEK_CUR
|
|
31 # define SEEK_CUR 1
|
|
32 #endif
|
|
33
|
|
34 typedef struct gz_stream {
|
|
35 z_stream stream;
|
|
36 int z_err; /* error code for last stream operation */
|
|
37 int z_eof; /* set if end of input file */
|
|
38 FILE *file; /* .gz file */
|
|
39 Byte *inbuf; /* input buffer */
|
|
40 Byte *outbuf; /* output buffer */
|
|
41 uLong crc; /* crc32 of uncompressed data */
|
|
42 char *msg; /* error message */
|
|
43 char *path; /* path name for debugging only */
|
|
44 int transparent; /* 1 if input file is not a .gz file */
|
|
45 char mode; /* 'w' or 'r' */
|
|
46 } gz_stream;
|
|
47
|
|
48
|
|
49 local int destroy __P((gz_stream *s));
|
|
50 local gzFile gz_open __P((char *path, char *mode, int fd));
|
|
51 local void putLong __P((FILE *file, uLong x));
|
|
52 local uLong getLong __P((Byte *buf));
|
|
53
|
|
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 zcfree((voidp)0, s);
|
|
81 return err;
|
|
82 }
|
|
83
|
|
84 /* ===========================================================================
|
|
85 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
|
|
87 or path name (if fd == -1).
|
|
88 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
|
|
90 can be checked to distinguish the two cases (if errno is zero, the
|
|
91 zlib error is Z_MEM_ERROR).
|
|
92 */
|
|
93 local gzFile gz_open (path, mode, fd)
|
|
94 char *path;
|
|
95 char *mode;
|
|
96 int fd;
|
|
97 {
|
|
98 int err;
|
|
99 char *p = mode;
|
|
100 gz_stream *s = (gz_stream *)ALLOC(sizeof(gz_stream));
|
|
101
|
|
102 if (!s) return Z_NULL;
|
|
103
|
|
104 s->stream.zalloc = (alloc_func)0;
|
|
105 s->stream.zfree = (free_func)0;
|
|
106 s->stream.next_in = s->inbuf = Z_NULL;
|
|
107 s->stream.next_out = s->outbuf = Z_NULL;
|
|
108 s->stream.avail_in = s->stream.avail_out = 0;
|
|
109 s->file = NULL;
|
|
110 s->z_err = Z_OK;
|
|
111 s->z_eof = 0;
|
|
112 s->crc = crc32(0L, Z_NULL, 0);
|
|
113 s->msg = NULL;
|
|
114 s->transparent = 0;
|
|
115
|
|
116 s->path = (char*)ALLOC(strlen(path)+1);
|
|
117 if (s->path == NULL) {
|
|
118 return destroy(s), (gzFile)Z_NULL;
|
|
119 }
|
|
120 strcpy(s->path, path); /* do this early for debugging */
|
|
121
|
|
122 s->mode = '\0';
|
|
123 do {
|
|
124 if (*p == 'r') s->mode = 'r';
|
|
125 if (*p == 'w') s->mode = 'w';
|
|
126 } while (*p++);
|
|
127 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
|
|
128
|
|
129 if (s->mode == 'w') {
|
|
130 err = deflateInit2(&(s->stream), Z_DEFAULT_COMPRESSION,
|
|
131 DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0);
|
|
132 /* windowBits is passed < 0 to suppress zlib header */
|
|
133
|
|
134 s->stream.next_out = s->outbuf = ALLOC(Z_BUFSIZE);
|
|
135
|
|
136 if (err != Z_OK || s->outbuf == Z_NULL) {
|
|
137 return destroy(s), (gzFile)Z_NULL;
|
|
138 }
|
|
139 } else {
|
|
140 err = inflateInit2(&(s->stream), -MAX_WBITS);
|
|
141 s->stream.next_in = s->inbuf = ALLOC(Z_BUFSIZE);
|
|
142
|
|
143 if (err != Z_OK || s->inbuf == Z_NULL) {
|
|
144 return destroy(s), (gzFile)Z_NULL;
|
|
145 }
|
|
146 }
|
|
147 s->stream.avail_out = Z_BUFSIZE;
|
|
148
|
|
149 errno = 0;
|
|
150 s->file = fd < 0 ? FOPEN(path, mode) : fdopen(fd, mode);
|
|
151
|
|
152 if (s->file == NULL) {
|
|
153 return destroy(s), (gzFile)Z_NULL;
|
|
154 }
|
|
155 if (s->mode == 'w') {
|
|
156 /* Write a very simple .gz header:
|
|
157 */
|
|
158 fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", GZ_MAGIC_1, GZ_MAGIC_2,
|
|
159 DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
|
|
160 } else {
|
|
161 /* Check and skip the header:
|
|
162 */
|
|
163 Byte c1 = 0, c2 = 0;
|
|
164 Byte method = 0;
|
|
165 Byte flags = 0;
|
|
166 Byte xflags = 0;
|
|
167 Byte time[4];
|
|
168 Byte osCode;
|
|
169 int c;
|
|
170
|
|
171 s->stream.avail_in = fread(s->inbuf, 1, 2, s->file);
|
|
172 if (s->stream.avail_in != 2 || s->inbuf[0] != GZ_MAGIC_1
|
|
173 || s->inbuf[1] != GZ_MAGIC_2) {
|
|
174 s->transparent = 1;
|
|
175 return (gzFile)s;
|
|
176 }
|
|
177 s->stream.avail_in = 0;
|
|
178 fscanf(s->file,"%c%c%4c%c%c", &method, &flags, time, &xflags, &osCode);
|
|
179
|
|
180 if (method != DEFLATED || feof(s->file) || (flags & RESERVED) != 0) {
|
|
181 s->z_err = Z_DATA_ERROR;
|
|
182 return (gzFile)s;
|
|
183 }
|
|
184 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
|
|
185 long len;
|
|
186 fscanf(s->file, "%c%c", &c1, &c2);
|
|
187 len = c1 + ((long)c2<<8);
|
|
188 fseek(s->file, len, SEEK_CUR);
|
|
189 }
|
|
190 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
|
|
191 while ((c = getc(s->file)) != 0 && c != EOF) ;
|
|
192 }
|
|
193 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
|
|
194 while ((c = getc(s->file)) != 0 && c != EOF) ;
|
|
195 }
|
|
196 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
|
|
197 fscanf(s->file, "%c%c", &c1, &c2);
|
|
198 }
|
|
199 if (feof(s->file)) {
|
|
200 s->z_err = Z_DATA_ERROR;
|
|
201 }
|
|
202 }
|
|
203 return (gzFile)s;
|
|
204 }
|
|
205
|
|
206 /* ===========================================================================
|
|
207 Opens a gzip (.gz) file for reading or writing.
|
|
208 */
|
|
209 gzFile gzopen (path, mode)
|
|
210 char *path;
|
|
211 char *mode;
|
|
212 {
|
|
213 return gz_open (path, mode, -1);
|
|
214 }
|
|
215
|
|
216 /* ===========================================================================
|
|
217 Associate a gzFile with the file descriptor fd.
|
|
218 */
|
|
219 gzFile gzdopen (fd, mode)
|
|
220 int fd;
|
|
221 char *mode;
|
|
222 {
|
|
223 char name[20];
|
|
224 sprintf(name, "<fd:%d>", fd); /* for debugging */
|
|
225
|
|
226 return gz_open (name, mode, fd);
|
|
227 }
|
|
228
|
|
229 /* ===========================================================================
|
|
230 Reads the given number of uncompressed bytes from the compressed file.
|
|
231 gzread returns the number of bytes actually read (0 for end of file).
|
|
232 */
|
|
233 int gzread (file, buf, len)
|
|
234 gzFile file;
|
|
235 voidp buf;
|
|
236 unsigned len;
|
|
237 {
|
|
238 gz_stream *s = (gz_stream*)file;
|
|
239
|
|
240 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
|
|
241
|
|
242 if (s->transparent) {
|
|
243 unsigned n = 0;
|
|
244 Byte *b = (Byte*)buf;
|
|
245 /* Copy the first two (non-magic) bytes if not done already */
|
|
246 while (s->stream.avail_in > 0 && len > 0) {
|
|
247 *b++ = *s->stream.next_in++;
|
|
248 s->stream.avail_in--;
|
|
249 len--; n++;
|
|
250 }
|
|
251 if (len == 0) return n;
|
|
252 return n + fread(b, 1, len, s->file);
|
|
253 }
|
|
254 if (s->z_err == Z_DATA_ERROR) return -1; /* bad .gz file */
|
|
255 if (s->z_err == Z_STREAM_END) return 0; /* don't read crc as data */
|
|
256
|
|
257 s->stream.next_out = buf;
|
|
258 s->stream.avail_out = len;
|
|
259
|
|
260 while (s->stream.avail_out != 0) {
|
|
261
|
|
262 if (s->stream.avail_in == 0 && !s->z_eof) {
|
|
263
|
|
264 errno = 0;
|
|
265 s->stream.avail_in =
|
|
266 fread(s->inbuf, 1, Z_BUFSIZE, s->file);
|
|
267 if (s->stream.avail_in == 0) {
|
|
268 s->z_eof = 1;
|
|
269 } else if (s->stream.avail_in == (uInt)EOF) {
|
|
270 s->stream.avail_in = 0;
|
|
271 s->z_eof = 1;
|
|
272 s->z_err = Z_ERRNO;
|
|
273 break;
|
|
274 }
|
|
275 s->stream.next_in = s->inbuf;
|
|
276 }
|
|
277 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
|
|
278
|
|
279 if (s->z_err == Z_STREAM_END ||
|
|
280 s->z_err != Z_OK || s->z_eof) break;
|
|
281 }
|
|
282 len -= s->stream.avail_out;
|
|
283 s->crc = crc32(s->crc, buf, len);
|
|
284 return len;
|
|
285 }
|
|
286
|
|
287 /* ===========================================================================
|
|
288 Writes the given number of uncompressed bytes into the compressed file.
|
|
289 gzwrite returns the number of bytes actually written (0 in case of error).
|
|
290 */
|
|
291 int gzwrite (file, buf, len)
|
|
292 gzFile file;
|
|
293 voidp buf;
|
|
294 unsigned len;
|
|
295 {
|
|
296 gz_stream *s = (gz_stream*)file;
|
|
297
|
|
298 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
|
|
299
|
|
300 s->stream.next_in = buf;
|
|
301 s->stream.avail_in = len;
|
|
302
|
|
303 while (s->stream.avail_in != 0) {
|
|
304
|
|
305 if (s->stream.avail_out == 0) {
|
|
306
|
|
307 s->stream.next_out = s->outbuf;
|
|
308 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
|
|
309 s->z_err = Z_ERRNO;
|
|
310 break;
|
|
311 }
|
|
312 s->stream.avail_out = Z_BUFSIZE;
|
|
313 }
|
|
314 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
|
|
315
|
|
316 if (s->z_err != Z_OK) break;
|
|
317 }
|
|
318 s->crc = crc32(s->crc, buf, len);
|
|
319
|
|
320 return len - s->stream.avail_in;
|
|
321 }
|
|
322
|
|
323 /* ===========================================================================
|
|
324 Flushes all pending output into the compressed file. The parameter
|
|
325 flush is as in the deflate() function.
|
|
326 gzflush should be called only when strictly necessary because it can
|
|
327 degrade compression.
|
|
328 */
|
|
329 int gzflush (file, flush)
|
|
330 gzFile file;
|
|
331 int flush;
|
|
332 {
|
|
333 uInt len;
|
|
334 int done = 0;
|
|
335 gz_stream *s = (gz_stream*)file;
|
|
336
|
|
337 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
|
|
338
|
|
339 s->stream.avail_in = 0; /* should be zero already anyway */
|
|
340
|
|
341 for (;;) {
|
|
342 len = Z_BUFSIZE - s->stream.avail_out;
|
|
343
|
|
344 if (len != 0) {
|
|
345 if (fwrite(s->outbuf, 1, len, s->file) != len) {
|
|
346 s->z_err = Z_ERRNO;
|
|
347 return Z_ERRNO;
|
|
348 }
|
|
349 s->stream.next_out = s->outbuf;
|
|
350 s->stream.avail_out = Z_BUFSIZE;
|
|
351 }
|
|
352 if (done) break;
|
|
353 s->z_err = deflate(&(s->stream), flush);
|
|
354
|
|
355 /* deflate has finished flushing only when it hasn't used up
|
|
356 * all the available space in the output buffer:
|
|
357 */
|
|
358 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
|
|
359
|
|
360 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
|
|
361 }
|
|
362 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
|
|
363 }
|
|
364
|
|
365 /* ===========================================================================
|
|
366 Outputs a long in LSB order to the given file
|
|
367 */
|
|
368 local void putLong (file, x)
|
|
369 FILE *file;
|
|
370 uLong x;
|
|
371 {
|
|
372 int n;
|
|
373 for (n = 0; n < 4; n++) {
|
|
374 fputc((int)(x & 0xff), file);
|
|
375 x >>= 8;
|
|
376 }
|
|
377 }
|
|
378
|
|
379 /* ===========================================================================
|
|
380 Reads a long in LSB order from the given buffer
|
|
381 */
|
|
382 local uLong getLong (buf)
|
|
383 Byte *buf;
|
|
384 {
|
|
385 uLong x = 0;
|
|
386 Byte *p = buf+4;
|
|
387
|
|
388 do {
|
|
389 x <<= 8;
|
|
390 x |= *--p;
|
|
391 } while (p != buf);
|
|
392 return x;
|
|
393 }
|
|
394
|
|
395 /* ===========================================================================
|
|
396 Flushes all pending output if necessary, closes the compressed file
|
|
397 and deallocates all the (de)compression state.
|
|
398 */
|
|
399 int gzclose (file)
|
|
400 gzFile file;
|
|
401 {
|
|
402 uInt n;
|
|
403 int err;
|
|
404 gz_stream *s = (gz_stream*)file;
|
|
405
|
|
406 if (s == NULL) return Z_STREAM_ERROR;
|
|
407
|
|
408 if (s->mode == 'w') {
|
|
409 err = gzflush (file, Z_FINISH);
|
|
410 if (err != Z_OK) return destroy(file);
|
|
411
|
|
412 putLong (s->file, s->crc);
|
|
413 putLong (s->file, s->stream.total_in);
|
|
414
|
|
415 } else if (s->mode == 'r' && s->z_err == Z_STREAM_END) {
|
|
416
|
|
417 /* slide CRC and original size if they are at the end of inbuf */
|
|
418 if ((n = s->stream.avail_in) < 8 && !s->z_eof) {
|
|
419 Byte *p = s->inbuf;
|
|
420 Byte *q = s->stream.next_in;
|
|
421 while (n--) { *p++ = *q++; };
|
|
422
|
|
423 n = s->stream.avail_in;
|
|
424 n += fread(p, 1, 8, s->file);
|
|
425 s->stream.next_in = s->inbuf;
|
|
426 }
|
|
427 /* check CRC and original size */
|
|
428 if (n < 8 ||
|
|
429 getLong(s->stream.next_in) != s->crc ||
|
|
430 getLong(s->stream.next_in + 4) != s->stream.total_out) {
|
|
431
|
|
432 s->z_err = Z_DATA_ERROR;
|
|
433 }
|
|
434 }
|
|
435 return destroy(file);
|
|
436 }
|
|
437
|
|
438 /* ===========================================================================
|
|
439 Returns the error message for the last error which occured on the
|
|
440 given compressed file. errnum is set to zlib error number. If an
|
|
441 error occured in the file system and not in the compression library,
|
|
442 errnum is set to Z_ERRNO and the application may consult errno
|
|
443 to get the exact error code.
|
|
444 */
|
|
445 char* gzerror (file, errnum)
|
|
446 gzFile file;
|
|
447 int *errnum;
|
|
448 {
|
|
449 char *m;
|
|
450 gz_stream *s = (gz_stream*)file;
|
|
451
|
|
452 if (s == NULL) {
|
|
453 *errnum = Z_STREAM_ERROR;
|
|
454 return z_errmsg[1-Z_STREAM_ERROR];
|
|
455 }
|
|
456 *errnum = s->z_err;
|
|
457 if (*errnum == Z_OK) return "";
|
|
458
|
|
459 m = *errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg;
|
|
460
|
|
461 if (m == NULL || *m == '\0') m = z_errmsg[1-s->z_err];
|
|
462
|
|
463 TRYFREE(s->msg);
|
|
464 s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
|
|
465 strcpy(s->msg, s->path);
|
|
466 strcat(s->msg, ": ");
|
|
467 strcat(s->msg, m);
|
|
468 return s->msg;
|
|
469 }
|