1 /* gzio.c -- IO on .gz files
2 * Copyright (C) 1995-2002 Jean-loup Gailly.
3 * For conditions of distribution and use, see copyright notice in zlib.h
5 * Compile this file with -DNO_DEFLATE to avoid the compression code.
8 /* memgzio.c - IO on .gz files in memory
9 * Adapted from original gzio.c from zlib library by Forgotten
12 /* @(#) $Id: memgzio.c,v 1.5 2006/06/06 21:04:20 spacy51 Exp $ */
20 /*struct internal_state {int dummy;};*/ /* for buggy compilers */
24 # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
26 # define Z_BUFSIZE 16384
29 #ifndef Z_PRINTF_BUFSIZE
30 # define Z_PRINTF_BUFSIZE 4096
33 #define ALLOC(size) malloc(size)
34 #define TRYFREE(p) {if (p) free(p);}
36 static int gz_magic
[2] = {0x1f, 0x8b}; /* gzip magic header */
39 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
40 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
41 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
42 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
43 #define COMMENT 0x10 /* bit 4 set: file comment present */
44 #define RESERVED 0xE0 /* bits 5..7: reserved */
46 typedef struct _MemFile
{
54 typedef struct mem_stream
{
56 int z_err
; /* error code for last stream operation */
57 int z_eof
; /* set if end of input file */
58 MEMFILE
*file
; /* memoru file */
59 Byte
*inbuf
; /* input buffer */
60 Byte
*outbuf
; /* output buffer */
61 uLong crc
; /* crc32 of uncompressed data */
62 char *msg
; /* error message */
63 int transparent
; /* 1 if input file is not a .gz file */
64 char mode
; /* 'w' or 'r' */
65 long startpos
; /* start of compressed data in file (header skipped) */
69 local gzFile gz_open
OF((char *memory
, const int available
, const char *mode
));
70 local
int do_flush
OF((gzFile file
, int flush
));
71 local
int get_byte
OF((mem_stream
*s
));
72 local
void check_header
OF((mem_stream
*s
));
73 local
int destroy
OF((mem_stream
*s
));
74 local
void putLong
OF((MEMFILE
*file
, uLong x
));
75 local uLong getLong
OF((mem_stream
*s
));
77 local MEMFILE
*memOpen(char *memory
, int available
, char mode
)
84 if(mode
!= 'w' && mode
!= 'r')
87 f
= (MEMFILE
*)malloc(sizeof(MEMFILE
));
94 f
->available
= available
- 8;
100 *((int *)(memory
+4)) = 0;
102 if(memory
[0] != 'V' || memory
[1] != 'B' || memory
[2] != 'A' ||
107 f
->available
= *((int *)(memory
+4));
114 local
size_t memWrite(const void *buffer
, size_t size
, size_t count
,
117 size_t total
= size
*count
;
119 if(file
->mode
!= 'w') {
124 if(total
> (size_t)file
->available
) {
125 total
= file
->available
;
127 memcpy(file
->next
, buffer
, total
);
128 file
->available
-= (int)total
;
133 local
size_t memRead(void *buffer
, size_t size
, size_t count
,
136 size_t total
= size
*count
;
138 if(file
->mode
!= 'r') {
143 if(file
->available
== 0)
146 if(total
> (size_t)file
->available
) {
147 total
= file
->available
;
149 memcpy(buffer
, file
->next
, total
);
150 file
->available
-= (int)total
;
155 local
int memPutc(int c
, MEMFILE
*file
)
157 if(file
->mode
!= 'w') {
162 if(file
->available
>= 1) {
171 local
long memTell(MEMFILE
*f
)
173 return (long)(f
->next
- f
->memory
) - 8;
176 local
int memError(MEMFILE
*f
)
181 local
int memClose(MEMFILE
*f
)
184 *((int *)(f
->memory
+4)) = memTell(f
);
190 local
int memPrintf(MEMFILE
*f
, const char *format
, ...)
196 va_start(list
, format
);
197 len
= vsprintf(buffer
, format
, list
);
200 return (int)memWrite(buffer
, 1, len
, f
);
203 /* ===========================================================================
204 Opens a gzip (.gz) file for reading or writing. The mode parameter
205 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
206 or path name (if fd == -1).
207 gz_open return NULL if the file could not be opened or if there was
208 insufficient memory to allocate the (de)compression state; errno
209 can be checked to distinguish the two cases (if errno is zero, the
210 zlib error is Z_MEM_ERROR).
212 local gzFile
gz_open (memory
, available
, mode
)
218 int level
= Z_DEFAULT_COMPRESSION
; /* compression level */
219 int strategy
= Z_DEFAULT_STRATEGY
; /* compression strategy */
220 char *p
= (char*)mode
;
222 char fmode
[80]; /* copy of mode, without the compression level */
225 s
= (mem_stream
*)ALLOC(sizeof(mem_stream
));
226 if (!s
) return Z_NULL
;
228 s
->stream
.zalloc
= (alloc_func
)0;
229 s
->stream
.zfree
= (free_func
)0;
230 s
->stream
.opaque
= (voidpf
)0;
231 s
->stream
.next_in
= s
->inbuf
= Z_NULL
;
232 s
->stream
.next_out
= s
->outbuf
= Z_NULL
;
233 s
->stream
.avail_in
= s
->stream
.avail_out
= 0;
236 s
->crc
= crc32(0L, Z_NULL
, 0);
243 if (*p
== 'r') s
->mode
= 'r';
244 if (*p
== 'w' || *p
== 'a') s
->mode
= 'w';
245 if (*p
>= '0' && *p
<= '9') {
247 } else if (*p
== 'f') {
248 strategy
= Z_FILTERED
;
249 } else if (*p
== 'h') {
250 strategy
= Z_HUFFMAN_ONLY
;
252 *m
++ = *p
; /* copy the mode */
254 } while (*p
++ && m
!= fmode
+ sizeof(fmode
));
255 if (s
->mode
== '\0') return destroy(s
), (gzFile
)Z_NULL
;
257 if (s
->mode
== 'w') {
259 err
= Z_STREAM_ERROR
;
261 err
= deflateInit2(&(s
->stream
), level
,
262 Z_DEFLATED
, -MAX_WBITS
, DEF_MEM_LEVEL
, strategy
);
263 /* windowBits is passed < 0 to suppress zlib header */
265 s
->stream
.next_out
= s
->outbuf
= (Byte
*)ALLOC(Z_BUFSIZE
);
267 if (err
!= Z_OK
|| s
->outbuf
== Z_NULL
) {
268 return destroy(s
), (gzFile
)Z_NULL
;
271 s
->stream
.next_in
= s
->inbuf
= (Byte
*)ALLOC(Z_BUFSIZE
);
273 err
= inflateInit2(&(s
->stream
), -MAX_WBITS
);
274 /* windowBits is passed < 0 to tell that there is no zlib header.
275 * Note that in this case inflate *requires* an extra "dummy" byte
276 * after the compressed stream in order to complete decompression and
277 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
278 * present after the compressed stream.
280 if (err
!= Z_OK
|| s
->inbuf
== Z_NULL
) {
281 return destroy(s
), (gzFile
)Z_NULL
;
284 s
->stream
.avail_out
= Z_BUFSIZE
;
287 s
->file
= memOpen(memory
, available
, s
->mode
);
289 if (s
->file
== NULL
) {
290 return destroy(s
), (gzFile
)Z_NULL
;
293 if (s
->mode
== 'w') {
294 /* Write a very simple .gz header:
296 memPrintf(s
->file
, "%c%c%c%c%c%c%c%c%c%c", gz_magic
[0], gz_magic
[1],
297 Z_DEFLATED
, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE
);
299 /* We use 10L instead of ftell(s->file) to because ftell causes an
300 * fflush on some systems. This version of the library doesn't use
301 * startpos anyway in write mode, so this initialization is not
305 check_header(s
); /* skip the .gz header */
306 s
->startpos
= (memTell(s
->file
) - s
->stream
.avail_in
);
312 /* ===========================================================================
313 Opens a gzip (.gz) file for reading or writing.
315 gzFile ZEXPORT
memgzopen (memory
, available
, mode
)
320 return gz_open (memory
, available
, mode
);
323 /* ===========================================================================
324 Read a byte from a mem_stream; update next_in and avail_in. Return EOF
326 IN assertion: the stream s has been sucessfully opened for reading.
328 local
int get_byte(s
)
331 if (s
->z_eof
) return EOF
;
332 if (s
->stream
.avail_in
== 0) {
334 s
->stream
.avail_in
= (uInt
)memRead(s
->inbuf
, 1, Z_BUFSIZE
, s
->file
);
335 if (s
->stream
.avail_in
== 0) {
337 if (memError(s
->file
)) s
->z_err
= Z_ERRNO
;
340 s
->stream
.next_in
= s
->inbuf
;
342 s
->stream
.avail_in
--;
343 return *(s
->stream
.next_in
)++;
346 /* ===========================================================================
347 Check the gzip header of a mem_stream opened for reading. Set the stream
348 mode to transparent if the gzip magic header is not present; set s->err
349 to Z_DATA_ERROR if the magic header is present but the rest of the header
351 IN assertion: the stream s has already been created sucessfully;
352 s->stream.avail_in is zero for the first time, but may be non-zero
353 for concatenated .gz files.
355 local
void check_header(s
)
358 int method
; /* method byte */
359 int flags
; /* flags byte */
363 /* Check the gzip magic header */
364 for (len
= 0; len
< 2; len
++) {
366 if (c
!= gz_magic
[len
]) {
367 if (len
!= 0) s
->stream
.avail_in
++, s
->stream
.next_in
--;
369 s
->stream
.avail_in
++, s
->stream
.next_in
--;
372 s
->z_err
= s
->stream
.avail_in
!= 0 ? Z_OK
: Z_STREAM_END
;
376 method
= get_byte(s
);
378 if (method
!= Z_DEFLATED
|| (flags
& RESERVED
) != 0) {
379 s
->z_err
= Z_DATA_ERROR
;
383 /* Discard time, xflags and OS code: */
384 for (len
= 0; len
< 6; len
++) (void)get_byte(s
);
386 if ((flags
& EXTRA_FIELD
) != 0) { /* skip the extra field */
387 len
= (uInt
)get_byte(s
);
388 len
+= ((uInt
)get_byte(s
))<<8;
389 /* len is garbage if EOF but the loop below will quit anyway */
390 while (len
-- != 0 && get_byte(s
) != EOF
) ;
392 if ((flags
& ORIG_NAME
) != 0) { /* skip the original file name */
393 while ((c
= get_byte(s
)) != 0 && c
!= EOF
) ;
395 if ((flags
& COMMENT
) != 0) { /* skip the .gz file comment */
396 while ((c
= get_byte(s
)) != 0 && c
!= EOF
) ;
398 if ((flags
& HEAD_CRC
) != 0) { /* skip the header crc */
399 for (len
= 0; len
< 2; len
++) (void)get_byte(s
);
401 s
->z_err
= s
->z_eof
? Z_DATA_ERROR
: Z_OK
;
404 /* ===========================================================================
405 * Cleanup then free the given mem_stream. Return a zlib error code.
406 Try freeing in the reverse order of allocations.
408 local
int destroy (s
)
413 if (!s
) return Z_STREAM_ERROR
;
417 if (s
->stream
.state
!= NULL
) {
418 if (s
->mode
== 'w') {
420 err
= Z_STREAM_ERROR
;
422 err
= deflateEnd(&(s
->stream
));
424 } else if (s
->mode
== 'r') {
425 err
= inflateEnd(&(s
->stream
));
428 if (s
->file
!= NULL
&& memClose(s
->file
)) {
430 if (errno
!= ESPIPE
) /* fclose is broken for pipes in HP/UX */
434 if (s
->z_err
< 0) err
= s
->z_err
;
442 /* ===========================================================================
443 Reads the given number of uncompressed bytes from the compressed file.
444 gzread returns the number of bytes actually read (0 for end of file).
446 int ZEXPORT
memgzread (file
, buf
, len
)
451 mem_stream
*s
= (mem_stream
*)file
;
452 Bytef
*start
= (Bytef
*)buf
; /* starting point for crc computation */
453 Byte
*next_out
; /* == stream.next_out but not forced far (for MSDOS) */
455 if (s
== NULL
|| s
->mode
!= 'r') return Z_STREAM_ERROR
;
457 if (s
->z_err
== Z_DATA_ERROR
|| s
->z_err
== Z_ERRNO
) return -1;
458 if (s
->z_err
== Z_STREAM_END
) return 0; /* EOF */
460 next_out
= (Byte
*)buf
;
461 s
->stream
.next_out
= (Bytef
*)buf
;
462 s
->stream
.avail_out
= len
;
464 while (s
->stream
.avail_out
!= 0) {
466 if (s
->transparent
) {
467 /* Copy first the lookahead bytes: */
468 uInt n
= s
->stream
.avail_in
;
469 if (n
> s
->stream
.avail_out
) n
= s
->stream
.avail_out
;
471 zmemcpy(s
->stream
.next_out
, s
->stream
.next_in
, n
);
473 s
->stream
.next_out
= next_out
;
474 s
->stream
.next_in
+= n
;
475 s
->stream
.avail_out
-= n
;
476 s
->stream
.avail_in
-= n
;
478 if (s
->stream
.avail_out
> 0) {
479 s
->stream
.avail_out
-= (uInt
)memRead(next_out
, 1, s
->stream
.avail_out
, s
->file
);
481 len
-= s
->stream
.avail_out
;
482 s
->stream
.total_in
+= (uLong
)len
;
483 s
->stream
.total_out
+= (uLong
)len
;
484 if (len
== 0) s
->z_eof
= 1;
487 if (s
->stream
.avail_in
== 0 && !s
->z_eof
) {
490 s
->stream
.avail_in
= (uInt
)memRead(s
->inbuf
, 1, Z_BUFSIZE
, s
->file
);
491 if (s
->stream
.avail_in
== 0) {
493 if (memError(s
->file
)) {
498 s
->stream
.next_in
= s
->inbuf
;
500 s
->z_err
= inflate(&(s
->stream
), Z_NO_FLUSH
);
502 if (s
->z_err
== Z_STREAM_END
) {
503 /* Check CRC and original size */
504 s
->crc
= crc32(s
->crc
, start
, (uInt
)(s
->stream
.next_out
- start
));
505 start
= s
->stream
.next_out
;
507 if (getLong(s
) != s
->crc
) {
508 s
->z_err
= Z_DATA_ERROR
;
511 /* The uncompressed length returned by above getlong() may
512 * be different from s->stream.total_out) in case of
513 * concatenated .gz files. Check for such files:
516 if (s
->z_err
== Z_OK
) {
517 uLong total_in
= s
->stream
.total_in
;
518 uLong total_out
= s
->stream
.total_out
;
520 inflateReset(&(s
->stream
));
521 s
->stream
.total_in
= total_in
;
522 s
->stream
.total_out
= total_out
;
523 s
->crc
= crc32(0L, Z_NULL
, 0);
527 if (s
->z_err
!= Z_OK
|| s
->z_eof
) break;
529 s
->crc
= crc32(s
->crc
, start
, (uInt
)(s
->stream
.next_out
- start
));
531 return (int)(len
- s
->stream
.avail_out
);
536 /* ===========================================================================
537 Writes the given number of uncompressed bytes into the compressed file.
538 gzwrite returns the number of bytes actually written (0 in case of error).
540 int ZEXPORT
memgzwrite (file
, buf
, len
)
545 mem_stream
*s
= (mem_stream
*)file
;
547 if (s
== NULL
|| s
->mode
!= 'w') return Z_STREAM_ERROR
;
549 s
->stream
.next_in
= (Bytef
*)buf
;
550 s
->stream
.avail_in
= len
;
552 while (s
->stream
.avail_in
!= 0) {
554 if (s
->stream
.avail_out
== 0) {
556 s
->stream
.next_out
= s
->outbuf
;
557 if (memWrite(s
->outbuf
, 1, Z_BUFSIZE
, s
->file
) != Z_BUFSIZE
) {
561 s
->stream
.avail_out
= Z_BUFSIZE
;
563 s
->z_err
= deflate(&(s
->stream
), Z_NO_FLUSH
);
564 if (s
->z_err
!= Z_OK
) break;
566 s
->crc
= crc32(s
->crc
, (const Bytef
*)buf
, len
);
568 return (int)(len
- s
->stream
.avail_in
);
571 /* ===========================================================================
572 Flushes all pending output into the compressed file. The parameter
573 flush is as in the deflate() function.
575 local
int do_flush (file
, flush
)
581 mem_stream
*s
= (mem_stream
*)file
;
583 if (s
== NULL
|| s
->mode
!= 'w') return Z_STREAM_ERROR
;
585 s
->stream
.avail_in
= 0; /* should be zero already anyway */
588 len
= Z_BUFSIZE
- s
->stream
.avail_out
;
591 if ((uInt
)memWrite(s
->outbuf
, 1, len
, s
->file
) != len
) {
595 s
->stream
.next_out
= s
->outbuf
;
596 s
->stream
.avail_out
= Z_BUFSIZE
;
599 s
->z_err
= deflate(&(s
->stream
), flush
);
601 /* Ignore the second of two consecutive flushes: */
602 if (len
== 0 && s
->z_err
== Z_BUF_ERROR
) s
->z_err
= Z_OK
;
604 /* deflate has finished flushing only when it hasn't used up
605 * all the available space in the output buffer:
607 done
= (s
->stream
.avail_out
!= 0 || s
->z_err
== Z_STREAM_END
);
609 if (s
->z_err
!= Z_OK
&& s
->z_err
!= Z_STREAM_END
) break;
611 return s
->z_err
== Z_STREAM_END
? Z_OK
: s
->z_err
;
614 /* ===========================================================================
615 Outputs a long in LSB order to the given file
617 local
void putLong (file
, x
)
622 for (n
= 0; n
< 4; n
++) {
623 memPutc((int)(x
& 0xff), file
);
628 /* ===========================================================================
629 Reads a long in LSB order from the given mem_stream. Sets z_err in case
632 local uLong
getLong (s
)
635 uLong x
= (uLong
)get_byte(s
);
638 x
+= ((uLong
)get_byte(s
))<<8;
639 x
+= ((uLong
)get_byte(s
))<<16;
641 if (c
== EOF
) s
->z_err
= Z_DATA_ERROR
;
646 /* ===========================================================================
647 Flushes all pending output if necessary, closes the compressed file
648 and deallocates all the (de)compression state.
650 int ZEXPORT
memgzclose (file
)
654 mem_stream
*s
= (mem_stream
*)file
;
656 if (s
== NULL
) return Z_STREAM_ERROR
;
658 if (s
->mode
== 'w') {
660 return Z_STREAM_ERROR
;
662 err
= do_flush (file
, Z_FINISH
);
663 if (err
!= Z_OK
) return destroy((mem_stream
*)file
);
665 putLong (s
->file
, s
->crc
);
666 putLong (s
->file
, s
->stream
.total_in
);
669 return destroy((mem_stream
*)file
);
672 long ZEXPORT
memtell(file
)
675 mem_stream
*s
= (mem_stream
*)file
;
677 if (s
== NULL
) return Z_STREAM_ERROR
;
679 return memTell(s
->file
);