comparison zlib/gzio.c @ 3:5a977ccbc7a9 default tip

Empty changelog
author darius
date Sat, 06 Dec 1997 05:41:29 +0000
parents
children
comparison
equal deleted inserted replaced
2:fba0b6e6cdc7 3:5a977ccbc7a9
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 }