rlm@1: /* gzio.c -- IO on .gz files rlm@1: * Copyright (C) 1995-2002 Jean-loup Gailly. rlm@1: * For conditions of distribution and use, see copyright notice in zlib.h rlm@1: * rlm@1: * Compile this file with -DNO_DEFLATE to avoid the compression code. rlm@1: */ rlm@1: rlm@1: /* memgzio.c - IO on .gz files in memory rlm@1: * Adapted from original gzio.c from zlib library by Forgotten rlm@1: */ rlm@1: rlm@1: /* @(#) $Id: memgzio.c,v 1.5 2006/06/06 21:04:20 spacy51 Exp $ */ rlm@1: rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: #include rlm@1: rlm@1: #include "memgzio.h" rlm@1: rlm@1: #ifndef local rlm@1: #define local static rlm@1: #endif rlm@1: rlm@1: #ifndef DEF_MEM_LEVEL rlm@1: # define DEF_MEM_LEVEL 8 rlm@1: #endif rlm@1: rlm@1: #ifndef OS_CODE rlm@1: #define OS_CODE 3 rlm@1: #endif rlm@1: rlm@1: #ifndef zmemcpy rlm@1: #define zmemcpy memcpy rlm@1: #endif rlm@1: rlm@1: /*struct internal_state {int dummy;};*/ /* for buggy compilers */ rlm@1: rlm@1: #ifndef Z_BUFSIZE rlm@1: # ifdef MAXSEG_64K rlm@1: # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */ rlm@1: # else rlm@1: # define Z_BUFSIZE 16384 rlm@1: # endif rlm@1: #endif rlm@1: #ifndef Z_PRINTF_BUFSIZE rlm@1: # define Z_PRINTF_BUFSIZE 4096 rlm@1: #endif rlm@1: rlm@1: #define ALLOC(size) malloc(size) rlm@1: #define TRYFREE(p) \ rlm@1: {if (p) \ rlm@1: free(p);} rlm@1: rlm@1: static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ rlm@1: rlm@1: /* gzip flag byte */ rlm@1: #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ rlm@1: #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ rlm@1: #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ rlm@1: #define ORIG_NAME 0x08 /* bit 3 set: original file name present */ rlm@1: #define COMMENT 0x10 /* bit 4 set: file comment present */ rlm@1: #define RESERVED 0xE0 /* bits 5..7: reserved */ rlm@1: rlm@1: typedef struct _MemFile rlm@1: { rlm@1: char *memory; rlm@1: char *next; rlm@1: int available; rlm@1: int error; rlm@1: char mode; rlm@1: } MEMFILE; rlm@1: rlm@1: typedef struct mem_stream rlm@1: { rlm@1: z_stream stream; rlm@1: int z_err; /* error code for last stream operation */ rlm@1: int z_eof; /* set if end of input file */ rlm@1: MEMFILE *file; /* memoru file */ rlm@1: Byte * inbuf; /* input buffer */ rlm@1: Byte * outbuf; /* output buffer */ rlm@1: uLong crc; /* crc32 of uncompressed data */ rlm@1: char * msg; /* error message */ rlm@1: int transparent; /* 1 if input file is not a .gz file */ rlm@1: char mode; /* 'w' or 'r' */ rlm@1: long startpos; /* start of compressed data in file (header skipped) */ rlm@1: } mem_stream; rlm@1: rlm@1: local gzFile gz_open OF((char *memory, const int available, const char *mode)); rlm@1: local int do_flush OF((gzFile file, int flush)); rlm@1: local int get_byte OF((mem_stream *s)); rlm@1: local void check_header OF((mem_stream *s)); rlm@1: local int destroy OF((mem_stream *s)); rlm@1: local void putLong OF((MEMFILE *file, uLong x)); rlm@1: local uLong getLong OF((mem_stream *s)); rlm@1: rlm@1: local MEMFILE *memOpen(char *memory, int available, char mode) rlm@1: { rlm@1: MEMFILE *f; rlm@1: rlm@1: if (available <= 8) rlm@1: return NULL; rlm@1: rlm@1: if (mode != 'w' && mode != 'r') rlm@1: return NULL; rlm@1: rlm@1: f = (MEMFILE *)malloc(sizeof(MEMFILE)); rlm@1: rlm@1: f->memory = memory; rlm@1: f->mode = mode; rlm@1: f->error = 0; rlm@1: rlm@1: if (mode == 'w') rlm@1: { rlm@1: f->available = available - 8; rlm@1: f->next = memory + 8; rlm@1: memory[0] = 'V'; rlm@1: memory[1] = 'B'; rlm@1: memory[2] = 'A'; rlm@1: memory[3] = ' '; rlm@1: *((int *)(memory+4)) = 0; rlm@1: } rlm@1: else rlm@1: { rlm@1: if (memory[0] != 'V' || memory[1] != 'B' || memory[2] != 'A' || rlm@1: memory[3] != ' ') rlm@1: { rlm@1: free(f); rlm@1: return NULL; rlm@1: } rlm@1: f->available = *((int *)(memory+4)); rlm@1: f->next = memory+8; rlm@1: } rlm@1: rlm@1: return f; rlm@1: } rlm@1: rlm@1: local size_t memWrite(const void *buffer, size_t size, size_t count, rlm@1: MEMFILE *file) rlm@1: { rlm@1: size_t total = size*count; rlm@1: rlm@1: if (file->mode != 'w') rlm@1: { rlm@1: file->error = 1; rlm@1: return 0; rlm@1: } rlm@1: rlm@1: if (total > (size_t)file->available) rlm@1: { rlm@1: total = file->available; rlm@1: } rlm@1: memcpy(file->next, buffer, total); rlm@1: file->available -= (int)total; rlm@1: file->next += total; rlm@1: return total; rlm@1: } rlm@1: rlm@1: local size_t memRead(void *buffer, size_t size, size_t count, rlm@1: MEMFILE *file) rlm@1: { rlm@1: size_t total = size*count; rlm@1: rlm@1: if (file->mode != 'r') rlm@1: { rlm@1: file->error = 1; rlm@1: return 0; rlm@1: } rlm@1: rlm@1: if (file->available == 0) rlm@1: return -1; rlm@1: rlm@1: if (total > (size_t)file->available) rlm@1: { rlm@1: total = file->available; rlm@1: } rlm@1: memcpy(buffer, file->next, total); rlm@1: file->available -= (int)total; rlm@1: file->next += total; rlm@1: return total; rlm@1: } rlm@1: rlm@1: local int memPutc(int c, MEMFILE *file) rlm@1: { rlm@1: if (file->mode != 'w') rlm@1: { rlm@1: file->error = 1; rlm@1: return -1; rlm@1: } rlm@1: rlm@1: if (file->available >= 1) rlm@1: { rlm@1: *file->next++ = c; rlm@1: file->available--; rlm@1: } rlm@1: else rlm@1: return -1; rlm@1: rlm@1: return c; rlm@1: } rlm@1: rlm@1: local long memTell(MEMFILE *f) rlm@1: { rlm@1: return (long)(f->next - f->memory) - 8; rlm@1: } rlm@1: rlm@1: local int memError(MEMFILE *f) rlm@1: { rlm@1: return f->error; rlm@1: } rlm@1: rlm@1: local int memClose(MEMFILE *f) rlm@1: { rlm@1: if (f->mode == 'w') rlm@1: { rlm@1: *((int *)(f->memory+4)) = memTell(f); rlm@1: } rlm@1: free(f); rlm@1: return 0; rlm@1: } rlm@1: rlm@1: local int memPrintf(MEMFILE *f, const char *format, ...) rlm@1: { rlm@1: char buffer[80]; rlm@1: va_list list; rlm@1: int len; rlm@1: rlm@1: va_start(list, format); rlm@1: len = vsprintf(buffer, format, list); rlm@1: va_end(list); rlm@1: rlm@1: return (int)memWrite(buffer, 1, len, f); rlm@1: } rlm@1: rlm@1: /* =========================================================================== rlm@1: Opens a gzip (.gz) file for reading or writing. The mode parameter rlm@1: is as in fopen ("rb" or "wb"). The file is given either by file descriptor rlm@1: or path name (if fd == -1). rlm@1: gz_open return NULL if the file could not be opened or if there was rlm@1: insufficient memory to allocate the (de)compression state; errno rlm@1: can be checked to distinguish the two cases (if errno is zero, the rlm@1: zlib error is Z_MEM_ERROR). rlm@1: */ rlm@1: local gzFile gz_open(memory, available, mode) rlm@1: char *memory; rlm@1: const int available; rlm@1: const char *mode; rlm@1: { rlm@1: int err; rlm@1: int level = Z_DEFAULT_COMPRESSION; /* compression level */ rlm@1: int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */ rlm@1: char * p = (char *)mode; rlm@1: mem_stream *s; rlm@1: char fmode[80]; /* copy of mode, without the compression level */ rlm@1: char * m = fmode; rlm@1: rlm@1: s = (mem_stream *)ALLOC(sizeof(mem_stream)); rlm@1: if (!s) rlm@1: return Z_NULL; rlm@1: rlm@1: s->stream.zalloc = (alloc_func)0; rlm@1: s->stream.zfree = (free_func)0; rlm@1: s->stream.opaque = (voidpf)0; rlm@1: s->stream.next_in = s->inbuf = Z_NULL; rlm@1: s->stream.next_out = s->outbuf = Z_NULL; rlm@1: s->stream.avail_in = s->stream.avail_out = 0; rlm@1: s->z_err = Z_OK; rlm@1: s->z_eof = 0; rlm@1: s->crc = crc32(0L, Z_NULL, 0); rlm@1: s->msg = NULL; rlm@1: s->transparent = 0; rlm@1: s->file = NULL; rlm@1: rlm@1: s->mode = '\0'; rlm@1: do rlm@1: { rlm@1: if (*p == 'r') rlm@1: s->mode = 'r'; rlm@1: if (*p == 'w' || *p == 'a') rlm@1: s->mode = 'w'; rlm@1: if (*p >= '0' && *p <= '9') rlm@1: { rlm@1: level = *p - '0'; rlm@1: } rlm@1: else if (*p == 'f') rlm@1: { rlm@1: strategy = Z_FILTERED; rlm@1: } rlm@1: else if (*p == 'h') rlm@1: { rlm@1: strategy = Z_HUFFMAN_ONLY; rlm@1: } rlm@1: else rlm@1: { rlm@1: *m++ = *p; /* copy the mode */ rlm@1: } rlm@1: } rlm@1: while (*p++ && m != fmode + sizeof(fmode)); rlm@1: if (s->mode == '\0') rlm@1: return destroy(s), (gzFile)Z_NULL; rlm@1: rlm@1: if (s->mode == 'w') rlm@1: { rlm@1: #ifdef NO_DEFLATE rlm@1: err = Z_STREAM_ERROR; rlm@1: #else rlm@1: err = deflateInit2(&(s->stream), level, rlm@1: Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy); rlm@1: /* windowBits is passed < 0 to suppress zlib header */ rlm@1: rlm@1: s->stream.next_out = s->outbuf = (Byte *)ALLOC(Z_BUFSIZE); rlm@1: #endif rlm@1: if (err != Z_OK || s->outbuf == Z_NULL) rlm@1: { rlm@1: return destroy(s), (gzFile)Z_NULL; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: s->stream.next_in = s->inbuf = (Byte *)ALLOC(Z_BUFSIZE); rlm@1: rlm@1: err = inflateInit2(&(s->stream), -MAX_WBITS); rlm@1: /* windowBits is passed < 0 to tell that there is no zlib header. rlm@1: * Note that in this case inflate *requires* an extra "dummy" byte rlm@1: * after the compressed stream in order to complete decompression and rlm@1: * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are rlm@1: * present after the compressed stream. rlm@1: */ rlm@1: if (err != Z_OK || s->inbuf == Z_NULL) rlm@1: { rlm@1: return destroy(s), (gzFile)Z_NULL; rlm@1: } rlm@1: } rlm@1: s->stream.avail_out = Z_BUFSIZE; rlm@1: rlm@1: errno = 0; rlm@1: s->file = memOpen(memory, available, s->mode); rlm@1: rlm@1: if (s->file == NULL) rlm@1: { rlm@1: return destroy(s), (gzFile)Z_NULL; rlm@1: } rlm@1: rlm@1: if (s->mode == 'w') rlm@1: { rlm@1: /* Write a very simple .gz header: rlm@1: */ rlm@1: memPrintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], rlm@1: Z_DEFLATED, 0 /*flags*/, 0, 0, 0, 0 /*time*/, 0 /*xflags*/, OS_CODE); rlm@1: s->startpos = 10L; rlm@1: /* We use 10L instead of ftell(s->file) to because ftell causes an rlm@1: * fflush on some systems. This version of the library doesn't use rlm@1: * startpos anyway in write mode, so this initialization is not rlm@1: * necessary. rlm@1: */ rlm@1: } rlm@1: else rlm@1: { rlm@1: check_header(s); /* skip the .gz header */ rlm@1: s->startpos = (memTell(s->file) - s->stream.avail_in); rlm@1: } rlm@1: rlm@1: return (gzFile)s; rlm@1: } rlm@1: rlm@1: /* =========================================================================== rlm@1: Opens a gzip (.gz) file for reading or writing. rlm@1: */ rlm@1: gzFile ZEXPORT memgzopen(memory, available, mode) rlm@1: char *memory; rlm@1: int available; rlm@1: const char *mode; rlm@1: { rlm@1: return gz_open(memory, available, mode); rlm@1: } rlm@1: rlm@1: /* =========================================================================== rlm@1: Read a byte from a mem_stream; update next_in and avail_in. Return EOF rlm@1: for end of file. rlm@1: IN assertion: the stream s has been sucessfully opened for reading. rlm@1: */ rlm@1: local int get_byte(s) rlm@1: mem_stream *s; rlm@1: { rlm@1: if (s->z_eof) rlm@1: return EOF; rlm@1: if (s->stream.avail_in == 0) rlm@1: { rlm@1: errno = 0; rlm@1: s->stream.avail_in = (uInt)memRead(s->inbuf, 1, Z_BUFSIZE, s->file); rlm@1: if (s->stream.avail_in == 0) rlm@1: { rlm@1: s->z_eof = 1; rlm@1: if (memError(s->file)) rlm@1: s->z_err = Z_ERRNO; rlm@1: return EOF; rlm@1: } rlm@1: s->stream.next_in = s->inbuf; rlm@1: } rlm@1: s->stream.avail_in--; rlm@1: return *(s->stream.next_in)++; rlm@1: } rlm@1: rlm@1: /* =========================================================================== rlm@1: Check the gzip header of a mem_stream opened for reading. Set the stream rlm@1: mode to transparent if the gzip magic header is not present; set s->err rlm@1: to Z_DATA_ERROR if the magic header is present but the rest of the header rlm@1: is incorrect. rlm@1: IN assertion: the stream s has already been created sucessfully; rlm@1: s->stream.avail_in is zero for the first time, but may be non-zero rlm@1: for concatenated .gz files. rlm@1: */ rlm@1: local void check_header(s) rlm@1: mem_stream *s; rlm@1: { rlm@1: int method; /* method byte */ rlm@1: int flags; /* flags byte */ rlm@1: uInt len; rlm@1: int c; rlm@1: rlm@1: /* Check the gzip magic header */ rlm@1: for (len = 0; len < 2; len++) rlm@1: { rlm@1: c = get_byte(s); rlm@1: if (c != gz_magic[len]) rlm@1: { rlm@1: if (len != 0) rlm@1: s->stream.avail_in++, s->stream.next_in--; rlm@1: if (c != EOF) rlm@1: { rlm@1: s->stream.avail_in++, s->stream.next_in--; rlm@1: s->transparent = 1; rlm@1: } rlm@1: s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; rlm@1: return; rlm@1: } rlm@1: } rlm@1: method = get_byte(s); rlm@1: flags = get_byte(s); rlm@1: if (method != Z_DEFLATED || (flags & RESERVED) != 0) rlm@1: { rlm@1: s->z_err = Z_DATA_ERROR; rlm@1: return; rlm@1: } rlm@1: rlm@1: /* Discard time, xflags and OS code: */ rlm@1: for (len = 0; len < 6; len++) rlm@1: (void)get_byte(s); rlm@1: rlm@1: if ((flags & EXTRA_FIELD) != 0) /* skip the extra field */ rlm@1: { rlm@1: len = (uInt)get_byte(s); rlm@1: len += ((uInt)get_byte(s))<<8; rlm@1: /* len is garbage if EOF but the loop below will quit anyway */ rlm@1: while (len-- != 0 && get_byte(s) != EOF) rlm@1: ; rlm@1: } rlm@1: if ((flags & ORIG_NAME) != 0) /* skip the original file name */ rlm@1: { rlm@1: while ((c = get_byte(s)) != 0 && c != EOF) rlm@1: ; rlm@1: } rlm@1: if ((flags & COMMENT) != 0) /* skip the .gz file comment */ rlm@1: { rlm@1: while ((c = get_byte(s)) != 0 && c != EOF) rlm@1: ; rlm@1: } rlm@1: if ((flags & HEAD_CRC) != 0) /* skip the header crc */ rlm@1: { rlm@1: for (len = 0; len < 2; len++) rlm@1: (void)get_byte(s); rlm@1: } rlm@1: s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; rlm@1: } rlm@1: rlm@1: /* =========================================================================== rlm@1: * Cleanup then free the given mem_stream. Return a zlib error code. rlm@1: Try freeing in the reverse order of allocations. rlm@1: */ rlm@1: local int destroy(s) rlm@1: mem_stream *s; rlm@1: { rlm@1: int err = Z_OK; rlm@1: rlm@1: if (!s) rlm@1: return Z_STREAM_ERROR; rlm@1: rlm@1: TRYFREE(s->msg); rlm@1: rlm@1: if (s->stream.state != NULL) rlm@1: { rlm@1: if (s->mode == 'w') rlm@1: { rlm@1: #ifdef NO_DEFLATE rlm@1: err = Z_STREAM_ERROR; rlm@1: #else rlm@1: err = deflateEnd(&(s->stream)); rlm@1: #endif rlm@1: } rlm@1: else if (s->mode == 'r') rlm@1: { rlm@1: err = inflateEnd(&(s->stream)); rlm@1: } rlm@1: } rlm@1: if (s->file != NULL && memClose(s->file)) rlm@1: { rlm@1: #ifdef ESPIPE rlm@1: if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */ rlm@1: #endif rlm@1: err = Z_ERRNO; rlm@1: } rlm@1: if (s->z_err < 0) rlm@1: err = s->z_err; rlm@1: rlm@1: TRYFREE(s->inbuf); rlm@1: TRYFREE(s->outbuf); rlm@1: TRYFREE(s); rlm@1: return err; rlm@1: } rlm@1: rlm@1: /* =========================================================================== rlm@1: Reads the given number of uncompressed bytes from the compressed file. rlm@1: gzread returns the number of bytes actually read (0 for end of file). rlm@1: */ rlm@1: int ZEXPORT memgzread(file, buf, len) rlm@1: gzFile file; rlm@1: voidp buf; rlm@1: unsigned len; rlm@1: { rlm@1: mem_stream *s = (mem_stream *)file; rlm@1: Bytef * start = (Bytef *)buf; /* starting point for crc computation */ rlm@1: Byte * next_out; /* == stream.next_out but not forced far (for MSDOS) */ rlm@1: rlm@1: if (s == NULL || s->mode != 'r') rlm@1: return Z_STREAM_ERROR; rlm@1: rlm@1: if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) rlm@1: return -1; rlm@1: if (s->z_err == Z_STREAM_END) rlm@1: return 0; /* EOF */ rlm@1: rlm@1: next_out = (Byte *)buf; rlm@1: s->stream.next_out = (Bytef *)buf; rlm@1: s->stream.avail_out = len; rlm@1: rlm@1: while (s->stream.avail_out != 0) rlm@1: { rlm@1: if (s->transparent) rlm@1: { rlm@1: /* Copy first the lookahead bytes: */ rlm@1: uInt n = s->stream.avail_in; rlm@1: if (n > s->stream.avail_out) rlm@1: n = s->stream.avail_out; rlm@1: if (n > 0) rlm@1: { rlm@1: zmemcpy(s->stream.next_out, s->stream.next_in, n); rlm@1: next_out += n; rlm@1: s->stream.next_out = next_out; rlm@1: s->stream.next_in += n; rlm@1: s->stream.avail_out -= n; rlm@1: s->stream.avail_in -= n; rlm@1: } rlm@1: if (s->stream.avail_out > 0) rlm@1: { rlm@1: s->stream.avail_out -= (uInt)memRead(next_out, 1, s->stream.avail_out, s->file); rlm@1: } rlm@1: len -= s->stream.avail_out; rlm@1: s->stream.total_in += (uLong)len; rlm@1: s->stream.total_out += (uLong)len; rlm@1: if (len == 0) rlm@1: s->z_eof = 1; rlm@1: return (int)len; rlm@1: } rlm@1: if (s->stream.avail_in == 0 && !s->z_eof) rlm@1: { rlm@1: errno = 0; rlm@1: s->stream.avail_in = (uInt)memRead(s->inbuf, 1, Z_BUFSIZE, s->file); rlm@1: if (s->stream.avail_in == 0) rlm@1: { rlm@1: s->z_eof = 1; rlm@1: if (memError(s->file)) rlm@1: { rlm@1: s->z_err = Z_ERRNO; rlm@1: break; rlm@1: } rlm@1: } rlm@1: s->stream.next_in = s->inbuf; rlm@1: } rlm@1: s->z_err = inflate(&(s->stream), Z_NO_FLUSH); rlm@1: rlm@1: if (s->z_err == Z_STREAM_END) rlm@1: { rlm@1: /* Check CRC and original size */ rlm@1: s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); rlm@1: start = s->stream.next_out; rlm@1: rlm@1: if (getLong(s) != s->crc) rlm@1: { rlm@1: s->z_err = Z_DATA_ERROR; rlm@1: } rlm@1: else rlm@1: { rlm@1: (void)getLong(s); rlm@1: /* The uncompressed length returned by above getlong() may rlm@1: * be different from s->stream.total_out) in case of rlm@1: * concatenated .gz files. Check for such files: rlm@1: */ rlm@1: check_header(s); rlm@1: if (s->z_err == Z_OK) rlm@1: { rlm@1: uLong total_in = s->stream.total_in; rlm@1: uLong total_out = s->stream.total_out; rlm@1: rlm@1: inflateReset(&(s->stream)); rlm@1: s->stream.total_in = total_in; rlm@1: s->stream.total_out = total_out; rlm@1: s->crc = crc32(0L, Z_NULL, 0); rlm@1: } rlm@1: } rlm@1: } rlm@1: if (s->z_err != Z_OK || s->z_eof) rlm@1: break; rlm@1: } rlm@1: s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); rlm@1: rlm@1: return (int)(len - s->stream.avail_out); rlm@1: } rlm@1: rlm@1: #ifndef NO_DEFLATE rlm@1: /* =========================================================================== rlm@1: Writes the given number of uncompressed bytes into the compressed file. rlm@1: gzwrite returns the number of bytes actually written (0 in case of error). rlm@1: */ rlm@1: int ZEXPORT memgzwrite(file, buf, len) rlm@1: gzFile file; rlm@1: const voidp buf; rlm@1: unsigned len; rlm@1: { rlm@1: mem_stream *s = (mem_stream *)file; rlm@1: rlm@1: if (s == NULL || s->mode != 'w') rlm@1: return Z_STREAM_ERROR; rlm@1: rlm@1: s->stream.next_in = (Bytef *)buf; rlm@1: s->stream.avail_in = len; rlm@1: rlm@1: while (s->stream.avail_in != 0) rlm@1: { rlm@1: if (s->stream.avail_out == 0) rlm@1: { rlm@1: s->stream.next_out = s->outbuf; rlm@1: if (memWrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) rlm@1: { rlm@1: s->z_err = Z_ERRNO; rlm@1: break; rlm@1: } rlm@1: s->stream.avail_out = Z_BUFSIZE; rlm@1: } rlm@1: s->z_err = deflate(&(s->stream), Z_NO_FLUSH); rlm@1: if (s->z_err != Z_OK) rlm@1: break; rlm@1: } rlm@1: s->crc = crc32(s->crc, (const Bytef *)buf, len); rlm@1: rlm@1: return (int)(len - s->stream.avail_in); rlm@1: } rlm@1: #endif rlm@1: /* =========================================================================== rlm@1: Flushes all pending output into the compressed file. The parameter rlm@1: flush is as in the deflate() function. rlm@1: */ rlm@1: local int do_flush(file, flush) rlm@1: gzFile file; rlm@1: int flush; rlm@1: { rlm@1: uInt len; rlm@1: int done = 0; rlm@1: mem_stream *s = (mem_stream *)file; rlm@1: rlm@1: if (s == NULL || s->mode != 'w') rlm@1: return Z_STREAM_ERROR; rlm@1: rlm@1: s->stream.avail_in = 0; /* should be zero already anyway */ rlm@1: rlm@1: for (;;) rlm@1: { rlm@1: len = Z_BUFSIZE - s->stream.avail_out; rlm@1: rlm@1: if (len != 0) rlm@1: { rlm@1: if ((uInt)memWrite(s->outbuf, 1, len, s->file) != len) rlm@1: { rlm@1: s->z_err = Z_ERRNO; rlm@1: return Z_ERRNO; rlm@1: } rlm@1: s->stream.next_out = s->outbuf; rlm@1: s->stream.avail_out = Z_BUFSIZE; rlm@1: } rlm@1: if (done) rlm@1: break; rlm@1: s->z_err = deflate(&(s->stream), flush); rlm@1: rlm@1: /* Ignore the second of two consecutive flushes: */ rlm@1: if (len == 0 && s->z_err == Z_BUF_ERROR) rlm@1: s->z_err = Z_OK; rlm@1: rlm@1: /* deflate has finished flushing only when it hasn't used up rlm@1: * all the available space in the output buffer: rlm@1: */ rlm@1: done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); rlm@1: rlm@1: if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) rlm@1: break; rlm@1: } rlm@1: return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; rlm@1: } rlm@1: rlm@1: /* =========================================================================== rlm@1: Outputs a long in LSB order to the given file rlm@1: */ rlm@1: local void putLong(file, x) rlm@1: MEMFILE *file; rlm@1: uLong x; rlm@1: { rlm@1: int n; rlm@1: for (n = 0; n < 4; n++) rlm@1: { rlm@1: memPutc((int)(x & 0xff), file); rlm@1: x >>= 8; rlm@1: } rlm@1: } rlm@1: rlm@1: /* =========================================================================== rlm@1: Reads a long in LSB order from the given mem_stream. Sets z_err in case rlm@1: of error. rlm@1: */ rlm@1: local uLong getLong(s) rlm@1: mem_stream *s; rlm@1: { rlm@1: uLong x = (uLong)get_byte(s); rlm@1: int c; rlm@1: rlm@1: x += ((uLong)get_byte(s))<<8; rlm@1: x += ((uLong)get_byte(s))<<16; rlm@1: c = get_byte(s); rlm@1: if (c == EOF) rlm@1: s->z_err = Z_DATA_ERROR; rlm@1: x += ((uLong)c)<<24; rlm@1: return x; rlm@1: } rlm@1: rlm@1: /* =========================================================================== rlm@1: Flushes all pending output if necessary, closes the compressed file rlm@1: and deallocates all the (de)compression state. rlm@1: */ rlm@1: int ZEXPORT memgzclose(file) rlm@1: gzFile file; rlm@1: { rlm@1: int err; rlm@1: mem_stream *s = (mem_stream *)file; rlm@1: rlm@1: if (s == NULL) rlm@1: return Z_STREAM_ERROR; rlm@1: rlm@1: if (s->mode == 'w') rlm@1: { rlm@1: #ifdef NO_DEFLATE rlm@1: return Z_STREAM_ERROR; rlm@1: #else rlm@1: err = do_flush(file, Z_FINISH); rlm@1: if (err != Z_OK) rlm@1: return destroy((mem_stream *)file); rlm@1: rlm@1: putLong(s->file, s->crc); rlm@1: putLong(s->file, s->stream.total_in); rlm@1: #endif rlm@1: } rlm@1: return destroy((mem_stream *)file); rlm@1: } rlm@1: rlm@1: long ZEXPORT memtell(file) rlm@1: gzFile file; rlm@1: { rlm@1: mem_stream *s = (mem_stream *)file; rlm@1: rlm@1: if (s == NULL) rlm@1: return Z_STREAM_ERROR; rlm@1: rlm@1: return memTell(s->file); rlm@1: }