annotate src/common/memgzio.c @ 581:5f09601abe8c

saving progress.
author Robert McIntyre <rlm@mit.edu>
date Sat, 01 Sep 2012 09:35:07 -0500
parents f9f4f1b99eed
children
rev   line source
rlm@1 1 /* gzio.c -- IO on .gz files
rlm@1 2 * Copyright (C) 1995-2002 Jean-loup Gailly.
rlm@1 3 * For conditions of distribution and use, see copyright notice in zlib.h
rlm@1 4 *
rlm@1 5 * Compile this file with -DNO_DEFLATE to avoid the compression code.
rlm@1 6 */
rlm@1 7
rlm@1 8 /* memgzio.c - IO on .gz files in memory
rlm@1 9 * Adapted from original gzio.c from zlib library by Forgotten
rlm@1 10 */
rlm@1 11
rlm@1 12 /* @(#) $Id: memgzio.c,v 1.5 2006/06/06 21:04:20 spacy51 Exp $ */
rlm@1 13
rlm@1 14 #include <stdio.h>
rlm@1 15 #include <stdarg.h>
rlm@1 16 #include <stdlib.h>
rlm@1 17 #include <string.h>
rlm@1 18 #include <errno.h>
rlm@1 19
rlm@1 20 #include "memgzio.h"
rlm@1 21
rlm@1 22 #ifndef local
rlm@1 23 #define local static
rlm@1 24 #endif
rlm@1 25
rlm@1 26 #ifndef DEF_MEM_LEVEL
rlm@1 27 # define DEF_MEM_LEVEL 8
rlm@1 28 #endif
rlm@1 29
rlm@1 30 #ifndef OS_CODE
rlm@1 31 #define OS_CODE 3
rlm@1 32 #endif
rlm@1 33
rlm@1 34 #ifndef zmemcpy
rlm@1 35 #define zmemcpy memcpy
rlm@1 36 #endif
rlm@1 37
rlm@1 38 /*struct internal_state {int dummy;};*/ /* for buggy compilers */
rlm@1 39
rlm@1 40 #ifndef Z_BUFSIZE
rlm@1 41 # ifdef MAXSEG_64K
rlm@1 42 # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
rlm@1 43 # else
rlm@1 44 # define Z_BUFSIZE 16384
rlm@1 45 # endif
rlm@1 46 #endif
rlm@1 47 #ifndef Z_PRINTF_BUFSIZE
rlm@1 48 # define Z_PRINTF_BUFSIZE 4096
rlm@1 49 #endif
rlm@1 50
rlm@1 51 #define ALLOC(size) malloc(size)
rlm@1 52 #define TRYFREE(p) \
rlm@1 53 {if (p) \
rlm@1 54 free(p);}
rlm@1 55
rlm@1 56 static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
rlm@1 57
rlm@1 58 /* gzip flag byte */
rlm@1 59 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
rlm@1 60 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
rlm@1 61 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
rlm@1 62 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
rlm@1 63 #define COMMENT 0x10 /* bit 4 set: file comment present */
rlm@1 64 #define RESERVED 0xE0 /* bits 5..7: reserved */
rlm@1 65
rlm@1 66 typedef struct _MemFile
rlm@1 67 {
rlm@1 68 char *memory;
rlm@1 69 char *next;
rlm@1 70 int available;
rlm@1 71 int error;
rlm@1 72 char mode;
rlm@1 73 } MEMFILE;
rlm@1 74
rlm@1 75 typedef struct mem_stream
rlm@1 76 {
rlm@1 77 z_stream stream;
rlm@1 78 int z_err; /* error code for last stream operation */
rlm@1 79 int z_eof; /* set if end of input file */
rlm@1 80 MEMFILE *file; /* memoru file */
rlm@1 81 Byte * inbuf; /* input buffer */
rlm@1 82 Byte * outbuf; /* output buffer */
rlm@1 83 uLong crc; /* crc32 of uncompressed data */
rlm@1 84 char * msg; /* error message */
rlm@1 85 int transparent; /* 1 if input file is not a .gz file */
rlm@1 86 char mode; /* 'w' or 'r' */
rlm@1 87 long startpos; /* start of compressed data in file (header skipped) */
rlm@1 88 } mem_stream;
rlm@1 89
rlm@1 90 local gzFile gz_open OF((char *memory, const int available, const char *mode));
rlm@1 91 local int do_flush OF((gzFile file, int flush));
rlm@1 92 local int get_byte OF((mem_stream *s));
rlm@1 93 local void check_header OF((mem_stream *s));
rlm@1 94 local int destroy OF((mem_stream *s));
rlm@1 95 local void putLong OF((MEMFILE *file, uLong x));
rlm@1 96 local uLong getLong OF((mem_stream *s));
rlm@1 97
rlm@1 98 local MEMFILE *memOpen(char *memory, int available, char mode)
rlm@1 99 {
rlm@1 100 MEMFILE *f;
rlm@1 101
rlm@1 102 if (available <= 8)
rlm@1 103 return NULL;
rlm@1 104
rlm@1 105 if (mode != 'w' && mode != 'r')
rlm@1 106 return NULL;
rlm@1 107
rlm@1 108 f = (MEMFILE *)malloc(sizeof(MEMFILE));
rlm@1 109
rlm@1 110 f->memory = memory;
rlm@1 111 f->mode = mode;
rlm@1 112 f->error = 0;
rlm@1 113
rlm@1 114 if (mode == 'w')
rlm@1 115 {
rlm@1 116 f->available = available - 8;
rlm@1 117 f->next = memory + 8;
rlm@1 118 memory[0] = 'V';
rlm@1 119 memory[1] = 'B';
rlm@1 120 memory[2] = 'A';
rlm@1 121 memory[3] = ' ';
rlm@1 122 *((int *)(memory+4)) = 0;
rlm@1 123 }
rlm@1 124 else
rlm@1 125 {
rlm@1 126 if (memory[0] != 'V' || memory[1] != 'B' || memory[2] != 'A' ||
rlm@1 127 memory[3] != ' ')
rlm@1 128 {
rlm@1 129 free(f);
rlm@1 130 return NULL;
rlm@1 131 }
rlm@1 132 f->available = *((int *)(memory+4));
rlm@1 133 f->next = memory+8;
rlm@1 134 }
rlm@1 135
rlm@1 136 return f;
rlm@1 137 }
rlm@1 138
rlm@1 139 local size_t memWrite(const void *buffer, size_t size, size_t count,
rlm@1 140 MEMFILE *file)
rlm@1 141 {
rlm@1 142 size_t total = size*count;
rlm@1 143
rlm@1 144 if (file->mode != 'w')
rlm@1 145 {
rlm@1 146 file->error = 1;
rlm@1 147 return 0;
rlm@1 148 }
rlm@1 149
rlm@1 150 if (total > (size_t)file->available)
rlm@1 151 {
rlm@1 152 total = file->available;
rlm@1 153 }
rlm@1 154 memcpy(file->next, buffer, total);
rlm@1 155 file->available -= (int)total;
rlm@1 156 file->next += total;
rlm@1 157 return total;
rlm@1 158 }
rlm@1 159
rlm@1 160 local size_t memRead(void *buffer, size_t size, size_t count,
rlm@1 161 MEMFILE *file)
rlm@1 162 {
rlm@1 163 size_t total = size*count;
rlm@1 164
rlm@1 165 if (file->mode != 'r')
rlm@1 166 {
rlm@1 167 file->error = 1;
rlm@1 168 return 0;
rlm@1 169 }
rlm@1 170
rlm@1 171 if (file->available == 0)
rlm@1 172 return -1;
rlm@1 173
rlm@1 174 if (total > (size_t)file->available)
rlm@1 175 {
rlm@1 176 total = file->available;
rlm@1 177 }
rlm@1 178 memcpy(buffer, file->next, total);
rlm@1 179 file->available -= (int)total;
rlm@1 180 file->next += total;
rlm@1 181 return total;
rlm@1 182 }
rlm@1 183
rlm@1 184 local int memPutc(int c, MEMFILE *file)
rlm@1 185 {
rlm@1 186 if (file->mode != 'w')
rlm@1 187 {
rlm@1 188 file->error = 1;
rlm@1 189 return -1;
rlm@1 190 }
rlm@1 191
rlm@1 192 if (file->available >= 1)
rlm@1 193 {
rlm@1 194 *file->next++ = c;
rlm@1 195 file->available--;
rlm@1 196 }
rlm@1 197 else
rlm@1 198 return -1;
rlm@1 199
rlm@1 200 return c;
rlm@1 201 }
rlm@1 202
rlm@1 203 local long memTell(MEMFILE *f)
rlm@1 204 {
rlm@1 205 return (long)(f->next - f->memory) - 8;
rlm@1 206 }
rlm@1 207
rlm@1 208 local int memError(MEMFILE *f)
rlm@1 209 {
rlm@1 210 return f->error;
rlm@1 211 }
rlm@1 212
rlm@1 213 local int memClose(MEMFILE *f)
rlm@1 214 {
rlm@1 215 if (f->mode == 'w')
rlm@1 216 {
rlm@1 217 *((int *)(f->memory+4)) = memTell(f);
rlm@1 218 }
rlm@1 219 free(f);
rlm@1 220 return 0;
rlm@1 221 }
rlm@1 222
rlm@1 223 local int memPrintf(MEMFILE *f, const char *format, ...)
rlm@1 224 {
rlm@1 225 char buffer[80];
rlm@1 226 va_list list;
rlm@1 227 int len;
rlm@1 228
rlm@1 229 va_start(list, format);
rlm@1 230 len = vsprintf(buffer, format, list);
rlm@1 231 va_end(list);
rlm@1 232
rlm@1 233 return (int)memWrite(buffer, 1, len, f);
rlm@1 234 }
rlm@1 235
rlm@1 236 /* ===========================================================================
rlm@1 237 Opens a gzip (.gz) file for reading or writing. The mode parameter
rlm@1 238 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
rlm@1 239 or path name (if fd == -1).
rlm@1 240 gz_open return NULL if the file could not be opened or if there was
rlm@1 241 insufficient memory to allocate the (de)compression state; errno
rlm@1 242 can be checked to distinguish the two cases (if errno is zero, the
rlm@1 243 zlib error is Z_MEM_ERROR).
rlm@1 244 */
rlm@1 245 local gzFile gz_open(memory, available, mode)
rlm@1 246 char *memory;
rlm@1 247 const int available;
rlm@1 248 const char *mode;
rlm@1 249 {
rlm@1 250 int err;
rlm@1 251 int level = Z_DEFAULT_COMPRESSION; /* compression level */
rlm@1 252 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
rlm@1 253 char * p = (char *)mode;
rlm@1 254 mem_stream *s;
rlm@1 255 char fmode[80]; /* copy of mode, without the compression level */
rlm@1 256 char * m = fmode;
rlm@1 257
rlm@1 258 s = (mem_stream *)ALLOC(sizeof(mem_stream));
rlm@1 259 if (!s)
rlm@1 260 return Z_NULL;
rlm@1 261
rlm@1 262 s->stream.zalloc = (alloc_func)0;
rlm@1 263 s->stream.zfree = (free_func)0;
rlm@1 264 s->stream.opaque = (voidpf)0;
rlm@1 265 s->stream.next_in = s->inbuf = Z_NULL;
rlm@1 266 s->stream.next_out = s->outbuf = Z_NULL;
rlm@1 267 s->stream.avail_in = s->stream.avail_out = 0;
rlm@1 268 s->z_err = Z_OK;
rlm@1 269 s->z_eof = 0;
rlm@1 270 s->crc = crc32(0L, Z_NULL, 0);
rlm@1 271 s->msg = NULL;
rlm@1 272 s->transparent = 0;
rlm@1 273 s->file = NULL;
rlm@1 274
rlm@1 275 s->mode = '\0';
rlm@1 276 do
rlm@1 277 {
rlm@1 278 if (*p == 'r')
rlm@1 279 s->mode = 'r';
rlm@1 280 if (*p == 'w' || *p == 'a')
rlm@1 281 s->mode = 'w';
rlm@1 282 if (*p >= '0' && *p <= '9')
rlm@1 283 {
rlm@1 284 level = *p - '0';
rlm@1 285 }
rlm@1 286 else if (*p == 'f')
rlm@1 287 {
rlm@1 288 strategy = Z_FILTERED;
rlm@1 289 }
rlm@1 290 else if (*p == 'h')
rlm@1 291 {
rlm@1 292 strategy = Z_HUFFMAN_ONLY;
rlm@1 293 }
rlm@1 294 else
rlm@1 295 {
rlm@1 296 *m++ = *p; /* copy the mode */
rlm@1 297 }
rlm@1 298 }
rlm@1 299 while (*p++ && m != fmode + sizeof(fmode));
rlm@1 300 if (s->mode == '\0')
rlm@1 301 return destroy(s), (gzFile)Z_NULL;
rlm@1 302
rlm@1 303 if (s->mode == 'w')
rlm@1 304 {
rlm@1 305 #ifdef NO_DEFLATE
rlm@1 306 err = Z_STREAM_ERROR;
rlm@1 307 #else
rlm@1 308 err = deflateInit2(&(s->stream), level,
rlm@1 309 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
rlm@1 310 /* windowBits is passed < 0 to suppress zlib header */
rlm@1 311
rlm@1 312 s->stream.next_out = s->outbuf = (Byte *)ALLOC(Z_BUFSIZE);
rlm@1 313 #endif
rlm@1 314 if (err != Z_OK || s->outbuf == Z_NULL)
rlm@1 315 {
rlm@1 316 return destroy(s), (gzFile)Z_NULL;
rlm@1 317 }
rlm@1 318 }
rlm@1 319 else
rlm@1 320 {
rlm@1 321 s->stream.next_in = s->inbuf = (Byte *)ALLOC(Z_BUFSIZE);
rlm@1 322
rlm@1 323 err = inflateInit2(&(s->stream), -MAX_WBITS);
rlm@1 324 /* windowBits is passed < 0 to tell that there is no zlib header.
rlm@1 325 * Note that in this case inflate *requires* an extra "dummy" byte
rlm@1 326 * after the compressed stream in order to complete decompression and
rlm@1 327 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
rlm@1 328 * present after the compressed stream.
rlm@1 329 */
rlm@1 330 if (err != Z_OK || s->inbuf == Z_NULL)
rlm@1 331 {
rlm@1 332 return destroy(s), (gzFile)Z_NULL;
rlm@1 333 }
rlm@1 334 }
rlm@1 335 s->stream.avail_out = Z_BUFSIZE;
rlm@1 336
rlm@1 337 errno = 0;
rlm@1 338 s->file = memOpen(memory, available, s->mode);
rlm@1 339
rlm@1 340 if (s->file == NULL)
rlm@1 341 {
rlm@1 342 return destroy(s), (gzFile)Z_NULL;
rlm@1 343 }
rlm@1 344
rlm@1 345 if (s->mode == 'w')
rlm@1 346 {
rlm@1 347 /* Write a very simple .gz header:
rlm@1 348 */
rlm@1 349 memPrintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
rlm@1 350 Z_DEFLATED, 0 /*flags*/, 0, 0, 0, 0 /*time*/, 0 /*xflags*/, OS_CODE);
rlm@1 351 s->startpos = 10L;
rlm@1 352 /* We use 10L instead of ftell(s->file) to because ftell causes an
rlm@1 353 * fflush on some systems. This version of the library doesn't use
rlm@1 354 * startpos anyway in write mode, so this initialization is not
rlm@1 355 * necessary.
rlm@1 356 */
rlm@1 357 }
rlm@1 358 else
rlm@1 359 {
rlm@1 360 check_header(s); /* skip the .gz header */
rlm@1 361 s->startpos = (memTell(s->file) - s->stream.avail_in);
rlm@1 362 }
rlm@1 363
rlm@1 364 return (gzFile)s;
rlm@1 365 }
rlm@1 366
rlm@1 367 /* ===========================================================================
rlm@1 368 Opens a gzip (.gz) file for reading or writing.
rlm@1 369 */
rlm@1 370 gzFile ZEXPORT memgzopen(memory, available, mode)
rlm@1 371 char *memory;
rlm@1 372 int available;
rlm@1 373 const char *mode;
rlm@1 374 {
rlm@1 375 return gz_open(memory, available, mode);
rlm@1 376 }
rlm@1 377
rlm@1 378 /* ===========================================================================
rlm@1 379 Read a byte from a mem_stream; update next_in and avail_in. Return EOF
rlm@1 380 for end of file.
rlm@1 381 IN assertion: the stream s has been sucessfully opened for reading.
rlm@1 382 */
rlm@1 383 local int get_byte(s)
rlm@1 384 mem_stream *s;
rlm@1 385 {
rlm@1 386 if (s->z_eof)
rlm@1 387 return EOF;
rlm@1 388 if (s->stream.avail_in == 0)
rlm@1 389 {
rlm@1 390 errno = 0;
rlm@1 391 s->stream.avail_in = (uInt)memRead(s->inbuf, 1, Z_BUFSIZE, s->file);
rlm@1 392 if (s->stream.avail_in == 0)
rlm@1 393 {
rlm@1 394 s->z_eof = 1;
rlm@1 395 if (memError(s->file))
rlm@1 396 s->z_err = Z_ERRNO;
rlm@1 397 return EOF;
rlm@1 398 }
rlm@1 399 s->stream.next_in = s->inbuf;
rlm@1 400 }
rlm@1 401 s->stream.avail_in--;
rlm@1 402 return *(s->stream.next_in)++;
rlm@1 403 }
rlm@1 404
rlm@1 405 /* ===========================================================================
rlm@1 406 Check the gzip header of a mem_stream opened for reading. Set the stream
rlm@1 407 mode to transparent if the gzip magic header is not present; set s->err
rlm@1 408 to Z_DATA_ERROR if the magic header is present but the rest of the header
rlm@1 409 is incorrect.
rlm@1 410 IN assertion: the stream s has already been created sucessfully;
rlm@1 411 s->stream.avail_in is zero for the first time, but may be non-zero
rlm@1 412 for concatenated .gz files.
rlm@1 413 */
rlm@1 414 local void check_header(s)
rlm@1 415 mem_stream *s;
rlm@1 416 {
rlm@1 417 int method; /* method byte */
rlm@1 418 int flags; /* flags byte */
rlm@1 419 uInt len;
rlm@1 420 int c;
rlm@1 421
rlm@1 422 /* Check the gzip magic header */
rlm@1 423 for (len = 0; len < 2; len++)
rlm@1 424 {
rlm@1 425 c = get_byte(s);
rlm@1 426 if (c != gz_magic[len])
rlm@1 427 {
rlm@1 428 if (len != 0)
rlm@1 429 s->stream.avail_in++, s->stream.next_in--;
rlm@1 430 if (c != EOF)
rlm@1 431 {
rlm@1 432 s->stream.avail_in++, s->stream.next_in--;
rlm@1 433 s->transparent = 1;
rlm@1 434 }
rlm@1 435 s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
rlm@1 436 return;
rlm@1 437 }
rlm@1 438 }
rlm@1 439 method = get_byte(s);
rlm@1 440 flags = get_byte(s);
rlm@1 441 if (method != Z_DEFLATED || (flags & RESERVED) != 0)
rlm@1 442 {
rlm@1 443 s->z_err = Z_DATA_ERROR;
rlm@1 444 return;
rlm@1 445 }
rlm@1 446
rlm@1 447 /* Discard time, xflags and OS code: */
rlm@1 448 for (len = 0; len < 6; len++)
rlm@1 449 (void)get_byte(s);
rlm@1 450
rlm@1 451 if ((flags & EXTRA_FIELD) != 0) /* skip the extra field */
rlm@1 452 {
rlm@1 453 len = (uInt)get_byte(s);
rlm@1 454 len += ((uInt)get_byte(s))<<8;
rlm@1 455 /* len is garbage if EOF but the loop below will quit anyway */
rlm@1 456 while (len-- != 0 && get_byte(s) != EOF)
rlm@1 457 ;
rlm@1 458 }
rlm@1 459 if ((flags & ORIG_NAME) != 0) /* skip the original file name */
rlm@1 460 {
rlm@1 461 while ((c = get_byte(s)) != 0 && c != EOF)
rlm@1 462 ;
rlm@1 463 }
rlm@1 464 if ((flags & COMMENT) != 0) /* skip the .gz file comment */
rlm@1 465 {
rlm@1 466 while ((c = get_byte(s)) != 0 && c != EOF)
rlm@1 467 ;
rlm@1 468 }
rlm@1 469 if ((flags & HEAD_CRC) != 0) /* skip the header crc */
rlm@1 470 {
rlm@1 471 for (len = 0; len < 2; len++)
rlm@1 472 (void)get_byte(s);
rlm@1 473 }
rlm@1 474 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
rlm@1 475 }
rlm@1 476
rlm@1 477 /* ===========================================================================
rlm@1 478 * Cleanup then free the given mem_stream. Return a zlib error code.
rlm@1 479 Try freeing in the reverse order of allocations.
rlm@1 480 */
rlm@1 481 local int destroy(s)
rlm@1 482 mem_stream *s;
rlm@1 483 {
rlm@1 484 int err = Z_OK;
rlm@1 485
rlm@1 486 if (!s)
rlm@1 487 return Z_STREAM_ERROR;
rlm@1 488
rlm@1 489 TRYFREE(s->msg);
rlm@1 490
rlm@1 491 if (s->stream.state != NULL)
rlm@1 492 {
rlm@1 493 if (s->mode == 'w')
rlm@1 494 {
rlm@1 495 #ifdef NO_DEFLATE
rlm@1 496 err = Z_STREAM_ERROR;
rlm@1 497 #else
rlm@1 498 err = deflateEnd(&(s->stream));
rlm@1 499 #endif
rlm@1 500 }
rlm@1 501 else if (s->mode == 'r')
rlm@1 502 {
rlm@1 503 err = inflateEnd(&(s->stream));
rlm@1 504 }
rlm@1 505 }
rlm@1 506 if (s->file != NULL && memClose(s->file))
rlm@1 507 {
rlm@1 508 #ifdef ESPIPE
rlm@1 509 if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
rlm@1 510 #endif
rlm@1 511 err = Z_ERRNO;
rlm@1 512 }
rlm@1 513 if (s->z_err < 0)
rlm@1 514 err = s->z_err;
rlm@1 515
rlm@1 516 TRYFREE(s->inbuf);
rlm@1 517 TRYFREE(s->outbuf);
rlm@1 518 TRYFREE(s);
rlm@1 519 return err;
rlm@1 520 }
rlm@1 521
rlm@1 522 /* ===========================================================================
rlm@1 523 Reads the given number of uncompressed bytes from the compressed file.
rlm@1 524 gzread returns the number of bytes actually read (0 for end of file).
rlm@1 525 */
rlm@1 526 int ZEXPORT memgzread(file, buf, len)
rlm@1 527 gzFile file;
rlm@1 528 voidp buf;
rlm@1 529 unsigned len;
rlm@1 530 {
rlm@1 531 mem_stream *s = (mem_stream *)file;
rlm@1 532 Bytef * start = (Bytef *)buf; /* starting point for crc computation */
rlm@1 533 Byte * next_out; /* == stream.next_out but not forced far (for MSDOS) */
rlm@1 534
rlm@1 535 if (s == NULL || s->mode != 'r')
rlm@1 536 return Z_STREAM_ERROR;
rlm@1 537
rlm@1 538 if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
rlm@1 539 return -1;
rlm@1 540 if (s->z_err == Z_STREAM_END)
rlm@1 541 return 0; /* EOF */
rlm@1 542
rlm@1 543 next_out = (Byte *)buf;
rlm@1 544 s->stream.next_out = (Bytef *)buf;
rlm@1 545 s->stream.avail_out = len;
rlm@1 546
rlm@1 547 while (s->stream.avail_out != 0)
rlm@1 548 {
rlm@1 549 if (s->transparent)
rlm@1 550 {
rlm@1 551 /* Copy first the lookahead bytes: */
rlm@1 552 uInt n = s->stream.avail_in;
rlm@1 553 if (n > s->stream.avail_out)
rlm@1 554 n = s->stream.avail_out;
rlm@1 555 if (n > 0)
rlm@1 556 {
rlm@1 557 zmemcpy(s->stream.next_out, s->stream.next_in, n);
rlm@1 558 next_out += n;
rlm@1 559 s->stream.next_out = next_out;
rlm@1 560 s->stream.next_in += n;
rlm@1 561 s->stream.avail_out -= n;
rlm@1 562 s->stream.avail_in -= n;
rlm@1 563 }
rlm@1 564 if (s->stream.avail_out > 0)
rlm@1 565 {
rlm@1 566 s->stream.avail_out -= (uInt)memRead(next_out, 1, s->stream.avail_out, s->file);
rlm@1 567 }
rlm@1 568 len -= s->stream.avail_out;
rlm@1 569 s->stream.total_in += (uLong)len;
rlm@1 570 s->stream.total_out += (uLong)len;
rlm@1 571 if (len == 0)
rlm@1 572 s->z_eof = 1;
rlm@1 573 return (int)len;
rlm@1 574 }
rlm@1 575 if (s->stream.avail_in == 0 && !s->z_eof)
rlm@1 576 {
rlm@1 577 errno = 0;
rlm@1 578 s->stream.avail_in = (uInt)memRead(s->inbuf, 1, Z_BUFSIZE, s->file);
rlm@1 579 if (s->stream.avail_in == 0)
rlm@1 580 {
rlm@1 581 s->z_eof = 1;
rlm@1 582 if (memError(s->file))
rlm@1 583 {
rlm@1 584 s->z_err = Z_ERRNO;
rlm@1 585 break;
rlm@1 586 }
rlm@1 587 }
rlm@1 588 s->stream.next_in = s->inbuf;
rlm@1 589 }
rlm@1 590 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
rlm@1 591
rlm@1 592 if (s->z_err == Z_STREAM_END)
rlm@1 593 {
rlm@1 594 /* Check CRC and original size */
rlm@1 595 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
rlm@1 596 start = s->stream.next_out;
rlm@1 597
rlm@1 598 if (getLong(s) != s->crc)
rlm@1 599 {
rlm@1 600 s->z_err = Z_DATA_ERROR;
rlm@1 601 }
rlm@1 602 else
rlm@1 603 {
rlm@1 604 (void)getLong(s);
rlm@1 605 /* The uncompressed length returned by above getlong() may
rlm@1 606 * be different from s->stream.total_out) in case of
rlm@1 607 * concatenated .gz files. Check for such files:
rlm@1 608 */
rlm@1 609 check_header(s);
rlm@1 610 if (s->z_err == Z_OK)
rlm@1 611 {
rlm@1 612 uLong total_in = s->stream.total_in;
rlm@1 613 uLong total_out = s->stream.total_out;
rlm@1 614
rlm@1 615 inflateReset(&(s->stream));
rlm@1 616 s->stream.total_in = total_in;
rlm@1 617 s->stream.total_out = total_out;
rlm@1 618 s->crc = crc32(0L, Z_NULL, 0);
rlm@1 619 }
rlm@1 620 }
rlm@1 621 }
rlm@1 622 if (s->z_err != Z_OK || s->z_eof)
rlm@1 623 break;
rlm@1 624 }
rlm@1 625 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
rlm@1 626
rlm@1 627 return (int)(len - s->stream.avail_out);
rlm@1 628 }
rlm@1 629
rlm@1 630 #ifndef NO_DEFLATE
rlm@1 631 /* ===========================================================================
rlm@1 632 Writes the given number of uncompressed bytes into the compressed file.
rlm@1 633 gzwrite returns the number of bytes actually written (0 in case of error).
rlm@1 634 */
rlm@1 635 int ZEXPORT memgzwrite(file, buf, len)
rlm@1 636 gzFile file;
rlm@1 637 const voidp buf;
rlm@1 638 unsigned len;
rlm@1 639 {
rlm@1 640 mem_stream *s = (mem_stream *)file;
rlm@1 641
rlm@1 642 if (s == NULL || s->mode != 'w')
rlm@1 643 return Z_STREAM_ERROR;
rlm@1 644
rlm@1 645 s->stream.next_in = (Bytef *)buf;
rlm@1 646 s->stream.avail_in = len;
rlm@1 647
rlm@1 648 while (s->stream.avail_in != 0)
rlm@1 649 {
rlm@1 650 if (s->stream.avail_out == 0)
rlm@1 651 {
rlm@1 652 s->stream.next_out = s->outbuf;
rlm@1 653 if (memWrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE)
rlm@1 654 {
rlm@1 655 s->z_err = Z_ERRNO;
rlm@1 656 break;
rlm@1 657 }
rlm@1 658 s->stream.avail_out = Z_BUFSIZE;
rlm@1 659 }
rlm@1 660 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
rlm@1 661 if (s->z_err != Z_OK)
rlm@1 662 break;
rlm@1 663 }
rlm@1 664 s->crc = crc32(s->crc, (const Bytef *)buf, len);
rlm@1 665
rlm@1 666 return (int)(len - s->stream.avail_in);
rlm@1 667 }
rlm@1 668 #endif
rlm@1 669 /* ===========================================================================
rlm@1 670 Flushes all pending output into the compressed file. The parameter
rlm@1 671 flush is as in the deflate() function.
rlm@1 672 */
rlm@1 673 local int do_flush(file, flush)
rlm@1 674 gzFile file;
rlm@1 675 int flush;
rlm@1 676 {
rlm@1 677 uInt len;
rlm@1 678 int done = 0;
rlm@1 679 mem_stream *s = (mem_stream *)file;
rlm@1 680
rlm@1 681 if (s == NULL || s->mode != 'w')
rlm@1 682 return Z_STREAM_ERROR;
rlm@1 683
rlm@1 684 s->stream.avail_in = 0; /* should be zero already anyway */
rlm@1 685
rlm@1 686 for (;;)
rlm@1 687 {
rlm@1 688 len = Z_BUFSIZE - s->stream.avail_out;
rlm@1 689
rlm@1 690 if (len != 0)
rlm@1 691 {
rlm@1 692 if ((uInt)memWrite(s->outbuf, 1, len, s->file) != len)
rlm@1 693 {
rlm@1 694 s->z_err = Z_ERRNO;
rlm@1 695 return Z_ERRNO;
rlm@1 696 }
rlm@1 697 s->stream.next_out = s->outbuf;
rlm@1 698 s->stream.avail_out = Z_BUFSIZE;
rlm@1 699 }
rlm@1 700 if (done)
rlm@1 701 break;
rlm@1 702 s->z_err = deflate(&(s->stream), flush);
rlm@1 703
rlm@1 704 /* Ignore the second of two consecutive flushes: */
rlm@1 705 if (len == 0 && s->z_err == Z_BUF_ERROR)
rlm@1 706 s->z_err = Z_OK;
rlm@1 707
rlm@1 708 /* deflate has finished flushing only when it hasn't used up
rlm@1 709 * all the available space in the output buffer:
rlm@1 710 */
rlm@1 711 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
rlm@1 712
rlm@1 713 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END)
rlm@1 714 break;
rlm@1 715 }
rlm@1 716 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
rlm@1 717 }
rlm@1 718
rlm@1 719 /* ===========================================================================
rlm@1 720 Outputs a long in LSB order to the given file
rlm@1 721 */
rlm@1 722 local void putLong(file, x)
rlm@1 723 MEMFILE *file;
rlm@1 724 uLong x;
rlm@1 725 {
rlm@1 726 int n;
rlm@1 727 for (n = 0; n < 4; n++)
rlm@1 728 {
rlm@1 729 memPutc((int)(x & 0xff), file);
rlm@1 730 x >>= 8;
rlm@1 731 }
rlm@1 732 }
rlm@1 733
rlm@1 734 /* ===========================================================================
rlm@1 735 Reads a long in LSB order from the given mem_stream. Sets z_err in case
rlm@1 736 of error.
rlm@1 737 */
rlm@1 738 local uLong getLong(s)
rlm@1 739 mem_stream *s;
rlm@1 740 {
rlm@1 741 uLong x = (uLong)get_byte(s);
rlm@1 742 int c;
rlm@1 743
rlm@1 744 x += ((uLong)get_byte(s))<<8;
rlm@1 745 x += ((uLong)get_byte(s))<<16;
rlm@1 746 c = get_byte(s);
rlm@1 747 if (c == EOF)
rlm@1 748 s->z_err = Z_DATA_ERROR;
rlm@1 749 x += ((uLong)c)<<24;
rlm@1 750 return x;
rlm@1 751 }
rlm@1 752
rlm@1 753 /* ===========================================================================
rlm@1 754 Flushes all pending output if necessary, closes the compressed file
rlm@1 755 and deallocates all the (de)compression state.
rlm@1 756 */
rlm@1 757 int ZEXPORT memgzclose(file)
rlm@1 758 gzFile file;
rlm@1 759 {
rlm@1 760 int err;
rlm@1 761 mem_stream *s = (mem_stream *)file;
rlm@1 762
rlm@1 763 if (s == NULL)
rlm@1 764 return Z_STREAM_ERROR;
rlm@1 765
rlm@1 766 if (s->mode == 'w')
rlm@1 767 {
rlm@1 768 #ifdef NO_DEFLATE
rlm@1 769 return Z_STREAM_ERROR;
rlm@1 770 #else
rlm@1 771 err = do_flush(file, Z_FINISH);
rlm@1 772 if (err != Z_OK)
rlm@1 773 return destroy((mem_stream *)file);
rlm@1 774
rlm@1 775 putLong(s->file, s->crc);
rlm@1 776 putLong(s->file, s->stream.total_in);
rlm@1 777 #endif
rlm@1 778 }
rlm@1 779 return destroy((mem_stream *)file);
rlm@1 780 }
rlm@1 781
rlm@1 782 long ZEXPORT memtell(file)
rlm@1 783 gzFile file;
rlm@1 784 {
rlm@1 785 mem_stream *s = (mem_stream *)file;
rlm@1 786
rlm@1 787 if (s == NULL)
rlm@1 788 return Z_STREAM_ERROR;
rlm@1 789
rlm@1 790 return memTell(s->file);
rlm@1 791 }