diff src/common/memgzio.c @ 1:f9f4f1b99eed

importing src directory
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:31:27 -0600
parents
children
line wrap: on
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/common/memgzio.c	Sat Mar 03 10:31:27 2012 -0600
     1.3 @@ -0,0 +1,791 @@
     1.4 +/* gzio.c -- IO on .gz files
     1.5 + * Copyright (C) 1995-2002 Jean-loup Gailly.
     1.6 + * For conditions of distribution and use, see copyright notice in zlib.h
     1.7 + *
     1.8 + * Compile this file with -DNO_DEFLATE to avoid the compression code.
     1.9 + */
    1.10 +
    1.11 +/* memgzio.c - IO on .gz files in memory
    1.12 + * Adapted from original gzio.c from zlib library by Forgotten
    1.13 + */
    1.14 +
    1.15 +/* @(#) $Id: memgzio.c,v 1.5 2006/06/06 21:04:20 spacy51 Exp $ */
    1.16 +
    1.17 +#include <stdio.h>
    1.18 +#include <stdarg.h>
    1.19 +#include <stdlib.h>
    1.20 +#include <string.h>
    1.21 +#include <errno.h>
    1.22 +
    1.23 +#include "memgzio.h"
    1.24 +
    1.25 +#ifndef local
    1.26 +#define local static
    1.27 +#endif
    1.28 +
    1.29 +#ifndef DEF_MEM_LEVEL
    1.30 +#  define DEF_MEM_LEVEL 8
    1.31 +#endif
    1.32 +
    1.33 +#ifndef OS_CODE
    1.34 +#define OS_CODE 3
    1.35 +#endif
    1.36 +
    1.37 +#ifndef zmemcpy
    1.38 +#define zmemcpy memcpy
    1.39 +#endif
    1.40 +
    1.41 +/*struct internal_state {int dummy;};*/ /* for buggy compilers */
    1.42 +
    1.43 +#ifndef Z_BUFSIZE
    1.44 +#  ifdef MAXSEG_64K
    1.45 +#    define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
    1.46 +#  else
    1.47 +#    define Z_BUFSIZE 16384
    1.48 +#  endif
    1.49 +#endif
    1.50 +#ifndef Z_PRINTF_BUFSIZE
    1.51 +#  define Z_PRINTF_BUFSIZE 4096
    1.52 +#endif
    1.53 +
    1.54 +#define ALLOC(size) malloc(size)
    1.55 +#define TRYFREE(p) \
    1.56 +	{if (p)                            \
    1.57 +		 free(p);}
    1.58 +
    1.59 +static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
    1.60 +
    1.61 +/* gzip flag byte */
    1.62 +#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
    1.63 +#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
    1.64 +#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
    1.65 +#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
    1.66 +#define COMMENT      0x10 /* bit 4 set: file comment present */
    1.67 +#define RESERVED     0xE0 /* bits 5..7: reserved */
    1.68 +
    1.69 +typedef struct _MemFile
    1.70 +{
    1.71 +	char *memory;
    1.72 +	char *next;
    1.73 +	int   available;
    1.74 +	int   error;
    1.75 +	char  mode;
    1.76 +} MEMFILE;
    1.77 +
    1.78 +typedef struct mem_stream
    1.79 +{
    1.80 +	z_stream stream;
    1.81 +	int      z_err;   /* error code for last stream operation */
    1.82 +	int      z_eof;   /* set if end of input file */
    1.83 +	MEMFILE *file;    /* memoru file */
    1.84 +	Byte *   inbuf;   /* input buffer */
    1.85 +	Byte *   outbuf;  /* output buffer */
    1.86 +	uLong    crc;     /* crc32 of uncompressed data */
    1.87 +	char *   msg;     /* error message */
    1.88 +	int      transparent; /* 1 if input file is not a .gz file */
    1.89 +	char     mode;    /* 'w' or 'r' */
    1.90 +	long     startpos; /* start of compressed data in file (header skipped) */
    1.91 +} mem_stream;
    1.92 +
    1.93 +local gzFile gz_open      OF((char *memory, const int available, const char *mode));
    1.94 +local int do_flush        OF((gzFile file, int flush));
    1.95 +local int get_byte     OF((mem_stream *s));
    1.96 +local void check_header OF((mem_stream *s));
    1.97 +local int destroy      OF((mem_stream *s));
    1.98 +local void putLong      OF((MEMFILE *file, uLong x));
    1.99 +local uLong getLong      OF((mem_stream *s));
   1.100 +
   1.101 +local MEMFILE *memOpen(char *memory, int available, char mode)
   1.102 +{
   1.103 +	MEMFILE *f;
   1.104 +
   1.105 +	if (available <= 8)
   1.106 +		return NULL;
   1.107 +
   1.108 +	if (mode != 'w' && mode != 'r')
   1.109 +		return NULL;
   1.110 +
   1.111 +	f = (MEMFILE *)malloc(sizeof(MEMFILE));
   1.112 +
   1.113 +	f->memory = memory;
   1.114 +	f->mode   = mode;
   1.115 +	f->error  = 0;
   1.116 +
   1.117 +	if (mode == 'w')
   1.118 +	{
   1.119 +		f->available         = available - 8;
   1.120 +		f->next              = memory + 8;
   1.121 +		memory[0]            = 'V';
   1.122 +		memory[1]            = 'B';
   1.123 +		memory[2]            = 'A';
   1.124 +		memory[3]            = ' ';
   1.125 +		*((int *)(memory+4)) = 0;
   1.126 +	}
   1.127 +	else
   1.128 +	{
   1.129 +		if (memory[0] != 'V' || memory[1] != 'B' || memory[2] != 'A' ||
   1.130 +		    memory[3] != ' ')
   1.131 +		{
   1.132 +			free(f);
   1.133 +			return NULL;
   1.134 +		}
   1.135 +		f->available = *((int *)(memory+4));
   1.136 +		f->next      = memory+8;
   1.137 +	}
   1.138 +
   1.139 +	return f;
   1.140 +}
   1.141 +
   1.142 +local size_t memWrite(const void *buffer, size_t size, size_t count,
   1.143 +                      MEMFILE *file)
   1.144 +{
   1.145 +	size_t total = size*count;
   1.146 +
   1.147 +	if (file->mode != 'w')
   1.148 +	{
   1.149 +		file->error = 1;
   1.150 +		return 0;
   1.151 +	}
   1.152 +
   1.153 +	if (total > (size_t)file->available)
   1.154 +	{
   1.155 +		total = file->available;
   1.156 +	}
   1.157 +	memcpy(file->next, buffer, total);
   1.158 +	file->available -= (int)total;
   1.159 +	file->next      += total;
   1.160 +	return total;
   1.161 +}
   1.162 +
   1.163 +local size_t memRead(void *buffer, size_t size, size_t count,
   1.164 +                     MEMFILE *file)
   1.165 +{
   1.166 +	size_t total = size*count;
   1.167 +
   1.168 +	if (file->mode != 'r')
   1.169 +	{
   1.170 +		file->error = 1;
   1.171 +		return 0;
   1.172 +	}
   1.173 +
   1.174 +	if (file->available == 0)
   1.175 +		return -1;
   1.176 +
   1.177 +	if (total > (size_t)file->available)
   1.178 +	{
   1.179 +		total = file->available;
   1.180 +	}
   1.181 +	memcpy(buffer, file->next, total);
   1.182 +	file->available -= (int)total;
   1.183 +	file->next      += total;
   1.184 +	return total;
   1.185 +}
   1.186 +
   1.187 +local int memPutc(int c, MEMFILE *file)
   1.188 +{
   1.189 +	if (file->mode != 'w')
   1.190 +	{
   1.191 +		file->error = 1;
   1.192 +		return -1;
   1.193 +	}
   1.194 +
   1.195 +	if (file->available >= 1)
   1.196 +	{
   1.197 +		*file->next++ = c;
   1.198 +		file->available--;
   1.199 +	}
   1.200 +	else
   1.201 +		return -1;
   1.202 +
   1.203 +	return c;
   1.204 +}
   1.205 +
   1.206 +local long memTell(MEMFILE *f)
   1.207 +{
   1.208 +	return (long)(f->next - f->memory) - 8;
   1.209 +}
   1.210 +
   1.211 +local int memError(MEMFILE *f)
   1.212 +{
   1.213 +	return f->error;
   1.214 +}
   1.215 +
   1.216 +local int memClose(MEMFILE *f)
   1.217 +{
   1.218 +	if (f->mode == 'w')
   1.219 +	{
   1.220 +		*((int *)(f->memory+4)) = memTell(f);
   1.221 +	}
   1.222 +	free(f);
   1.223 +	return 0;
   1.224 +}
   1.225 +
   1.226 +local int memPrintf(MEMFILE *f, const char *format, ...)
   1.227 +{
   1.228 +	char    buffer[80];
   1.229 +	va_list list;
   1.230 +	int     len;
   1.231 +
   1.232 +	va_start(list, format);
   1.233 +	len = vsprintf(buffer, format, list);
   1.234 +	va_end(list);
   1.235 +
   1.236 +	return (int)memWrite(buffer, 1, len, f);
   1.237 +}
   1.238 +
   1.239 +/* ===========================================================================
   1.240 +     Opens a gzip (.gz) file for reading or writing. The mode parameter
   1.241 +   is as in fopen ("rb" or "wb"). The file is given either by file descriptor
   1.242 +   or path name (if fd == -1).
   1.243 +     gz_open return NULL if the file could not be opened or if there was
   1.244 +   insufficient memory to allocate the (de)compression state; errno
   1.245 +   can be checked to distinguish the two cases (if errno is zero, the
   1.246 +   zlib error is Z_MEM_ERROR).
   1.247 + */
   1.248 +local gzFile gz_open(memory, available, mode)
   1.249 +char *memory;
   1.250 +const int   available;
   1.251 +const char *mode;
   1.252 +{
   1.253 +	int         err;
   1.254 +	int         level    = Z_DEFAULT_COMPRESSION; /* compression level */
   1.255 +	int         strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
   1.256 +	char *      p        = (char *)mode;
   1.257 +	mem_stream *s;
   1.258 +	char        fmode[80]; /* copy of mode, without the compression level */
   1.259 +	char *      m = fmode;
   1.260 +
   1.261 +	s = (mem_stream *)ALLOC(sizeof(mem_stream));
   1.262 +	if (!s)
   1.263 +		return Z_NULL;
   1.264 +
   1.265 +	s->stream.zalloc   = (alloc_func)0;
   1.266 +	s->stream.zfree    = (free_func)0;
   1.267 +	s->stream.opaque   = (voidpf)0;
   1.268 +	s->stream.next_in  = s->inbuf = Z_NULL;
   1.269 +	s->stream.next_out = s->outbuf = Z_NULL;
   1.270 +	s->stream.avail_in = s->stream.avail_out = 0;
   1.271 +	s->z_err           = Z_OK;
   1.272 +	s->z_eof           = 0;
   1.273 +	s->crc             = crc32(0L, Z_NULL, 0);
   1.274 +	s->msg             = NULL;
   1.275 +	s->transparent     = 0;
   1.276 +	s->file            = NULL;
   1.277 +
   1.278 +	s->mode = '\0';
   1.279 +	do
   1.280 +	{
   1.281 +		if (*p == 'r')
   1.282 +			s->mode = 'r';
   1.283 +		if (*p == 'w' || *p == 'a')
   1.284 +			s->mode = 'w';
   1.285 +		if (*p >= '0' && *p <= '9')
   1.286 +		{
   1.287 +			level = *p - '0';
   1.288 +		}
   1.289 +		else if (*p == 'f')
   1.290 +		{
   1.291 +			strategy = Z_FILTERED;
   1.292 +		}
   1.293 +		else if (*p == 'h')
   1.294 +		{
   1.295 +			strategy = Z_HUFFMAN_ONLY;
   1.296 +		}
   1.297 +		else
   1.298 +		{
   1.299 +			*m++ = *p; /* copy the mode */
   1.300 +		}
   1.301 +	}
   1.302 +	while (*p++ && m != fmode + sizeof(fmode));
   1.303 +	if (s->mode == '\0')
   1.304 +		return destroy(s), (gzFile)Z_NULL;
   1.305 +
   1.306 +	if (s->mode == 'w')
   1.307 +	{
   1.308 +#ifdef NO_DEFLATE
   1.309 +		err = Z_STREAM_ERROR;
   1.310 +#else
   1.311 +		err = deflateInit2(&(s->stream), level,
   1.312 +		                   Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
   1.313 +		/* windowBits is passed < 0 to suppress zlib header */
   1.314 +
   1.315 +		s->stream.next_out = s->outbuf = (Byte *)ALLOC(Z_BUFSIZE);
   1.316 +#endif
   1.317 +		if (err != Z_OK || s->outbuf == Z_NULL)
   1.318 +		{
   1.319 +			return destroy(s), (gzFile)Z_NULL;
   1.320 +		}
   1.321 +	}
   1.322 +	else
   1.323 +	{
   1.324 +		s->stream.next_in = s->inbuf = (Byte *)ALLOC(Z_BUFSIZE);
   1.325 +
   1.326 +		err = inflateInit2(&(s->stream), -MAX_WBITS);
   1.327 +		/* windowBits is passed < 0 to tell that there is no zlib header.
   1.328 +		 * Note that in this case inflate *requires* an extra "dummy" byte
   1.329 +		 * after the compressed stream in order to complete decompression and
   1.330 +		 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
   1.331 +		 * present after the compressed stream.
   1.332 +		 */
   1.333 +		if (err != Z_OK || s->inbuf == Z_NULL)
   1.334 +		{
   1.335 +			return destroy(s), (gzFile)Z_NULL;
   1.336 +		}
   1.337 +	}
   1.338 +	s->stream.avail_out = Z_BUFSIZE;
   1.339 +
   1.340 +	errno   = 0;
   1.341 +	s->file = memOpen(memory, available, s->mode);
   1.342 +
   1.343 +	if (s->file == NULL)
   1.344 +	{
   1.345 +		return destroy(s), (gzFile)Z_NULL;
   1.346 +	}
   1.347 +
   1.348 +	if (s->mode == 'w')
   1.349 +	{
   1.350 +		/* Write a very simple .gz header:
   1.351 +		 */
   1.352 +		memPrintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
   1.353 +		          Z_DEFLATED, 0 /*flags*/, 0, 0, 0, 0 /*time*/, 0 /*xflags*/, OS_CODE);
   1.354 +		s->startpos = 10L;
   1.355 +		/* We use 10L instead of ftell(s->file) to because ftell causes an
   1.356 +		 * fflush on some systems. This version of the library doesn't use
   1.357 +		 * startpos anyway in write mode, so this initialization is not
   1.358 +		 * necessary.
   1.359 +		 */
   1.360 +	}
   1.361 +	else
   1.362 +	{
   1.363 +		check_header(s); /* skip the .gz header */
   1.364 +		s->startpos = (memTell(s->file) - s->stream.avail_in);
   1.365 +	}
   1.366 +
   1.367 +	return (gzFile)s;
   1.368 +}
   1.369 +
   1.370 +/* ===========================================================================
   1.371 +     Opens a gzip (.gz) file for reading or writing.
   1.372 + */
   1.373 +gzFile ZEXPORT memgzopen(memory, available, mode)
   1.374 +char *memory;
   1.375 +int         available;
   1.376 +const char *mode;
   1.377 +{
   1.378 +	return gz_open(memory, available, mode);
   1.379 +}
   1.380 +
   1.381 +/* ===========================================================================
   1.382 +     Read a byte from a mem_stream; update next_in and avail_in. Return EOF
   1.383 +   for end of file.
   1.384 +   IN assertion: the stream s has been sucessfully opened for reading.
   1.385 + */
   1.386 +local int get_byte(s)
   1.387 +mem_stream *s;
   1.388 +{
   1.389 +	if (s->z_eof)
   1.390 +		return EOF;
   1.391 +	if (s->stream.avail_in == 0)
   1.392 +	{
   1.393 +		errno = 0;
   1.394 +		s->stream.avail_in = (uInt)memRead(s->inbuf, 1, Z_BUFSIZE, s->file);
   1.395 +		if (s->stream.avail_in == 0)
   1.396 +		{
   1.397 +			s->z_eof = 1;
   1.398 +			if (memError(s->file))
   1.399 +				s->z_err = Z_ERRNO;
   1.400 +			return EOF;
   1.401 +		}
   1.402 +		s->stream.next_in = s->inbuf;
   1.403 +	}
   1.404 +	s->stream.avail_in--;
   1.405 +	return *(s->stream.next_in)++;
   1.406 +}
   1.407 +
   1.408 +/* ===========================================================================
   1.409 +      Check the gzip header of a mem_stream opened for reading. Set the stream
   1.410 +    mode to transparent if the gzip magic header is not present; set s->err
   1.411 +    to Z_DATA_ERROR if the magic header is present but the rest of the header
   1.412 +    is incorrect.
   1.413 +    IN assertion: the stream s has already been created sucessfully;
   1.414 +       s->stream.avail_in is zero for the first time, but may be non-zero
   1.415 +       for concatenated .gz files.
   1.416 + */
   1.417 +local void check_header(s)
   1.418 +mem_stream *s;
   1.419 +{
   1.420 +	int  method; /* method byte */
   1.421 +	int  flags; /* flags byte */
   1.422 +	uInt len;
   1.423 +	int  c;
   1.424 +
   1.425 +	/* Check the gzip magic header */
   1.426 +	for (len = 0; len < 2; len++)
   1.427 +	{
   1.428 +		c = get_byte(s);
   1.429 +		if (c != gz_magic[len])
   1.430 +		{
   1.431 +			if (len != 0)
   1.432 +				s->stream.avail_in++, s->stream.next_in--;
   1.433 +			if (c != EOF)
   1.434 +			{
   1.435 +				s->stream.avail_in++, s->stream.next_in--;
   1.436 +				s->transparent = 1;
   1.437 +			}
   1.438 +			s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
   1.439 +			return;
   1.440 +		}
   1.441 +	}
   1.442 +	method = get_byte(s);
   1.443 +	flags  = get_byte(s);
   1.444 +	if (method != Z_DEFLATED || (flags & RESERVED) != 0)
   1.445 +	{
   1.446 +		s->z_err = Z_DATA_ERROR;
   1.447 +		return;
   1.448 +	}
   1.449 +
   1.450 +	/* Discard time, xflags and OS code: */
   1.451 +	for (len = 0; len < 6; len++)
   1.452 +		(void)get_byte(s);
   1.453 +
   1.454 +	if ((flags & EXTRA_FIELD) != 0)   /* skip the extra field */
   1.455 +	{
   1.456 +		len  =  (uInt)get_byte(s);
   1.457 +		len += ((uInt)get_byte(s))<<8;
   1.458 +		/* len is garbage if EOF but the loop below will quit anyway */
   1.459 +		while (len-- != 0 && get_byte(s) != EOF)
   1.460 +			;
   1.461 +	}
   1.462 +	if ((flags & ORIG_NAME) != 0)   /* skip the original file name */
   1.463 +	{
   1.464 +		while ((c = get_byte(s)) != 0 && c != EOF)
   1.465 +			;
   1.466 +	}
   1.467 +	if ((flags & COMMENT) != 0)     /* skip the .gz file comment */
   1.468 +	{
   1.469 +		while ((c = get_byte(s)) != 0 && c != EOF)
   1.470 +			;
   1.471 +	}
   1.472 +	if ((flags & HEAD_CRC) != 0)    /* skip the header crc */
   1.473 +	{
   1.474 +		for (len = 0; len < 2; len++)
   1.475 +			(void)get_byte(s);
   1.476 +	}
   1.477 +	s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
   1.478 +}
   1.479 +
   1.480 +/* ===========================================================================
   1.481 + * Cleanup then free the given mem_stream. Return a zlib error code.
   1.482 +   Try freeing in the reverse order of allocations.
   1.483 + */
   1.484 +local int destroy(s)
   1.485 +mem_stream *s;
   1.486 +{
   1.487 +	int err = Z_OK;
   1.488 +
   1.489 +	if (!s)
   1.490 +		return Z_STREAM_ERROR;
   1.491 +
   1.492 +	TRYFREE(s->msg);
   1.493 +
   1.494 +	if (s->stream.state != NULL)
   1.495 +	{
   1.496 +		if (s->mode == 'w')
   1.497 +		{
   1.498 +#ifdef NO_DEFLATE
   1.499 +			err = Z_STREAM_ERROR;
   1.500 +#else
   1.501 +			err = deflateEnd(&(s->stream));
   1.502 +#endif
   1.503 +		}
   1.504 +		else if (s->mode == 'r')
   1.505 +		{
   1.506 +			err = inflateEnd(&(s->stream));
   1.507 +		}
   1.508 +	}
   1.509 +	if (s->file != NULL && memClose(s->file))
   1.510 +	{
   1.511 +#ifdef ESPIPE
   1.512 +		if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
   1.513 +#endif
   1.514 +		err = Z_ERRNO;
   1.515 +	}
   1.516 +	if (s->z_err < 0)
   1.517 +		err = s->z_err;
   1.518 +
   1.519 +	TRYFREE(s->inbuf);
   1.520 +	TRYFREE(s->outbuf);
   1.521 +	TRYFREE(s);
   1.522 +	return err;
   1.523 +}
   1.524 +
   1.525 +/* ===========================================================================
   1.526 +     Reads the given number of uncompressed bytes from the compressed file.
   1.527 +   gzread returns the number of bytes actually read (0 for end of file).
   1.528 + */
   1.529 +int ZEXPORT memgzread(file, buf, len)
   1.530 +gzFile file;
   1.531 +voidp    buf;
   1.532 +unsigned len;
   1.533 +{
   1.534 +	mem_stream *s     = (mem_stream *)file;
   1.535 +	Bytef *     start = (Bytef *)buf; /* starting point for crc computation */
   1.536 +	Byte *      next_out; /* == stream.next_out but not forced far (for MSDOS) */
   1.537 +
   1.538 +	if (s == NULL || s->mode != 'r')
   1.539 +		return Z_STREAM_ERROR;
   1.540 +
   1.541 +	if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
   1.542 +		return -1;
   1.543 +	if (s->z_err == Z_STREAM_END)
   1.544 +		return 0;                            /* EOF */
   1.545 +
   1.546 +	next_out = (Byte *)buf;
   1.547 +	s->stream.next_out  = (Bytef *)buf;
   1.548 +	s->stream.avail_out = len;
   1.549 +
   1.550 +	while (s->stream.avail_out != 0)
   1.551 +	{
   1.552 +		if (s->transparent)
   1.553 +		{
   1.554 +			/* Copy first the lookahead bytes: */
   1.555 +			uInt n = s->stream.avail_in;
   1.556 +			if (n > s->stream.avail_out)
   1.557 +				n = s->stream.avail_out;
   1.558 +			if (n > 0)
   1.559 +			{
   1.560 +				zmemcpy(s->stream.next_out, s->stream.next_in, n);
   1.561 +				next_out += n;
   1.562 +				s->stream.next_out   = next_out;
   1.563 +				s->stream.next_in   += n;
   1.564 +				s->stream.avail_out -= n;
   1.565 +				s->stream.avail_in  -= n;
   1.566 +			}
   1.567 +			if (s->stream.avail_out > 0)
   1.568 +			{
   1.569 +				s->stream.avail_out -= (uInt)memRead(next_out, 1, s->stream.avail_out, s->file);
   1.570 +			}
   1.571 +			len -= s->stream.avail_out;
   1.572 +			s->stream.total_in  += (uLong)len;
   1.573 +			s->stream.total_out += (uLong)len;
   1.574 +			if (len == 0)
   1.575 +				s->z_eof = 1;
   1.576 +			return (int)len;
   1.577 +		}
   1.578 +		if (s->stream.avail_in == 0 && !s->z_eof)
   1.579 +		{
   1.580 +			errno = 0;
   1.581 +			s->stream.avail_in = (uInt)memRead(s->inbuf, 1, Z_BUFSIZE, s->file);
   1.582 +			if (s->stream.avail_in == 0)
   1.583 +			{
   1.584 +				s->z_eof = 1;
   1.585 +				if (memError(s->file))
   1.586 +				{
   1.587 +					s->z_err = Z_ERRNO;
   1.588 +					break;
   1.589 +				}
   1.590 +			}
   1.591 +			s->stream.next_in = s->inbuf;
   1.592 +		}
   1.593 +		s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
   1.594 +
   1.595 +		if (s->z_err == Z_STREAM_END)
   1.596 +		{
   1.597 +			/* Check CRC and original size */
   1.598 +			s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
   1.599 +			start  = s->stream.next_out;
   1.600 +
   1.601 +			if (getLong(s) != s->crc)
   1.602 +			{
   1.603 +				s->z_err = Z_DATA_ERROR;
   1.604 +			}
   1.605 +			else
   1.606 +			{
   1.607 +				(void)getLong(s);
   1.608 +				/* The uncompressed length returned by above getlong() may
   1.609 +				 * be different from s->stream.total_out) in case of
   1.610 +				 * concatenated .gz files. Check for such files:
   1.611 +				 */
   1.612 +				check_header(s);
   1.613 +				if (s->z_err == Z_OK)
   1.614 +				{
   1.615 +					uLong total_in  = s->stream.total_in;
   1.616 +					uLong total_out = s->stream.total_out;
   1.617 +
   1.618 +					inflateReset(&(s->stream));
   1.619 +					s->stream.total_in  = total_in;
   1.620 +					s->stream.total_out = total_out;
   1.621 +					s->crc = crc32(0L, Z_NULL, 0);
   1.622 +				}
   1.623 +			}
   1.624 +		}
   1.625 +		if (s->z_err != Z_OK || s->z_eof)
   1.626 +			break;
   1.627 +	}
   1.628 +	s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
   1.629 +
   1.630 +	return (int)(len - s->stream.avail_out);
   1.631 +}
   1.632 +
   1.633 +#ifndef NO_DEFLATE
   1.634 +/* ===========================================================================
   1.635 +     Writes the given number of uncompressed bytes into the compressed file.
   1.636 +   gzwrite returns the number of bytes actually written (0 in case of error).
   1.637 + */
   1.638 +int ZEXPORT memgzwrite(file, buf, len)
   1.639 +gzFile file;
   1.640 +const voidp buf;
   1.641 +unsigned    len;
   1.642 +{
   1.643 +	mem_stream *s = (mem_stream *)file;
   1.644 +
   1.645 +	if (s == NULL || s->mode != 'w')
   1.646 +		return Z_STREAM_ERROR;
   1.647 +
   1.648 +	s->stream.next_in  = (Bytef *)buf;
   1.649 +	s->stream.avail_in = len;
   1.650 +
   1.651 +	while (s->stream.avail_in != 0)
   1.652 +	{
   1.653 +		if (s->stream.avail_out == 0)
   1.654 +		{
   1.655 +			s->stream.next_out = s->outbuf;
   1.656 +			if (memWrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE)
   1.657 +			{
   1.658 +				s->z_err = Z_ERRNO;
   1.659 +				break;
   1.660 +			}
   1.661 +			s->stream.avail_out = Z_BUFSIZE;
   1.662 +		}
   1.663 +		s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
   1.664 +		if (s->z_err != Z_OK)
   1.665 +			break;
   1.666 +	}
   1.667 +	s->crc = crc32(s->crc, (const Bytef *)buf, len);
   1.668 +
   1.669 +	return (int)(len - s->stream.avail_in);
   1.670 +}
   1.671 +#endif
   1.672 +/* ===========================================================================
   1.673 +     Flushes all pending output into the compressed file. The parameter
   1.674 +   flush is as in the deflate() function.
   1.675 + */
   1.676 +local int do_flush(file, flush)
   1.677 +gzFile file;
   1.678 +int flush;
   1.679 +{
   1.680 +	uInt        len;
   1.681 +	int         done = 0;
   1.682 +	mem_stream *s    = (mem_stream *)file;
   1.683 +
   1.684 +	if (s == NULL || s->mode != 'w')
   1.685 +		return Z_STREAM_ERROR;
   1.686 +
   1.687 +	s->stream.avail_in = 0; /* should be zero already anyway */
   1.688 +
   1.689 +	for (;;)
   1.690 +	{
   1.691 +		len = Z_BUFSIZE - s->stream.avail_out;
   1.692 +
   1.693 +		if (len != 0)
   1.694 +		{
   1.695 +			if ((uInt)memWrite(s->outbuf, 1, len, s->file) != len)
   1.696 +			{
   1.697 +				s->z_err = Z_ERRNO;
   1.698 +				return Z_ERRNO;
   1.699 +			}
   1.700 +			s->stream.next_out  = s->outbuf;
   1.701 +			s->stream.avail_out = Z_BUFSIZE;
   1.702 +		}
   1.703 +		if (done)
   1.704 +			break;
   1.705 +		s->z_err = deflate(&(s->stream), flush);
   1.706 +
   1.707 +		/* Ignore the second of two consecutive flushes: */
   1.708 +		if (len == 0 && s->z_err == Z_BUF_ERROR)
   1.709 +			s->z_err = Z_OK;
   1.710 +
   1.711 +		/* deflate has finished flushing only when it hasn't used up
   1.712 +		 * all the available space in the output buffer:
   1.713 +		 */
   1.714 +		done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
   1.715 +
   1.716 +		if (s->z_err != Z_OK && s->z_err != Z_STREAM_END)
   1.717 +			break;
   1.718 +	}
   1.719 +	return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
   1.720 +}
   1.721 +
   1.722 +/* ===========================================================================
   1.723 +   Outputs a long in LSB order to the given file
   1.724 + */
   1.725 +local void putLong(file, x)
   1.726 +MEMFILE *file;
   1.727 +uLong x;
   1.728 +{
   1.729 +	int n;
   1.730 +	for (n = 0; n < 4; n++)
   1.731 +	{
   1.732 +		memPutc((int)(x & 0xff), file);
   1.733 +		x >>= 8;
   1.734 +	}
   1.735 +}
   1.736 +
   1.737 +/* ===========================================================================
   1.738 +   Reads a long in LSB order from the given mem_stream. Sets z_err in case
   1.739 +   of error.
   1.740 + */
   1.741 +local uLong getLong(s)
   1.742 +mem_stream *s;
   1.743 +{
   1.744 +	uLong x = (uLong)get_byte(s);
   1.745 +	int   c;
   1.746 +
   1.747 +	x += ((uLong)get_byte(s))<<8;
   1.748 +	x += ((uLong)get_byte(s))<<16;
   1.749 +	c  = get_byte(s);
   1.750 +	if (c == EOF)
   1.751 +		s->z_err = Z_DATA_ERROR;
   1.752 +	x += ((uLong)c)<<24;
   1.753 +	return x;
   1.754 +}
   1.755 +
   1.756 +/* ===========================================================================
   1.757 +     Flushes all pending output if necessary, closes the compressed file
   1.758 +   and deallocates all the (de)compression state.
   1.759 + */
   1.760 +int ZEXPORT memgzclose(file)
   1.761 +gzFile file;
   1.762 +{
   1.763 +	int         err;
   1.764 +	mem_stream *s = (mem_stream *)file;
   1.765 +
   1.766 +	if (s == NULL)
   1.767 +		return Z_STREAM_ERROR;
   1.768 +
   1.769 +	if (s->mode == 'w')
   1.770 +	{
   1.771 +#ifdef NO_DEFLATE
   1.772 +		return Z_STREAM_ERROR;
   1.773 +#else
   1.774 +		err = do_flush(file, Z_FINISH);
   1.775 +		if (err != Z_OK)
   1.776 +			return destroy((mem_stream *)file);
   1.777 +
   1.778 +		putLong(s->file, s->crc);
   1.779 +		putLong(s->file, s->stream.total_in);
   1.780 +#endif
   1.781 +	}
   1.782 +	return destroy((mem_stream *)file);
   1.783 +}
   1.784 +
   1.785 +long ZEXPORT memtell(file)
   1.786 +gzFile file;
   1.787 +{
   1.788 +	mem_stream *s = (mem_stream *)file;
   1.789 +
   1.790 +	if (s == NULL)
   1.791 +		return Z_STREAM_ERROR;
   1.792 +
   1.793 +	return memTell(s->file);
   1.794 +}