rename expr.cpp.h to expr.c.h
[rofl0r-VisualBoyAdvance.git] / src / memgzio.c
blob528539c329568ce17ccbdda4c45240ab4ef8ae12
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.
6 */
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 $ */
14 #include <stdio.h>
15 #include <stdarg.h>
16 #include <stdlib.h>
18 #include "memgzio.h"
20 /*struct internal_state {int dummy;};*/ /* for buggy compilers */
22 #ifndef Z_BUFSIZE
23 # ifdef MAXSEG_64K
24 # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
25 # else
26 # define Z_BUFSIZE 16384
27 # endif
28 #endif
29 #ifndef Z_PRINTF_BUFSIZE
30 # define Z_PRINTF_BUFSIZE 4096
31 #endif
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 */
38 /* gzip flag byte */
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 {
47 char *memory;
48 char *next;
49 int available;
50 int error;
51 char mode;
52 } MEMFILE;
54 typedef struct mem_stream {
55 z_stream 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) */
66 } mem_stream;
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)
79 MEMFILE *f;
81 if(available <= 8)
82 return NULL;
84 if(mode != 'w' && mode != 'r')
85 return NULL;
87 f = (MEMFILE *)malloc(sizeof(MEMFILE));
89 f->memory = memory;
90 f->mode = mode;
91 f->error = 0;
93 if(mode == 'w') {
94 f->available = available - 8;
95 f->next = memory + 8;
96 memory[0] = 'V';
97 memory[1] = 'B';
98 memory[2] = 'A';
99 memory[3] = ' ';
100 *((int *)(memory+4)) = 0;
101 } else {
102 if(memory[0] != 'V' || memory[1] != 'B' || memory[2] != 'A' ||
103 memory[3] != ' ') {
104 free(f);
105 return NULL;
107 f->available = *((int *)(memory+4));
108 f->next = memory+8;
111 return f;
114 local size_t memWrite(const void *buffer, size_t size, size_t count,
115 MEMFILE *file)
117 size_t total = size*count;
119 if(file->mode != 'w') {
120 file->error = 1;
121 return 0;
124 if(total > (size_t)file->available) {
125 total = file->available;
127 memcpy(file->next, buffer, total);
128 file->available -= (int)total;
129 file->next += total;
130 return total;
133 local size_t memRead(void *buffer, size_t size, size_t count,
134 MEMFILE *file)
136 size_t total = size*count;
138 if(file->mode != 'r') {
139 file->error = 1;
140 return 0;
143 if(file->available == 0)
144 return -1;
146 if(total > (size_t)file->available) {
147 total = file->available;
149 memcpy(buffer, file->next, total);
150 file->available -= (int)total;
151 file->next += total;
152 return total;
155 local int memPutc(int c, MEMFILE *file)
157 if(file->mode != 'w') {
158 file->error = 1;
159 return -1;
162 if(file->available >= 1) {
163 *file->next++ = c;
164 file->available--;
165 } else
166 return -1;
168 return c;
171 local long memTell(MEMFILE *f)
173 return (long)(f->next - f->memory) - 8;
176 local int memError(MEMFILE *f)
178 return f->error;
181 local int memClose(MEMFILE *f)
183 if(f->mode == 'w') {
184 *((int *)(f->memory+4)) = memTell(f);
186 free(f);
187 return 0;
190 local int memPrintf(MEMFILE *f, const char *format, ...)
192 char buffer[80];
193 va_list list;
194 int len;
196 va_start(list, format);
197 len = vsprintf(buffer, format, list);
198 va_end(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)
213 char *memory;
214 const int available;
215 const char *mode;
217 int err;
218 int level = Z_DEFAULT_COMPRESSION; /* compression level */
219 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
220 char *p = (char*)mode;
221 mem_stream *s;
222 char fmode[80]; /* copy of mode, without the compression level */
223 char *m = fmode;
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;
234 s->z_err = Z_OK;
235 s->z_eof = 0;
236 s->crc = crc32(0L, Z_NULL, 0);
237 s->msg = NULL;
238 s->transparent = 0;
239 s->file = NULL;
241 s->mode = '\0';
242 do {
243 if (*p == 'r') s->mode = 'r';
244 if (*p == 'w' || *p == 'a') s->mode = 'w';
245 if (*p >= '0' && *p <= '9') {
246 level = *p - '0';
247 } else if (*p == 'f') {
248 strategy = Z_FILTERED;
249 } else if (*p == 'h') {
250 strategy = Z_HUFFMAN_ONLY;
251 } else {
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') {
258 #ifdef NO_DEFLATE
259 err = Z_STREAM_ERROR;
260 #else
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);
266 #endif
267 if (err != Z_OK || s->outbuf == Z_NULL) {
268 return destroy(s), (gzFile)Z_NULL;
270 } else {
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;
286 errno = 0;
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);
298 s->startpos = 10L;
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
302 * necessary.
304 } else {
305 check_header(s); /* skip the .gz header */
306 s->startpos = (memTell(s->file) - s->stream.avail_in);
309 return (gzFile)s;
312 /* ===========================================================================
313 Opens a gzip (.gz) file for reading or writing.
315 gzFile ZEXPORT memgzopen (memory, available, mode)
316 char *memory;
317 int available;
318 const char *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
325 for end of file.
326 IN assertion: the stream s has been sucessfully opened for reading.
328 local int get_byte(s)
329 mem_stream *s;
331 if (s->z_eof) return EOF;
332 if (s->stream.avail_in == 0) {
333 errno = 0;
334 s->stream.avail_in = (uInt)memRead(s->inbuf, 1, Z_BUFSIZE, s->file);
335 if (s->stream.avail_in == 0) {
336 s->z_eof = 1;
337 if (memError(s->file)) s->z_err = Z_ERRNO;
338 return EOF;
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
350 is incorrect.
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)
356 mem_stream *s;
358 int method; /* method byte */
359 int flags; /* flags byte */
360 uInt len;
361 int c;
363 /* Check the gzip magic header */
364 for (len = 0; len < 2; len++) {
365 c = get_byte(s);
366 if (c != gz_magic[len]) {
367 if (len != 0) s->stream.avail_in++, s->stream.next_in--;
368 if (c != EOF) {
369 s->stream.avail_in++, s->stream.next_in--;
370 s->transparent = 1;
372 s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
373 return;
376 method = get_byte(s);
377 flags = get_byte(s);
378 if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
379 s->z_err = Z_DATA_ERROR;
380 return;
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)
409 mem_stream *s;
411 int err = Z_OK;
413 if (!s) return Z_STREAM_ERROR;
415 TRYFREE(s->msg);
417 if (s->stream.state != NULL) {
418 if (s->mode == 'w') {
419 #ifdef NO_DEFLATE
420 err = Z_STREAM_ERROR;
421 #else
422 err = deflateEnd(&(s->stream));
423 #endif
424 } else if (s->mode == 'r') {
425 err = inflateEnd(&(s->stream));
428 if (s->file != NULL && memClose(s->file)) {
429 #ifdef ESPIPE
430 if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
431 #endif
432 err = Z_ERRNO;
434 if (s->z_err < 0) err = s->z_err;
436 TRYFREE(s->inbuf);
437 TRYFREE(s->outbuf);
438 TRYFREE(s);
439 return 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)
447 gzFile file;
448 voidp buf;
449 unsigned 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;
470 if (n > 0) {
471 zmemcpy(s->stream.next_out, s->stream.next_in, n);
472 next_out += 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;
485 return (int)len;
487 if (s->stream.avail_in == 0 && !s->z_eof) {
489 errno = 0;
490 s->stream.avail_in = (uInt)memRead(s->inbuf, 1, Z_BUFSIZE, s->file);
491 if (s->stream.avail_in == 0) {
492 s->z_eof = 1;
493 if (memError(s->file)) {
494 s->z_err = Z_ERRNO;
495 break;
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;
509 } else {
510 (void)getLong(s);
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:
515 check_header(s);
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);
535 #ifndef NO_DEFLATE
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)
541 gzFile file;
542 const voidp buf;
543 unsigned 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) {
558 s->z_err = Z_ERRNO;
559 break;
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);
570 #endif
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)
576 gzFile file;
577 int flush;
579 uInt len;
580 int done = 0;
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 */
587 for (;;) {
588 len = Z_BUFSIZE - s->stream.avail_out;
590 if (len != 0) {
591 if ((uInt)memWrite(s->outbuf, 1, len, s->file) != len) {
592 s->z_err = Z_ERRNO;
593 return Z_ERRNO;
595 s->stream.next_out = s->outbuf;
596 s->stream.avail_out = Z_BUFSIZE;
598 if (done) break;
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)
618 MEMFILE *file;
619 uLong x;
621 int n;
622 for (n = 0; n < 4; n++) {
623 memPutc((int)(x & 0xff), file);
624 x >>= 8;
628 /* ===========================================================================
629 Reads a long in LSB order from the given mem_stream. Sets z_err in case
630 of error.
632 local uLong getLong (s)
633 mem_stream *s;
635 uLong x = (uLong)get_byte(s);
636 int c;
638 x += ((uLong)get_byte(s))<<8;
639 x += ((uLong)get_byte(s))<<16;
640 c = get_byte(s);
641 if (c == EOF) s->z_err = Z_DATA_ERROR;
642 x += ((uLong)c)<<24;
643 return x;
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)
651 gzFile file;
653 int err;
654 mem_stream *s = (mem_stream*)file;
656 if (s == NULL) return Z_STREAM_ERROR;
658 if (s->mode == 'w') {
659 #ifdef NO_DEFLATE
660 return Z_STREAM_ERROR;
661 #else
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);
667 #endif
669 return destroy((mem_stream*)file);
672 long ZEXPORT memtell(file)
673 gzFile file;
675 mem_stream *s = (mem_stream*)file;
677 if (s == NULL) return Z_STREAM_ERROR;
679 return memTell(s->file);