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