1 /*
2 Based on gzio.c from zlib 1.2.3, but considerably modified!
3
4 Copyright (C) 1995-2005 Jean-loup Gailly.
5 For conditions of distribution and use, see copyright notice in zlib.h:
6
7 This software is provided 'as-is', without any express or implied
8 warranty. In no event will the authors be held liable for any damages
9 arising from the use of this software.
10
11 Permission is granted to anyone to use this software for any purpose,
12 including commercial applications, and to alter it and redistribute it
13 freely, subject to the following restrictions:
14
15 1. The origin of this software must not be misrepresented; you must not
16 claim that you wrote the original software. If you use this software
17 in a product, an acknowledgment in the product documentation would be
18 appreciated but is not required.
19 2. Altered source versions must be plainly marked as such, and must not be
20 misrepresented as being the original software.
21 3. This notice may not be removed or altered from any source distribution.
22
23 Jean-loup Gailly Mark Adler
24 jloup@gzip.org madler@alumni.caltech.edu
25
26 */
27
28
29 #ifdef HAVE_CONFIG_H
30 #include <config.h> /* for Win32, HAVE_OFF_T and HAVE_FSEEKO */
31 #endif
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37
38 #include "zlib.h"
39
40 #ifdef Win32
41 # define OS_CODE 0x06
42 #else
43 # define OS_CODE 0x03
44 #endif
45
46 /* R ADDITION */
47 #ifdef Win32
48 # define Rz_off_t off64_t
49 #elif defined(HAVE_OFF_T) && defined(HAVE_FSEEKO)
50 # define Rz_off_t off_t
51 #else
52 # define Rz_off_t long
53 #endif
54
55
56 #define Z_BUFSIZE 16384
57
58 typedef struct gz_stream {
59 z_stream stream;
60 int z_err; /* error code for last stream operation */
61 int z_eof; /* set if end of input file */
62 FILE *file; /* .gz file */
63 Byte buffer[Z_BUFSIZE]; /* input or output buffer */
64 uLong crc; /* crc32 of uncompressed data */
65 int transparent; /* 1 if input file is not compressed */
66 char mode; /* 'w' or 'r' */
67 Rz_off_t start; /* start of compressed data in file (header skipped) */
68 Rz_off_t in; /* bytes into deflate or inflate */
69 Rz_off_t out; /* bytes out of deflate or inflate */
70 } gz_stream;
71
72
get_byte(gz_stream * s)73 static int get_byte(gz_stream *s)
74 {
75 if (s->z_eof) return EOF;
76 if (s->stream.avail_in == 0) {
77 errno = 0;
78 s->stream.avail_in = (uInt) fread(s->buffer, 1, Z_BUFSIZE, s->file);
79 if (s->stream.avail_in == 0) {
80 s->z_eof = 1;
81 if (ferror(s->file)) s->z_err = Z_ERRNO;
82 return EOF;
83 }
84 s->stream.next_in = s->buffer;
85 }
86 s->stream.avail_in--;
87 return *(s->stream.next_in)++;
88 }
89
destroy(gz_stream * s)90 static int destroy (gz_stream *s)
91 {
92 int err = Z_OK;
93
94 if (!s) return Z_STREAM_ERROR;
95
96 if (s->stream.state != NULL) {
97 if (s->mode == 'w') err = deflateEnd(&(s->stream));
98 else if (s->mode == 'r') err = inflateEnd(&(s->stream));
99 }
100 if (s->file != NULL && fclose(s->file)) {
101 #ifdef ESPIPE
102 if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
103 #endif
104 err = Z_ERRNO;
105 }
106 if (s->z_err < 0) err = s->z_err;
107
108 if(s) free(s);
109 return err;
110 }
111
112 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
113
114 /* gzip flag byte */
115 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text, unused */
116 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
117 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
118 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
119 #define COMMENT 0x10 /* bit 4 set: file comment present */
120 #define RESERVED 0xE0 /* bits 5..7: reserved */
121
check_header(gz_stream * s)122 static void check_header(gz_stream *s)
123 {
124 int method; /* method byte */
125 int flags; /* flags byte */
126 uInt len;
127 int c;
128
129 /* Assure two bytes in the buffer so we can peek ahead -- handle case
130 where first byte of header is at the end of the buffer after the last
131 gzip segment */
132 len = s->stream.avail_in;
133 if (len < 2) {
134 if (len) s->buffer[0] = s->stream.next_in[0];
135 errno = 0;
136 len = (uInt) fread(s->buffer + len, 1, Z_BUFSIZE >> len, s->file);
137 if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
138 s->stream.avail_in += len;
139 s->stream.next_in = s->buffer;
140 if (s->stream.avail_in < 2) {
141 s->transparent = s->stream.avail_in;
142 return;
143 }
144 }
145
146 /* Peek ahead to check the gzip magic header */
147 if (s->stream.next_in[0] != gz_magic[0] ||
148 s->stream.next_in[1] != gz_magic[1]) {
149 s->transparent = 1;
150 return;
151 }
152 s->stream.avail_in -= 2;
153 s->stream.next_in += 2;
154
155 /* Check the rest of the gzip header */
156 method = get_byte(s);
157 flags = get_byte(s);
158 if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
159 s->z_err = Z_DATA_ERROR;
160 return;
161 }
162
163 /* Discard time, xflags and OS code: */
164 for (len = 0; len < 6; len++) (void)get_byte(s);
165
166 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
167 len = (uInt )get_byte(s);
168 len += ((uInt) get_byte(s)) << 8;
169 /* len is garbage if EOF but the loop below will quit anyway */
170 while (len-- != 0 && get_byte(s) != EOF) ;
171 }
172 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
173 while ((c = get_byte(s)) != 0 && c != EOF) ;
174 }
175 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
176 while ((c = get_byte(s)) != 0 && c != EOF) ;
177 }
178 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
179 for (len = 0; len < 2; len++) (void) get_byte(s);
180 }
181 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
182 }
183
R_gzopen(const char * path,const char * mode)184 gzFile R_gzopen (const char *path, const char *mode)
185 {
186 int err;
187 int level = Z_DEFAULT_COMPRESSION; /* compression level */
188 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
189 char *p = (char *) mode;
190 gz_stream *s;
191 char fmode[80]; /* copy of mode, without the compression level */
192 char *m = fmode;
193
194 if (!path || !mode) return Z_NULL;
195
196 s = (gz_stream *) malloc(sizeof(gz_stream));
197 if (!s) return Z_NULL;
198
199 s->stream.zalloc = (alloc_func) 0;
200 s->stream.zfree = (free_func) 0;
201 s->stream.opaque = (voidpf) 0;
202 s->stream.next_in = s->buffer;
203 s->stream.next_out = s->buffer;
204 s->stream.avail_in = s->stream.avail_out = 0;
205 s->file = NULL;
206 s->z_err = Z_OK;
207 s->z_eof = 0;
208 s->in = 0;
209 s->out = 0;
210 s->crc = crc32(0L, Z_NULL, 0);
211 s->transparent = 0;
212 s->mode = '\0';
213 do {
214 if (*p == 'r') s->mode = 'r';
215 if (*p == 'w' || *p == 'a') s->mode = 'w';
216 if (*p >= '0' && *p <= '9') level = *p - '0';
217 else if (*p == 'f') strategy = Z_FILTERED;
218 else if (*p == 'h') strategy = Z_HUFFMAN_ONLY;
219 else if (*p == 'R') strategy = Z_RLE;
220 else *m++ = *p; /* copy the mode */
221 } while (*p++ && m != fmode + sizeof(fmode));
222 if (s->mode == '\0') return destroy(s), (gzFile) Z_NULL;
223
224 if (s->mode == 'w') {
225 err = deflateInit2(&(s->stream), level,
226 Z_DEFLATED, -MAX_WBITS, MAX_MEM_LEVEL, strategy);
227 /* windowBits is passed < 0 to suppress zlib header */
228 if (err != Z_OK) return destroy(s), (gzFile) Z_NULL;
229 } else {
230 err = inflateInit2(&(s->stream), -MAX_WBITS);
231 /* windowBits is passed < 0 to tell that there is no zlib header.
232 * Note that in this case inflate *requires* an extra "dummy" byte
233 * after the compressed stream in order to complete decompression and
234 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
235 * present after the compressed stream.
236 */
237 if (err != Z_OK) return destroy(s), (gzFile) Z_NULL;
238 }
239 s->stream.avail_out = Z_BUFSIZE;
240
241 errno = 0;
242 s->file = fopen(path, fmode);
243 if (s->file == NULL) return destroy(s), (gzFile) Z_NULL;
244
245 if (s->mode == 'w') {
246 /* Write a very simple .gz header */
247 fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
248 Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/,
249 OS_CODE);
250 s->start = 10L;
251 } else {
252 check_header(s); /* skip the .gz header */
253 s->start = f_tell(s->file) - s->stream.avail_in;
254 }
255 return (gzFile) s;
256 }
257
z_putLong(FILE * file,uLong x)258 static void z_putLong (FILE *file, uLong x)
259 {
260 int n;
261 for (n = 0; n < 4; n++) {
262 fputc((int) (x & 0xff), file);
263 x >>= 8;
264 }
265 }
266
getLong(gz_stream * s)267 static uLong getLong (gz_stream *s)
268 {
269 uLong x = (uLong) get_byte(s);
270 int c;
271
272 x += ((uLong) get_byte(s)) << 8;
273 x += ((uLong) get_byte(s)) << 16;
274 c = get_byte(s);
275 if (c == EOF) s->z_err = Z_DATA_ERROR;
276 x += ((uLong) c) << 24;
277 return x;
278 }
279
R_gzread(gzFile file,voidp buf,unsigned len)280 static int R_gzread (gzFile file, voidp buf, unsigned len)
281 {
282 gz_stream *s = (gz_stream*) file;
283 Bytef *start = (Bytef*) buf; /* starting point for crc computation */
284 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
285
286 if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
287
288 if (s->z_err == Z_DATA_ERROR) {
289 warning("invalid or incomplete compressed data");
290 return -1;
291 } else if(s->z_err == Z_ERRNO) {
292 warning("error reading the file");
293 return -1;
294 }
295 if (s->z_err == Z_STREAM_END) return 0; /* EOF */
296
297 next_out = (Byte*) buf;
298 s->stream.next_out = (Bytef*) buf;
299 s->stream.avail_out = len;
300
301 while (s->stream.avail_out != 0) {
302
303 if (s->transparent) {
304 /* Copy first the lookahead bytes: */
305 uInt n = s->stream.avail_in;
306 if (n > s->stream.avail_out) n = s->stream.avail_out;
307 if (n > 0) {
308 memcpy(s->stream.next_out, s->stream.next_in, n);
309 next_out += n;
310 s->stream.next_out = next_out;
311 s->stream.next_in += n;
312 s->stream.avail_out -= n;
313 s->stream.avail_in -= n;
314 }
315 if (s->stream.avail_out > 0) {
316 s->stream.avail_out -=
317 (uInt) fread(next_out, 1, s->stream.avail_out, s->file);
318 }
319 len -= s->stream.avail_out;
320 s->in += len;
321 s->out += len;
322 if (len == 0) s->z_eof = 1;
323 return (int)len;
324 }
325 if (s->stream.avail_in == 0 && !s->z_eof) {
326 errno = 0;
327 s->stream.avail_in = (uInt) fread(s->buffer, 1, Z_BUFSIZE, s->file);
328 if (s->stream.avail_in == 0) {
329 s->z_eof = 1;
330 if (ferror(s->file)) {
331 s->z_err = Z_ERRNO;
332 break;
333 }
334 }
335 s->stream.next_in = s->buffer;
336 }
337 s->in += s->stream.avail_in;
338 s->out += s->stream.avail_out;
339 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
340 s->in -= s->stream.avail_in;
341 s->out -= s->stream.avail_out;
342
343 if (s->z_err == Z_STREAM_END) {
344 /* Check CRC and original size */
345 s->crc = crc32(s->crc, start, (uInt) (s->stream.next_out - start));
346 start = s->stream.next_out;
347
348 if (getLong(s) != s->crc) {
349 warning("invalid or incomplete compressed data");
350 s->z_err = Z_DATA_ERROR;
351 } else {
352 (void)getLong(s);
353 /* The uncompressed length returned by above getlong() may be
354 * different from s->out in case of concatenated .gz files.
355 * Check for such files:
356 */
357 check_header(s);
358 if (s->z_err == Z_OK) {
359 inflateReset(&(s->stream));
360 s->crc = crc32(0L, Z_NULL, 0);
361 }
362 }
363 }
364 if (s->z_err != Z_OK || s->z_eof) break;
365 }
366 s->crc = crc32(s->crc, start, (uInt) (s->stream.next_out - start));
367
368 if (len == s->stream.avail_out &&
369 (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)) {
370 if(s->z_err == Z_DATA_ERROR)
371 warning("invalid or incomplete compressed data");
372 else if(s->z_err == Z_ERRNO)
373 warning("error reading the file");
374 return -1;
375 }
376 return (int)(len - s->stream.avail_out);
377 }
378
379 /* for devPS.c */
R_gzgets(gzFile file,char * buf,int len)380 char *R_gzgets(gzFile file, char *buf, int len)
381 {
382 char *b = buf;
383 if (buf == Z_NULL || len <= 0) return Z_NULL;
384
385 while (--len > 0 && R_gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
386 *buf = '\0';
387 return b == buf && len > 0 ? Z_NULL : b;
388 }
389
390
R_gzwrite(gzFile file,voidpc buf,unsigned len)391 static int R_gzwrite (gzFile file, voidpc buf, unsigned len)
392 {
393 gz_stream *s = (gz_stream*) file;
394
395 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
396
397 s->stream.next_in = (Bytef*) buf;
398 s->stream.avail_in = len;
399
400 while (s->stream.avail_in != 0) {
401 if (s->stream.avail_out == 0) {
402 s->stream.next_out = s->buffer;
403 if (fwrite(s->buffer, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
404 s->z_err = Z_ERRNO;
405 break;
406 }
407 s->stream.avail_out = Z_BUFSIZE;
408 }
409 s->in += s->stream.avail_in;
410 s->out += s->stream.avail_out;
411 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
412 s->in -= s->stream.avail_in;
413 s->out -= s->stream.avail_out;
414 if (s->z_err != Z_OK) break;
415 }
416 s->crc = crc32(s->crc, (const Bytef *) buf, len);
417
418 return (int) (len - s->stream.avail_in);
419 }
420
421
gz_flush(gzFile file,int flush)422 static int gz_flush (gzFile file, int flush)
423 {
424 uInt len;
425 int done = 0;
426 gz_stream *s = (gz_stream*) file;
427
428 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
429
430 s->stream.avail_in = 0; /* should be zero already anyway */
431
432 for (;;) {
433 len = Z_BUFSIZE - s->stream.avail_out;
434 if (len != 0) {
435 if ((uInt)fwrite(s->buffer, 1, len, s->file) != len) {
436 s->z_err = Z_ERRNO;
437 return Z_ERRNO;
438 }
439 s->stream.next_out = s->buffer;
440 s->stream.avail_out = Z_BUFSIZE;
441 }
442 if (done) break;
443 s->out += s->stream.avail_out;
444 s->z_err = deflate(&(s->stream), flush);
445 s->out -= s->stream.avail_out;
446
447 /* Ignore the second of two consecutive flushes: */
448 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
449
450 /* deflate has finished flushing only when it hasn't used up
451 * all the available space in the output buffer:
452 */
453 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
454
455 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
456 }
457 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
458 }
459
460 /* return value 0 for success, 1 for failure */
int_gzrewind(gzFile file)461 static int int_gzrewind (gzFile file)
462 {
463 gz_stream *s = (gz_stream*) file;
464
465 if (s == NULL || s->mode != 'r') return -1;
466
467 s->z_err = Z_OK;
468 s->z_eof = 0;
469 s->stream.avail_in = 0;
470 s->stream.next_in = s->buffer;
471 s->crc = crc32(0L, Z_NULL, 0);
472 if (!s->transparent) (void) inflateReset(&s->stream);
473 s->in = 0;
474 s->out = 0;
475 return f_seek(s->file, s->start, SEEK_SET);
476 }
477
R_gztell(gzFile file)478 static Rz_off_t R_gztell (gzFile file)
479 {
480 gz_stream *s = (gz_stream*) file;
481 if (s->mode == 'w') return s->in; else return s->out;
482 }
483
484 /* NB: return value is in line with fseeko, not gzseek */
R_gzseek(gzFile file,Rz_off_t offset,int whence)485 static int R_gzseek (gzFile file, Rz_off_t offset, int whence)
486 {
487 gz_stream *s = (gz_stream*) file;
488
489 if (s == NULL || whence == SEEK_END ||
490 s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) return -1;
491
492 if (s->mode == 'w') {
493 if (whence == SEEK_SET) offset -= s->in;
494 if (offset < 0) return -1;
495
496 /* At this point, offset is the number of zero bytes to write. */
497 memset(s->buffer, 0, Z_BUFSIZE);
498 while (offset > 0) {
499 uInt size = Z_BUFSIZE;
500 if (offset < Z_BUFSIZE) size = (uInt) offset;
501 size = R_gzwrite(file, s->buffer, size);
502 if (size == 0) return -1;
503 offset -= size;
504 }
505 return 0;
506 }
507
508 /* Rest of function is for reading only */
509
510 /* compute absolute position */
511 if (whence == SEEK_CUR) offset += s->out;
512 if (offset < 0) return -1;
513
514 if (s->transparent) {
515 s->stream.avail_in = 0;
516 s->stream.next_in = s->buffer;
517 if (f_seek(s->file, offset, SEEK_SET) < 0) return -1;
518 s->in = s->out = offset;
519 return 0;
520 }
521
522 /* For a negative seek, rewind and use positive seek */
523 if (offset >= s->out) offset -= s->out;
524 else if (int_gzrewind(file) < 0) return -1;
525
526 /* offset is now the number of bytes to skip. */
527 while (offset > 0) {
528 int size = Z_BUFSIZE;
529 if (offset < Z_BUFSIZE) size = (int) offset;
530 size = R_gzread(file, s->buffer, (uInt) size);
531 if (size <= 0) return -1;
532 offset -= size;
533 }
534 return 0;
535 }
536
R_gzclose(gzFile file)537 int R_gzclose (gzFile file)
538 {
539 gz_stream *s = (gz_stream*) file;
540 if (s == NULL) return Z_STREAM_ERROR;
541 if (s->mode == 'w') {
542 if (gz_flush (file, Z_FINISH) != Z_OK)
543 return destroy((gz_stream*) file);
544 z_putLong (s->file, s->crc);
545 z_putLong (s->file, (uLong) (s->in & 0xffffffff));
546 }
547 return destroy((gz_stream*) file);
548 }
549
550 /*
551 static voidpf
552 R_zlib_alloc(voidpf ptr, uInt items, uInt size)
553 {
554 return R_alloc(items, size);
555 }
556
557 static void
558 R_zlib_free(voidpf ptr, voidpf addr) {}
559 */
560
561 /* added in 4.0.0, modified from uncompress[2] */
562 static int
R_uncompress(Bytef * dest,uLong * destLen,Bytef * source,uLong sourceLen,int opt)563 R_uncompress(Bytef *dest, uLong *destLen, Bytef *source, uLong sourceLen,
564 int opt)
565 {
566 z_stream stream;
567
568 stream.next_in = source;
569 stream.avail_in = 0;
570 stream.zalloc = (alloc_func)0;
571 stream.zfree = (free_func)0;
572 stream.opaque = (voidpf)0;
573
574 /*
575 opt is the main difference from uncompress
576 0 means no headers (zlib)
577 16 selects gzip
578 32 allows auto-selection.
579 */
580 int err = inflateInit2( &stream, MAX_WBITS + opt );
581 if(err != Z_OK) return err;
582
583 const uInt max = (uInt)-1; // could have used UINT_MAX
584 uLong len = sourceLen, left = *destLen;
585 stream.next_out = dest;
586 stream.avail_out = 0;
587
588 do { // do >= 2^32 bits in chunks
589 if (stream.avail_out == 0) {
590 stream.avail_out = left > (uLong)max ? max : (uInt)left;
591 left -= stream.avail_out;
592 }
593 if (stream.avail_in == 0) {
594 stream.avail_in = len > (uLong)max ? max : (uInt)len;
595 len -= stream.avail_in;
596 }
597 err = inflate(&stream, Z_NO_FLUSH);
598 } while (err == Z_OK);
599
600 *destLen = stream.total_out;
601 inflateEnd(&stream);
602 return err;
603 }
604