1 /* gzio.c -- IO on .gz files
2 * Copyright (C) 1995-2005 Jean-loup Gailly.
3 * For conditions of distribution and use, see copyright notice in zlib.h
4 *
5 * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
6 */
7
8 /* @(#) $Id: gzio.cpp,v 1.4 2010-02-23 16:24:20 jeanlf Exp $ */
9
10 #include <gpac/tools.h>
11
12 #ifndef GPAC_DISABLE_ZLIB
13
14 #include "zutil.h"
15
16 # define NO_GZCOMPRESS
17
18 #ifndef NO_DUMMY_DECL
19 #ifndef __SYMBIAN32__
20 struct internal_state {
21 int dummy;
22 }; /* for buggy compilers */
23 #endif
24 #endif
25
26 #ifndef Z_BUFSIZE
27 # ifdef MAXSEG_64K
28 # define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
29 # else
30 # define Z_BUFSIZE 16384
31 # endif
32 #endif
33 #ifndef Z_PRINTF_BUFSIZE
34 # define Z_PRINTF_BUFSIZE 4096
35 #endif
36
37 #ifdef __MVS__
38 # pragma map (fdopen , "\174\174FDOPEN")
39 FILE *fdopen(int, const char *);
40 #endif
41
42 #ifndef STDC
43 //extern voidp gf_malloc OF((uInt size));
44 //extern void free OF((voidpf ptr));
45 #endif
46
47 #define ALLOC(size) gf_malloc(size)
48 #define TRYFREE(p) {if (p) gf_free(p);}
49
50 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
51
52 /* gzip flag byte */
53 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
54 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
55 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
56 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
57 #define COMMENT 0x10 /* bit 4 set: file comment present */
58 #define RESERVED 0xE0 /* bits 5..7: reserved */
59
60 const char * const gf_z_errmsg[10] = {
61 "need dictionary", /* Z_NEED_DICT 2 */
62 "stream end", /* Z_STREAM_END 1 */
63 "", /* Z_OK 0 */
64 "file error", /* Z_ERRNO (-1) */
65 "stream error", /* Z_STREAM_ERROR (-2) */
66 "data error", /* Z_DATA_ERROR (-3) */
67 "insufficient memory", /* Z_MEM_ERROR (-4) */
68 "buffer error", /* Z_BUF_ERROR (-5) */
69 "incompatible version",/* Z_VERSION_ERROR (-6) */
70 ""
71 };
72
73 typedef struct gz_stream {
74 z_stream stream;
75 int z_err; /* error code for last stream operation */
76 int z_eof; /* set if end of input file */
77 FILE *file; /* .gz file */
78 Byte *inbuf; /* input buffer */
79 Byte *outbuf; /* output buffer */
80 uLong crc; /* crc32 of uncompressed data */
81 char *msg; /* error message */
82 char *path; /* path name for debugging only */
83 int transparent; /* 1 if input file is not a .gz file */
84 char mode; /* 'w' or 'r' */
85 z_off_t start; /* start of compressed data in file (header skipped) */
86 z_off_t in; /* bytes into deflate or inflate */
87 z_off_t out; /* bytes out of deflate or inflate */
88 int back; /* one character push-back */
89 int last; /* true if push-back is last character */
90 } gz_stream;
91
92
93 //local gzFile gz_open OF((const char *path, const char *mode, int fd));
94 //local int do_flush OF((gzFile file, int flush));
95 //local int get_byte OF((gz_stream *s));
96 local void check_header OF((gz_stream *s));
97 local int destroy OF((gz_stream *s));
98 //local void putLong OF((FILE *file, uLong x));
99 local uLong getLong OF((gz_stream *s));
100
101 /* ===========================================================================
102 Opens a gzip (.gz) file for reading or writing. The mode parameter
103 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
104 or path name (if fd == -1).
105 gz_open returns NULL if the file could not be opened or if there was
106 insufficient memory to allocate the (de)compression state; errno
107 can be checked to distinguish the two cases (if errno is zero, the
108 zlib error is Z_MEM_ERROR).
109 */
110 GF_EXPORT
gf_gzopen(const char * path,const char * mode)111 void *gf_gzopen(const char *path, const char *mode)
112 {
113 int err;
114 #ifndef NO_GZCOMPRESS
115 int level = Z_DEFAULT_COMPRESSION; /* compression level */
116 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
117 #endif
118 char *p = (char*)mode;
119 gz_stream *s;
120 char fmode[80]; /* copy of mode, without the compression level */
121 char *m = fmode;
122
123 if (!path || !mode) return Z_NULL;
124
125 s = (gz_stream *)ALLOC(sizeof(gz_stream));
126 if (!s) return Z_NULL;
127
128 s->stream.zalloc = (alloc_func)0;
129 s->stream.zfree = (free_func)0;
130 s->stream.opaque = (voidpf)0;
131 s->stream.next_in = s->inbuf = Z_NULL;
132 s->stream.next_out = s->outbuf = Z_NULL;
133 s->stream.avail_in = s->stream.avail_out = 0;
134 s->file = NULL;
135 s->z_err = Z_OK;
136 s->z_eof = 0;
137 s->in = 0;
138 s->out = 0;
139 s->back = EOF;
140 s->crc = crc32(0L, Z_NULL, 0);
141 s->msg = NULL;
142 s->transparent = 0;
143
144 s->path = (char*)ALLOC(strlen(path)+1);
145 if (s->path == NULL) {
146 destroy(s);
147 return (gzFile)Z_NULL;
148 }
149 strcpy(s->path, path); /* do this early for debugging */
150
151 s->mode = '\0';
152 do {
153 if (*p == 'r') s->mode = 'r';
154 if (*p == 'w' || *p == 'a') s->mode = 'w';
155 if (*p >= '0' && *p <= '9') {
156 #ifndef NO_GZCOMPRESS
157 level = *p - '0';
158 #endif
159 }
160 else if (*p == 'f') {
161 #ifndef NO_GZCOMPRESS
162 strategy = Z_FILTERED;
163 #endif
164 } else if (*p == 'h') {
165 #ifndef NO_GZCOMPRESS
166 strategy = Z_HUFFMAN_ONLY;
167 //} else if (*p == 'R') {
168 // strategy = Z_RLE;
169 #endif
170 } else {
171 *m++ = *p; /* copy the mode */
172 }
173 } while (*p++ && m != fmode + sizeof(fmode));
174 if (s->mode == '\0') {
175 destroy(s);
176 return Z_NULL;
177 }
178
179 if (s->mode == 'w') {
180 #ifdef NO_GZCOMPRESS
181 err = Z_STREAM_ERROR;
182 #else
183 err = deflateInit2(&(s->stream), level,
184 Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
185 /* windowBits is passed < 0 to suppress zlib header */
186
187 s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
188 #endif
189 if (err != Z_OK || s->outbuf == Z_NULL) {
190 destroy(s);
191 return Z_NULL;
192 }
193 } else {
194 s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
195
196 err = inflateInit2(&(s->stream), -MAX_WBITS);
197 /* windowBits is passed < 0 to tell that there is no zlib header.
198 * Note that in this case inflate *requires* an extra "dummy" byte
199 * after the compressed stream in order to complete decompression and
200 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
201 * present after the compressed stream.
202 */
203 if (err != Z_OK || s->inbuf == Z_NULL) {
204 destroy(s);
205 return Z_NULL;
206 }
207 }
208 s->stream.avail_out = Z_BUFSIZE;
209
210 errno = 0;
211 s->file = gf_fopen(path, fmode);
212
213 if (s->file == NULL) {
214 destroy(s);
215 return (gzFile)Z_NULL;
216 }
217 if (s->mode == 'w') {
218 #ifndef NO_GZCOMPRESS
219 destroy(s);
220 return (gzFile)Z_NULL;
221 #else
222 /* Write a very simple .gz header:
223 */
224 gf_fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
225 Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
226 s->start = 10L;
227 /* We use 10L instead of ftell(s->file) to because ftell causes an
228 * fflush on some systems. This version of the library doesn't use
229 * start anyway in write mode, so this initialization is not
230 * necessary.
231 */
232 #endif
233
234 } else {
235 check_header(s); /* skip the .gz header */
236 s->start = (long) (gf_ftell(s->file) - s->stream.avail_in);
237 }
238
239 return (gzFile)s;
240 }
241
242
243 /* ===========================================================================
244 Read a byte from a gz_stream; update next_in and avail_in. Return EOF
245 for end of file.
246 IN assertion: the stream s has been sucessfully opened for reading.
247 */
get_byte(gz_stream * s)248 local int get_byte(gz_stream *s)
249 {
250 if (s->z_eof) return EOF;
251 if (s->stream.avail_in == 0) {
252 errno = 0;
253 s->stream.avail_in = (uInt)gf_fread(s->inbuf, Z_BUFSIZE, s->file);
254 if (s->stream.avail_in == 0) {
255 s->z_eof = 1;
256 if (gf_ferror(s->file)) s->z_err = Z_ERRNO;
257 return EOF;
258 }
259 s->stream.next_in = s->inbuf;
260 }
261 s->stream.avail_in--;
262 return *(s->stream.next_in)++;
263 }
264
265 /* ===========================================================================
266 Check the gzip header of a gz_stream opened for reading. Set the stream
267 mode to transparent if the gzip magic header is not present; set s->err
268 to Z_DATA_ERROR if the magic header is present but the rest of the header
269 is incorrect.
270 IN assertion: the stream s has already been created sucessfully;
271 s->stream.avail_in is zero for the first time, but may be non-zero
272 for concatenated .gz files.
273 */
check_header(gz_stream * s)274 local void check_header(gz_stream *s)
275 {
276 int method; /* method byte */
277 int flags; /* flags byte */
278 uInt len;
279 int c;
280
281 /* Assure two bytes in the buffer so we can peek ahead -- handle case
282 where first byte of header is at the end of the buffer after the last
283 gzip segment */
284 len = s->stream.avail_in;
285 if (len < 2) {
286 if (len) s->inbuf[0] = s->stream.next_in[0];
287 errno = 0;
288 len = (uInt)gf_fread(s->inbuf + len, Z_BUFSIZE >> len, s->file);
289 if (len == 0 && gf_ferror(s->file)) s->z_err = Z_ERRNO;
290 s->stream.avail_in += len;
291 s->stream.next_in = s->inbuf;
292 if (s->stream.avail_in < 2) {
293 s->transparent = s->stream.avail_in;
294 return;
295 }
296 }
297
298 /* Peek ahead to check the gzip magic header */
299 if (s->stream.next_in[0] != gz_magic[0] ||
300 s->stream.next_in[1] != gz_magic[1]) {
301 s->transparent = 1;
302 return;
303 }
304 s->stream.avail_in -= 2;
305 s->stream.next_in += 2;
306
307 /* Check the rest of the gzip header */
308 method = get_byte(s);
309 flags = get_byte(s);
310 if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
311 s->z_err = Z_DATA_ERROR;
312 return;
313 }
314
315 /* Discard time, xflags and OS code: */
316 for (len = 0; len < 6; len++) (void)get_byte(s);
317
318 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
319 len = (uInt)get_byte(s);
320 len += ((uInt)get_byte(s))<<8;
321 /* len is garbage if EOF but the loop below will quit anyway */
322 while (len-- != 0 && get_byte(s) != EOF) ;
323 }
324 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
325 while ((c = get_byte(s)) != 0 && c != EOF) ;
326 }
327 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
328 while ((c = get_byte(s)) != 0 && c != EOF) ;
329 }
330 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
331 for (len = 0; len < 2; len++) (void)get_byte(s);
332 }
333 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
334 }
335
336 /* ===========================================================================
337 * Cleanup then free the given gz_stream. Return a zlib error code.
338 Try freeing in the reverse order of allocations.
339 */
destroy(gz_stream * s)340 local int destroy (gz_stream *s)
341 {
342 int err = Z_OK;
343
344 if (!s) return Z_STREAM_ERROR;
345
346 TRYFREE(s->msg);
347
348 if (s->stream.state != NULL) {
349 if (s->mode == 'w') {
350 #ifdef NO_GZCOMPRESS
351 err = Z_STREAM_ERROR;
352 #else
353 err = deflateEnd(&(s->stream));
354 #endif
355 } else if (s->mode == 'r') {
356 err = inflateEnd(&(s->stream));
357 }
358 }
359 if (s->file != NULL && gf_fclose(s->file)) {
360 #ifdef ESPIPE
361 if (errno != ESPIPE) /* gf_fclose is broken for pipes in HP/UX */
362 #endif
363 err = Z_ERRNO;
364 }
365 if (s->z_err < 0) err = s->z_err;
366
367 TRYFREE(s->inbuf);
368 TRYFREE(s->outbuf);
369 TRYFREE(s->path);
370 TRYFREE(s);
371 return err;
372 }
373
374 GF_EXPORT
gf_gzread(void * file,voidp buf,unsigned len)375 int gf_gzread(void *file, voidp buf, unsigned len)
376 {
377 gz_stream *s = (gz_stream*)file;
378 Bytef *start = (Bytef*)buf; /* starting point for crc computation */
379 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
380
381 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
382
383 if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
384 if (s->z_err == Z_STREAM_END) return 0; /* EOF */
385
386 next_out = (Byte*)buf;
387 s->stream.next_out = (Bytef*)buf;
388 s->stream.avail_out = len;
389
390 if (s->stream.avail_out && s->back != EOF) {
391 *next_out++ = s->back;
392 s->stream.next_out++;
393 s->stream.avail_out--;
394 s->back = EOF;
395 s->out++;
396 start++;
397 if (s->last) {
398 s->z_err = Z_STREAM_END;
399 return 1;
400 }
401 }
402
403 while (s->stream.avail_out != 0) {
404
405 if (s->transparent) {
406 /* Copy first the lookahead bytes: */
407 uInt n = s->stream.avail_in;
408 if (n > s->stream.avail_out) n = s->stream.avail_out;
409 if (n > 0) {
410 zmemcpy(s->stream.next_out, s->stream.next_in, n);
411 next_out += n;
412 s->stream.next_out = next_out;
413 s->stream.next_in += n;
414 s->stream.avail_out -= n;
415 s->stream.avail_in -= n;
416 }
417 if (s->stream.avail_out > 0) {
418 s->stream.avail_out -=
419 (uInt)gf_fread(next_out, s->stream.avail_out, s->file);
420 }
421 len -= s->stream.avail_out;
422 s->in += len;
423 s->out += len;
424 if (len == 0) s->z_eof = 1;
425 return (int)len;
426 }
427 if (s->stream.avail_in == 0 && !s->z_eof) {
428
429 errno = 0;
430 s->stream.avail_in = (uInt)gf_fread(s->inbuf, Z_BUFSIZE, s->file);
431 if (s->stream.avail_in == 0) {
432 s->z_eof = 1;
433 if (gf_ferror(s->file)) {
434 s->z_err = Z_ERRNO;
435 break;
436 }
437 }
438 s->stream.next_in = s->inbuf;
439 }
440 s->in += s->stream.avail_in;
441 s->out += s->stream.avail_out;
442 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
443 s->in -= s->stream.avail_in;
444 s->out -= s->stream.avail_out;
445
446 if (s->z_err == Z_STREAM_END) {
447 /* Check CRC and original size */
448 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
449 start = s->stream.next_out;
450
451 if (getLong(s) != s->crc) {
452 s->z_err = Z_DATA_ERROR;
453 } else {
454 (void)getLong(s);
455 /* The uncompressed length returned by above getlong() may be
456 * different from s->out in case of concatenated .gz files.
457 * Check for such files:
458 */
459 check_header(s);
460 if (s->z_err == Z_OK) {
461 inflateReset(&(s->stream));
462 s->crc = crc32(0L, Z_NULL, 0);
463 }
464 }
465 }
466 if (s->z_err != Z_OK || s->z_eof) break;
467 }
468 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
469
470 if (len == s->stream.avail_out &&
471 (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
472 return -1;
473 return (int)(len - s->stream.avail_out);
474 }
475
476
477 /* ===========================================================================
478 Reads one byte from the compressed file. gf_gzgetc returns this byte
479 or -1 in case of end of file or error.
480 */
481 GF_EXPORT
gf_gzgetc(void * file)482 int gf_gzgetc(void *file)
483 {
484 unsigned char c;
485
486 return gf_gzread(file, &c, 1) == 1 ? c : -1;
487 }
488
489
490 #if 0
491
492 /* ===========================================================================
493 Push one byte back onto the stream.
494 */
495 int gzungetc(int c, gzFile file)
496 {
497 gz_stream *s = (gz_stream*)file;
498
499 if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
500 s->back = c;
501 s->out--;
502 s->last = (s->z_err == Z_STREAM_END);
503 if (s->last) s->z_err = Z_OK;
504 s->z_eof = 0;
505 return c;
506 }
507
508 #endif
509
510
511 /* ===========================================================================
512 Reads bytes from the compressed file until len-1 characters are
513 read, or a newline character is read and transferred to buf, or an
514 end-of-file condition is encountered. The string is then terminated
515 with a null character.
516 gf_gzgets returns buf, or Z_NULL in case of error.
517
518 The current implementation is not optimized at all.
519 */
520 GF_EXPORT
gf_gzgets(void * file,char * buf,int len)521 char * gf_gzgets(void *file, char *buf, int len)
522 {
523 char *b = buf;
524 if (buf == Z_NULL || len <= 0) return Z_NULL;
525
526 while (--len > 0 && gf_gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
527 *buf = '\0';
528 return b == buf && len > 0 ? Z_NULL : b;
529 }
530
531
532 #ifndef NO_GZCOMPRESS
533 /* ===========================================================================
534 Writes the given number of uncompressed bytes into the compressed file.
535 gf_gzwrite returns the number of bytes actually written (0 in case of error).
536 */
gf_gzwrite(gzFile file,void * const buf,unsigned len)537 int gf_gzwrite (gzFile file, void *const buf, unsigned len)
538 {
539 gz_stream *s = (gz_stream*)file;
540
541 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
542
543 s->stream.next_in = (Bytef*)buf;
544 s->stream.avail_in = len;
545
546 while (s->stream.avail_in != 0) {
547
548 if (s->stream.avail_out == 0) {
549
550 s->stream.next_out = s->outbuf;
551 if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
552 s->z_err = Z_ERRNO;
553 break;
554 }
555 s->stream.avail_out = Z_BUFSIZE;
556 }
557 s->in += s->stream.avail_in;
558 s->out += s->stream.avail_out;
559 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
560 s->in -= s->stream.avail_in;
561 s->out -= s->stream.avail_out;
562 if (s->z_err != Z_OK) break;
563 }
564 s->crc = crc32(s->crc, (const Bytef *)buf, len);
565
566 return (int)(len - s->stream.avail_in);
567 }
568
569
570 /* ===========================================================================
571 Converts, formats, and writes the args to the compressed file under
572 control of the format string, as in fprintf. gf_gzprintf returns the number of
573 uncompressed bytes actually written (0 in case of error).
574 */
575 #ifdef STDC
576 #include <stdarg.h>
577
gf_gzprintf(gzFile file,const char * format,...)578 int gf_gzprintf (gzFile file, const char *format, /* args */ ...)
579 {
580 char buf[Z_PRINTF_BUFSIZE];
581 va_list va;
582 int len = 0;
583
584 buf[sizeof(buf) - 1] = 0;
585 va_start(va, format);
586 #ifdef NO_vsnprintf
587 # ifdef HAS_vsprintf_void
588 (void)vsprintf(buf, format, va);
589 va_end(va);
590 for (len = 0; len < sizeof(buf); len++)
591 if (buf[len] == 0) break;
592 # else
593 len = vsprintf(buf, format, va);
594 va_end(va);
595 # endif
596 #else
597 # ifdef HAS_vsnprintf_void
598 (void)vsnprintf(buf, sizeof(buf), format, va);
599 va_end(va);
600 len = strlen(buf);
601 # else
602 len = vsnprintf(buf, sizeof(buf), format, va);
603 va_end(va);
604 # endif
605 #endif
606 if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
607 return 0;
608 return gf_gzwrite(file, buf, (unsigned)len);
609 }
610 #else /* not ANSI C */
611
gf_gzprintf(gzFile file,const char * format,int a1,int a2,int a3,int a4,int a5,int a6,int a7,int a8,int a9,int a10,int a11,int a12,int a13,int a14,int a15,int a16,int a17,int a18,int a19,int a20)612 int gf_gzprintf (gzFile file, const char *format, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10,
613 int a11, int a12, int a13, int a14, int a15, int a16, int a17, int a18, int a19, int a20)
614 {
615 char buf[Z_PRINTF_BUFSIZE];
616 int len;
617
618 buf[sizeof(buf) - 1] = 0;
619 #ifdef NO_snprintf
620 # ifdef HAS_sprintf_void
621 sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
622 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
623 for (len = 0; len < sizeof(buf); len++)
624 if (buf[len] == 0) break;
625 # else
626 len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
627 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
628 # endif
629 #else
630 # ifdef HAS_snprintf_void
631 snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
632 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
633 len = strlen(buf);
634 # else
635 len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
636 a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
637 # endif
638 #endif
639 if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
640 return 0;
641 return gf_gzwrite(file, buf, len);
642 }
643 #endif
644
645 /* ===========================================================================
646 Writes c, converted to an unsigned char, into the compressed file.
647 gf_gzputc returns the value that was written, or -1 in case of error.
648 */
649 GF_EXPORT
gf_gzputc(gzFile file,int c)650 int gf_gzputc(gzFile file, int c)
651 {
652 unsigned char cc = (unsigned char) c; /* required for big endian systems */
653
654 return gf_gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
655 }
656
657
658 /* ===========================================================================
659 Writes the given null-terminated string to the compressed file, excluding
660 the terminating null character.
661 gf_gzputs returns the number of characters written, or -1 in case of error.
662 */
gf_gzputs(gzFile file,const char * s)663 int gf_gzputs(gzFile file, const char *s)
664 {
665 return gf_gzwrite(file, (char*)s, (unsigned)strlen(s));
666 }
667
668
669 /* ===========================================================================
670 Flushes all pending output into the compressed file. The parameter
671 flush is as in the deflate() function.
672 */
do_flush(gzFile file,int flush)673 local int do_flush (gzFile file, int flush)
674 {
675 uInt len;
676 int done = 0;
677 gz_stream *s = (gz_stream*)file;
678
679 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
680
681 s->stream.avail_in = 0; /* should be zero already anyway */
682
683 for (;;) {
684 len = Z_BUFSIZE - s->stream.avail_out;
685
686 if (len != 0) {
687 if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
688 s->z_err = Z_ERRNO;
689 return Z_ERRNO;
690 }
691 s->stream.next_out = s->outbuf;
692 s->stream.avail_out = Z_BUFSIZE;
693 }
694 if (done) break;
695 s->out += s->stream.avail_out;
696 s->z_err = deflate(&(s->stream), flush);
697 s->out -= s->stream.avail_out;
698
699 /* Ignore the second of two consecutive flushes: */
700 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
701
702 /* deflate has finished flushing only when it hasn't used up
703 * all the available space in the output buffer:
704 */
705 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
706
707 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
708 }
709 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
710 }
711
gf_gzflush(gzFile file,int flush)712 int gf_gzflush (gzFile file, int flush)
713 {
714 gz_stream *s = (gz_stream*)file;
715 int err = do_flush (file, flush);
716
717 if (err) return err;
718 fflush(s->file);
719 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
720 }
721 #endif /* NO_GZCOMPRESS */
722
723 /* ===========================================================================
724 Rewinds input file.
725 */
726 GF_EXPORT
gf_gzrewind(void * file)727 s64 gf_gzrewind(void *file)
728 {
729 gz_stream *s = (gz_stream*)file;
730
731 if (s == NULL || s->mode != 'r') return -1;
732
733 s->z_err = Z_OK;
734 s->z_eof = 0;
735 s->back = EOF;
736 s->stream.avail_in = 0;
737 s->stream.next_in = s->inbuf;
738 s->crc = crc32(0L, Z_NULL, 0);
739 if (!s->transparent) (void)inflateReset(&s->stream);
740 s->in = 0;
741 s->out = 0;
742 return (s64) gf_fseek(s->file, s->start, SEEK_SET);
743 }
744
745 /* ===========================================================================
746 Sets the starting position for the next gf_gzread or gf_gzwrite on the given
747 compressed file. The offset represents a number of bytes in the
748 gf_gzseek returns the resulting offset location as measured in bytes from
749 the beginning of the uncompressed stream, or -1 in case of error.
750 SEEK_END is not implemented, returns error.
751 In this version of the library, gf_gzseek can be extremely slow.
752 */
753 GF_EXPORT
gf_gzseek(void * file,u64 _offset,int whence)754 u64 gf_gzseek(void *file, u64 _offset, int whence)
755 {
756 gz_stream *s = (gz_stream*)file;
757 s64 offset = (s64) _offset;
758
759 if (s == NULL || whence == SEEK_END ||
760 s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
761 return -1L;
762 }
763
764 if (s->mode == 'w') {
765 #ifdef NO_GZCOMPRESS
766 return -1L;
767 #else
768 if (whence == SEEK_SET) {
769 offset -= s->in;
770 }
771 if (offset < 0) return -1L;
772
773 /* At this point, offset is the number of zero bytes to write. */
774 if (s->inbuf == Z_NULL) {
775 s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
776 if (s->inbuf == Z_NULL) return -1L;
777 zmemzero(s->inbuf, Z_BUFSIZE);
778 }
779 while (offset > 0) {
780 uInt size = Z_BUFSIZE;
781 if (offset < Z_BUFSIZE) size = (uInt)offset;
782
783 size = gf_gzwrite(file, s->inbuf, size);
784 if (size == 0) return -1L;
785
786 offset -= size;
787 }
788 return s->in;
789 #endif
790 }
791 /* Rest of function is for reading only */
792
793 /* compute absolute position */
794 if (whence == SEEK_CUR) {
795 offset += s->out;
796 }
797 if (offset < 0) return -1L;
798
799 if (s->transparent) {
800 /* map to fseek */
801 s->back = EOF;
802 s->stream.avail_in = 0;
803 s->stream.next_in = s->inbuf;
804 if (gf_fseek(s->file, offset, SEEK_SET) < 0) return -1L;
805
806 s->in = s->out = (long) offset;
807 return offset;
808 }
809
810 /* For a negative seek, rewind and use positive seek */
811 if (offset >= s->out) {
812 offset -= s->out;
813 } else if (gf_gzrewind(file) < 0) {
814 return -1L;
815 }
816 /* offset is now the number of bytes to skip. */
817
818 if (offset != 0 && s->outbuf == Z_NULL) {
819 s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
820 if (s->outbuf == Z_NULL) return -1L;
821 }
822 if (offset && s->back != EOF) {
823 s->back = EOF;
824 s->out++;
825 offset--;
826 if (s->last) s->z_err = Z_STREAM_END;
827 }
828 while (offset > 0) {
829 int size = Z_BUFSIZE;
830 if (offset < Z_BUFSIZE) size = (int)offset;
831
832 size = gf_gzread(file, s->outbuf, (uInt)size);
833 if (size <= 0) return -1L;
834 offset -= size;
835 }
836 return s->out;
837 }
838
839 /* ===========================================================================
840 Returns the starting position for the next gf_gzread or gf_gzwrite on the
841 given compressed file. This position represents a number of bytes in the
842 uncompressed data stream.
843 */
844 GF_EXPORT
gf_gztell(void * file)845 u64 gf_gztell(void *file)
846 {
847 return gf_gzseek(file, 0L, SEEK_CUR);
848 }
849
850 /* ===========================================================================
851 Returns 1 when EOF has previously been detected reading the given
852 input stream, otherwise zero.
853 */
854 GF_EXPORT
gf_gzeof(void * file)855 int gf_gzeof(void *file)
856 {
857 gz_stream *s = (gz_stream*)file;
858
859 /* With concatenated compressed files that can have embedded
860 * crc trailers, z_eof is no longer the only/best indicator of EOF
861 * on a gz_stream. Handle end-of-stream error explicitly here.
862 */
863 if (s == NULL || s->mode != 'r') return 0;
864 if (s->z_eof) return 1;
865 return s->z_err == Z_STREAM_END;
866 }
867
868 /* ===========================================================================
869 Returns 1 if reading and doing so transparently, otherwise zero.
870 */
871 GF_EXPORT
gf_gzdirect(void * file)872 int gf_gzdirect (void * file)
873 {
874 gz_stream *s = (gz_stream*)file;
875
876 if (s == NULL || s->mode != 'r') return 0;
877 return s->transparent;
878 }
879
880 #if 0
881 /* ===========================================================================
882 Outputs a long in LSB order to the given file
883 */
884 local void putLong (FILE *file, uLong x)
885 {
886 int n;
887 for (n = 0; n < 4; n++) {
888 fputc((int)(x & 0xff), file);
889 x >>= 8;
890 }
891 }
892 #endif
893
894 /* ===========================================================================
895 Reads a long in LSB order from the given gz_stream. Sets z_err in case
896 of error.
897 */
getLong(gz_stream * s)898 local uLong getLong (gz_stream *s)
899 {
900 uLong x = (uLong)get_byte(s);
901 int c;
902
903 x += ((uLong)get_byte(s))<<8;
904 x += ((uLong)get_byte(s))<<16;
905 c = get_byte(s);
906 if (c == EOF) s->z_err = Z_DATA_ERROR;
907 x += ((uLong)c)<<24;
908 return x;
909 }
910
911 /* ===========================================================================
912 Flushes all pending output if necessary, closes the compressed file
913 and deallocates all the (de)compression state.
914 */
915 GF_EXPORT
gf_gzclose(void * file)916 int gf_gzclose(void *file)
917 {
918 gz_stream *s = (gz_stream*)file;
919
920 if (s == NULL) return Z_STREAM_ERROR;
921
922 if (s->mode == 'w') {
923 #ifdef NO_GZCOMPRESS
924 return Z_STREAM_ERROR;
925 #else
926 if (do_flush (file, Z_FINISH) != Z_OK)
927 return destroy((gz_stream*)file);
928
929 putLong (s->file, s->crc);
930 putLong (s->file, (uLong)(s->in & 0xffffffff));
931 #endif
932 }
933 return destroy((gz_stream*)file);
934 }
935
936 #ifdef STDC
937 # define zstrerror(errnum) strerror(errnum)
938 #else
939 # define zstrerror(errnum) ""
940 #endif
941
942 /* ===========================================================================
943 Returns the error message for the last error which occurred on the
944 given compressed file. errnum is set to zlib error number. If an
945 error occurred in the file system and not in the compression library,
946 errnum is set to Z_ERRNO and the application may consult errno
947 to get the exact error code.
948 */
949 GF_EXPORT
gf_gzerror(void * file,int * errnum)950 const char * gf_gzerror (void *file, int *errnum)
951 {
952 char *m;
953 gz_stream *s = (gz_stream*)file;
954
955 if (s == NULL) {
956 *errnum = Z_STREAM_ERROR;
957 return (const char*)ERR_MSG(Z_STREAM_ERROR);
958 }
959 *errnum = s->z_err;
960 if (*errnum == Z_OK) return (const char*)"";
961
962 m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
963
964 if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
965
966 TRYFREE(s->msg);
967 s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
968 if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
969 strcpy(s->msg, s->path);
970 strcat(s->msg, ": ");
971 strcat(s->msg, m);
972 return (const char*)s->msg;
973 }
974
975 /* ===========================================================================
976 Clear the error and end-of-file flags, and do the same for the real file.
977 */
978 GF_EXPORT
gf_gzclearerr(void * file)979 void gf_gzclearerr(void *file)
980 {
981 gz_stream *s = (gz_stream*)file;
982
983 if (s == NULL) return;
984 if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
985 s->z_eof = 0;
986 clearerr(s->file);
987 }
988
989 #endif //GPAC_DISABLE_ZLIB
990