summaryrefslogtreecommitdiff
path: root/gzio.c
diff options
context:
space:
mode:
Diffstat (limited to 'gzio.c')
-rw-r--r--gzio.c459
1 files changed, 459 insertions, 0 deletions
diff --git a/gzio.c b/gzio.c
new file mode 100644
index 0000000..b488e96
--- /dev/null
+++ b/gzio.c
@@ -0,0 +1,459 @@
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.4 1995/04/14 14:50:52 jloup Exp $ */
7
8#include <stdio.h>
9
10#include "zutil.h"
11
12struct 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
34typedef 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/* ===========================================================================
50 * Cleanup then free the given gz_stream. Return a zlib error code.
51 */
52local int destroy (s)
53 gz_stream *s;
54{
55 int err = Z_OK;
56
57 if (!s) return Z_STREAM_ERROR;
58
59 TRYFREE(s->inbuf);
60 TRYFREE(s->outbuf);
61 TRYFREE(s->path);
62 TRYFREE(s->msg);
63
64 if (s->stream.state != NULL) {
65 if (s->mode == 'w') {
66 err = deflateEnd(&(s->stream));
67 } else if (s->mode == 'r') {
68 err = inflateEnd(&(s->stream));
69 }
70 }
71 if (s->file != NULL && fclose(s->file)) {
72 err = Z_ERRNO;
73 }
74 zcfree((voidp)0, s);
75 return s->z_err < 0 ? s->z_err : err;
76}
77
78/* ===========================================================================
79 Opens a gzip (.gz) file for reading or writing. The mode parameter
80 is as in fopen ("rb" or "wb"). The file is given either by file descritor
81 or path name (if fd == -1).
82 gz_open return NULL if the file could not be opened or if there was
83 insufficient memory to allocate the (de)compression state; errno
84 can be checked to distinguish the two cases (if errno is zero, the
85 zlib error is Z_MEM_ERROR).
86*/
87local gzFile gz_open (path, mode, fd)
88 char *path;
89 char *mode;
90 int fd;
91{
92 int err;
93 char *p = mode;
94 gz_stream *s = (gz_stream *)ALLOC(sizeof(gz_stream));
95
96 if (!s) return Z_NULL;
97
98 s->stream.zalloc = (alloc_func)0;
99 s->stream.zfree = (free_func)0;
100 s->stream.next_in = s->inbuf = Z_NULL;
101 s->stream.next_out = s->outbuf = Z_NULL;
102 s->stream.avail_in = s->stream.avail_out = 0;
103 s->file = NULL;
104 s->z_err = Z_OK;
105 s->z_eof = 0;
106 s->crc = crc32(0L, Z_NULL, 0);
107 s->msg = NULL;
108 s->transparent = 0;
109
110 s->path = (char*)ALLOC(strlen(path)+1);
111 if (s->path == NULL) {
112 return destroy(s), (gzFile)Z_NULL;
113 }
114 strcpy(s->path, path); /* do this early for debugging */
115
116 s->mode = '\0';
117 do {
118 if (*p == 'r') s->mode = 'r';
119 if (*p == 'w') s->mode = 'w';
120 } while (*p++);
121 if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
122
123 if (s->mode == 'w') {
124 err = deflateInit2(&(s->stream), Z_DEFAULT_COMPRESSION,
125 DEFLATED, -WBITS, MEM_LEVEL, 0);
126 /* windowBits is passed < 0 to suppress zlib header */
127
128 s->stream.next_out = s->outbuf = ALLOC(Z_BUFSIZE);
129
130 if (err != Z_OK || s->outbuf == Z_NULL) {
131 return destroy(s), (gzFile)Z_NULL;
132 }
133 } else {
134 err = inflateInit2(&(s->stream), -WBITS);
135 s->stream.next_in = s->inbuf = ALLOC(Z_BUFSIZE);
136
137 if (err != Z_OK || s->inbuf == Z_NULL) {
138 return destroy(s), (gzFile)Z_NULL;
139 }
140 }
141 s->stream.avail_out = Z_BUFSIZE;
142
143 errno = 0;
144 s->file = fd < 0 ? FOPEN(path, mode) : fdopen(fd, mode);
145
146 if (s->file == NULL) {
147 return destroy(s), (gzFile)Z_NULL;
148 }
149 if (s->mode == 'w') {
150 /* Write a very simple .gz header:
151 */
152 fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", GZ_MAGIC_1, GZ_MAGIC_2,
153 DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
154 } else {
155 /* Check and skip the header:
156 */
157 Byte c1 = 0, c2 = 0;
158 Byte method = 0;
159 Byte flags = 0;
160 Byte xflags = 0;
161 Byte time[4];
162 Byte osCode;
163 int c;
164
165 s->stream.avail_in = fread(s->inbuf, 1, 2, s->file);
166 if (s->stream.avail_in != 2 || s->inbuf[0] != GZ_MAGIC_1
167 || s->inbuf[1] != GZ_MAGIC_2) {
168 s->transparent = 1;
169 return (gzFile)s;
170 }
171 s->stream.avail_in = 0;
172 fscanf(s->file,"%c%c%4c%c%c", &method, &flags, time, &xflags, &osCode);
173
174 if (method != DEFLATED || feof(s->file) || (flags & RESERVED) != 0) {
175 s->z_err = Z_DATA_ERROR;
176 return (gzFile)s;
177 }
178 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
179 long len;
180 fscanf(s->file, "%c%c", &c1, &c2);
181 len = c1 + ((long)c2<<8);
182 fseek(s->file, len, SEEK_CUR);
183 }
184 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
185 while ((c = getc(s->file)) != 0 && c != EOF) ;
186 }
187 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
188 while ((c = getc(s->file)) != 0 && c != EOF) ;
189 }
190 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
191 fscanf(s->file, "%c%c", &c1, &c2);
192 }
193 if (feof(s->file)) {
194 s->z_err = Z_DATA_ERROR;
195 }
196 }
197 return (gzFile)s;
198}
199
200/* ===========================================================================
201 Opens a gzip (.gz) file for reading or writing.
202*/
203gzFile gzopen (path, mode)
204 char *path;
205 char *mode;
206{
207 return gz_open (path, mode, -1);
208}
209
210/* ===========================================================================
211 Associate a gzFile with the file descriptor fd.
212*/
213gzFile gzdopen (fd, mode)
214 int fd;
215 char *mode;
216{
217 char name[20];
218 sprintf(name, "_fd:%d_", fd); /* for debugging */
219
220 return gz_open (name, mode, fd);
221}
222
223/* ===========================================================================
224 Reads the given number of uncompressed bytes from the compressed file.
225 gzread returns the number of bytes actually read (0 for end of file).
226*/
227int gzread (file, buf, len)
228 gzFile file;
229 voidp buf;
230 unsigned len;
231{
232 gz_stream *s = (gz_stream*)file;
233
234 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
235
236 if (s->transparent) {
237 unsigned n = 0;
238 /* Copy the first two (non-magic) bytes if not done already */
239 while (s->stream.avail_in > 0 && len > 0) {
240 *((Byte*)buf)++ = *s->stream.next_in++;
241 s->stream.avail_in--;
242 len--; n++;
243 }
244 if (len == 0) return n;
245 return n + fread(buf, 1, len, s->file);
246 }
247 if (s->z_err == Z_DATA_ERROR) return -1; /* bad .gz file */
248 if (s->z_err == Z_STREAM_END) return 0; /* don't read crc as data */
249
250 s->stream.next_out = buf;
251 s->stream.avail_out = len;
252
253 while (s->stream.avail_out != 0) {
254
255 if (s->stream.avail_in == 0 && !s->z_eof) {
256
257 errno = 0;
258 s->stream.avail_in =
259 fread(s->inbuf, 1, Z_BUFSIZE, s->file);
260 if (s->stream.avail_in == 0) {
261 s->z_eof = 1;
262 } else if (s->stream.avail_in == (uInt)EOF) {
263 s->stream.avail_in = 0;
264 s->z_eof = 1;
265 s->z_err = Z_ERRNO;
266 break;
267 }
268 s->stream.next_in = s->inbuf;
269 }
270 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
271
272 if (s->z_err == Z_STREAM_END ||
273 s->z_err != Z_OK || s->z_eof) break;
274 }
275 len -= s->stream.avail_out;
276 s->crc = crc32(s->crc, buf, len);
277 return len;
278}
279
280/* ===========================================================================
281 Writes the given number of uncompressed bytes into the compressed file.
282 gzwrite returns the number of bytes actually written (0 in case of error).
283*/
284int gzwrite (file, buf, len)
285 gzFile file;
286 voidp buf;
287 unsigned len;
288{
289 gz_stream *s = (gz_stream*)file;
290
291 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
292
293 s->stream.next_in = buf;
294 s->stream.avail_in = len;
295
296 while (s->stream.avail_in != 0) {
297
298 if (s->stream.avail_out == 0) {
299
300 s->stream.next_out = s->outbuf;
301 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
302 s->z_err = Z_ERRNO;
303 break;
304 }
305 s->stream.avail_out = Z_BUFSIZE;
306 }
307 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
308
309 if (s->z_err != Z_OK) break;
310 }
311 s->crc = crc32(s->crc, buf, len);
312
313 return len - s->stream.avail_in;
314}
315
316/* ===========================================================================
317 Flushes all pending output into the compressed file. The parameter
318 flush is as in the deflate() function.
319 gzflush should be called only when strictly necessary because it can
320 degrade compression.
321*/
322int gzflush (file, flush)
323 gzFile file;
324 int flush;
325{
326 uInt len;
327 int done = 0;
328 gz_stream *s = (gz_stream*)file;
329
330 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
331
332 s->stream.avail_in = 0; /* should be zero already anyway */
333
334 for (;;) {
335 len = Z_BUFSIZE - s->stream.avail_out;
336
337 if (len != 0) {
338 if (fwrite(s->outbuf, 1, len, s->file) != len) {
339 s->z_err = Z_ERRNO;
340 break;
341 }
342 s->stream.next_out = s->outbuf;
343 s->stream.avail_out = Z_BUFSIZE;
344 }
345 if (done) break;
346 s->z_err = deflate(&(s->stream), flush);
347
348 if (s->z_err != Z_OK) break;
349
350 /* deflate has finished flushing only when it hasn't used up
351 * all the available space in the output buffer:
352 */
353 done = (s->stream.avail_out != 0);
354 }
355 return s->z_err;
356}
357
358/* ===========================================================================
359 Outputs a long in LSB order to the given file
360*/
361local void putLong (file, x)
362 FILE *file;
363 uLong x;
364{
365 int n;
366 for (n = 0; n < 4; n++) {
367 fputc(x & 0xff, file);
368 x >>= 8;
369 }
370}
371
372/* ===========================================================================
373 Reads a long in LSB order from the given buffer
374*/
375local uLong getLong (buf)
376 Byte *buf;
377{
378 uLong x = 0;
379 Byte *p = buf+4;
380
381 do {
382 x <<= 8;
383 x |= *--p;
384 } while (p != buf);
385 return x;
386}
387
388/* ===========================================================================
389 Flushes all pending output if necessary, closes the compressed file
390 and deallocates all the (de)compression state.
391*/
392int gzclose (file)
393 gzFile file;
394{
395 uInt n;
396 gz_stream *s = (gz_stream*)file;
397
398 if (s == NULL) return Z_STREAM_ERROR;
399
400 if (s->mode == 'w') {
401 gzflush (file, Z_FINISH);
402 putLong (s->file, s->crc);
403 putLong (s->file, s->stream.total_in);
404
405 } else if (s->mode == 'r' && s->z_err == Z_STREAM_END) {
406
407 /* slide CRC and original size if they are at the end of inbuf */
408 if ((n = s->stream.avail_in) < 8 && !s->z_eof) {
409 Byte *p = s->inbuf;
410 Byte *q = s->stream.next_in;
411 while (n--) { *p++ = *q++; };
412
413 n = s->stream.avail_in;
414 n += fread(p, 1, 8, s->file);
415 s->stream.next_in = s->inbuf;
416 }
417 /* check CRC and original size */
418 if (n < 8 ||
419 getLong(s->stream.next_in) != s->crc ||
420 getLong(s->stream.next_in + 4) != s->stream.total_out) {
421
422 s->z_err = Z_DATA_ERROR;
423 }
424 }
425 return destroy(file);
426}
427
428/* ===========================================================================
429 Returns the error message for the last error which occured on the
430 given compressed file. errnum is set to zlib error number. If an
431 error occured in the file system and not in the compression library,
432 errnum is set to Z_ERRNO and the application may consult errno
433 to get the exact error code.
434*/
435char* gzerror (file, errnum)
436 gzFile file;
437 int *errnum;
438{
439 char *m;
440 gz_stream *s = (gz_stream*)file;
441
442 if (s == NULL) {
443 *errnum = Z_STREAM_ERROR;
444 return z_errmsg[1-Z_STREAM_ERROR];
445 }
446 *errnum = s->z_err;
447 if (*errnum == Z_OK) return "";
448
449 m = *errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg;
450
451 if (m == NULL || *m == '\0') m = z_errmsg[1-s->z_err];
452
453 TRYFREE(s->msg);
454 s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
455 strcpy(s->msg, s->path);
456 strcat(s->msg, ": ");
457 strcat(s->msg, m);
458 return s->msg;
459}