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