comparison zlib/gzio.c @ 10:1040ca591f2e

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