README: document some recent changes in the build environment
[cygwin-setup.git] / compress_gz.cc
blob7686adf879ee1f5afbd32232111bbb1ef03b007e
1 /*
2 * Copyright (c) 2001, Robert Collins.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
12 * Written by Robert Collins <rbtcollins@hotmail.com>
16 /*
17 * Portions copyright under the zlib licence - this class was derived from
18 * gzio.c in that library.
21 #include "compress_gz.h"
23 #include <stdexcept>
24 using namespace std;
25 #include <errno.h>
26 #include <memory.h>
27 #include <malloc.h>
29 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
30 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
31 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
32 #define COMMENT 0x10 /* bit 4 set: file comment present */
33 #define RESERVED 0xE0 /* bits 5..7: reserved */
36 /* TODO make this a static member and federate the magic logic */
37 static int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
40 * Predicate: the stream is open for read. For writing the class constructor variant with
41 * mode must be called directly
43 compress_gz::compress_gz (io_stream * parent)
45 construct (parent, "r");
48 compress_gz::compress_gz (io_stream * parent, const char *openmode)
50 construct (parent, openmode);
53 void
54 compress_gz::construct (io_stream * parent, const char *openmode)
56 original = parent;
57 owns_original = true;
58 peeklen = 0;
59 int err;
60 int level = Z_DEFAULT_COMPRESSION; /* compression level */
61 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
62 char *p = (char *) openmode;
63 char fmode[80]; /* copy of openmode, without the compression level */
64 char *m = fmode;
66 stream.zalloc = (alloc_func) NULL;
67 stream.zfree = (free_func) NULL;
68 stream.opaque = (voidpf) NULL;
69 stream.next_in = inbuf = NULL;
70 stream.next_out = outbuf = NULL;
71 stream.avail_in = stream.avail_out = 0;
72 z_err = Z_OK;
73 z_eof = 0;
74 crc = crc32 (0L, Z_NULL, 0);
75 msg = NULL;
76 transparent = 0;
78 mode = '\0';
80 if (!parent)
82 z_err = Z_STREAM_ERROR;
83 return;
88 if (*p == 'r')
89 mode = 'r';
90 if (*p == 'w' || *p == 'a')
91 mode = 'w';
92 if (*p >= '0' && *p <= '9')
94 level = *p - '0';
96 else if (*p == 'f')
98 strategy = Z_FILTERED;
100 else if (*p == 'h')
102 strategy = Z_HUFFMAN_ONLY;
104 else
106 *m++ = *p; /* copy the mode */
109 while (*p++ && m != fmode + sizeof (fmode));
110 if (mode == '\0')
112 destroy ();
113 z_err = Z_STREAM_ERROR;
114 return;
118 if (mode == 'w')
120 err = deflateInit2 (&(stream), level,
121 Z_DEFLATED, -MAX_WBITS, 8, strategy);
122 /* windowBits is passed < 0 to suppress zlib header */
124 stream.next_out = outbuf = (Byte *) malloc (16384);
125 if (err != Z_OK || outbuf == Z_NULL)
127 destroy ();
128 z_err = Z_STREAM_ERROR;
129 return;
132 else
135 stream.next_in = inbuf = (unsigned char *) malloc (16384);
136 err = inflateInit2 (&stream, -MAX_WBITS);
137 /* windowBits is passed < 0 to tell that there is no zlib header.
138 * Note that in this case inflate *requires* an extra "dummy" byte
139 * after the compressed stream in order to complete decompression and
140 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
141 * present after the compressed stream.
143 if (err != Z_OK || inbuf == Z_NULL)
145 destroy ();
146 z_err = Z_STREAM_ERROR;
147 return;
150 stream.avail_out = 16384;
152 errno = 0;
153 if (mode == 'w')
155 /* Write a very simple .gz header:
157 char temp[20];
158 sprintf (temp, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
159 Z_DEFLATED, 0 /*flags */ , 0, 0, 0, 0 /*time */ ,
160 0 /*xflags */ , 0x0b);
161 original->write (temp, 10);
162 startpos = 10L;
163 /* We use 10L instead of ftell(s->file) to because ftell causes an
164 * fflush on some systems. This version of the library doesn't use
165 * startpos anyway in write mode, so this initialization is not
166 * necessary.
169 else
172 check_header (); /* skip the .gz header */
173 startpos = (original->tell () - stream.avail_in);
176 return;
179 /* ===========================================================================
180 Outputs a long in LSB order to the given file
182 void
183 compress_gz::putLong (unsigned long x)
185 int n;
186 for (n = 0; n < 4; n++)
188 unsigned char c = (unsigned char) (x & 0xff);
189 original->write (&c, 1);
190 x = x >> 8;
195 uLong
196 compress_gz::getLong ()
198 uLong x = (uLong) get_byte ();
199 int c;
201 x += ((uLong) get_byte ()) << 8;
202 x += ((uLong) get_byte ()) << 16;
203 c = get_byte ();
204 if (c == EOF)
205 z_err = Z_DATA_ERROR;
206 x += ((uLong) c) << 24;
207 return x;
211 ssize_t
212 compress_gz::read (void *buffer, size_t len)
214 if (!len)
215 return 0;
217 if (peeklen)
219 ssize_t tmplen = std::min (peeklen, len);
220 peeklen -= tmplen;
221 memcpy (buffer, peekbuf, tmplen);
222 memmove (peekbuf, peekbuf + tmplen, tmplen);
223 ssize_t tmpread = read (&((char *) buffer)[tmplen], len - tmplen);
224 if (tmpread >= 0)
225 return tmpread + tmplen;
226 else
227 return tmpread;
230 Bytef *start = (Bytef *) buffer; /* starting point for crc computation */
231 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
233 if (mode != 'r')
235 z_err = Z_STREAM_ERROR;
236 return -1;
239 if (z_err == Z_DATA_ERROR || z_err == Z_ERRNO)
240 return -1;
241 if (z_err == Z_STREAM_END)
242 return 0; /* EOF */
244 next_out = (Byte *) buffer;
245 stream.next_out = (Bytef *) buffer;
246 stream.avail_out = len;
248 while (stream.avail_out != 0)
251 if (transparent)
253 /* Copy first the lookahead bytes: */
254 uInt n = stream.avail_in;
255 if (n > stream.avail_out)
256 n = stream.avail_out;
257 if (n > 0)
259 memcpy (stream.next_out, stream.next_in, n);
260 next_out += n;
261 stream.next_out = next_out;
262 stream.next_in += n;
263 stream.avail_out -= n;
264 stream.avail_in -= n;
266 if (stream.avail_out > 0)
268 stream.avail_out -= original->read (next_out, stream.avail_out);
270 len -= stream.avail_out;
271 stream.total_in += (uLong) len;
272 stream.total_out += (uLong) len;
273 if (len == 0)
274 z_eof = 1;
275 return (int) len;
277 if (stream.avail_in == 0 && !z_eof)
280 errno = 0;
281 stream.avail_in = original->read (inbuf, 16384);
282 if (stream.avail_in == 0)
284 z_eof = 1;
285 if (original->error ())
287 z_err = Z_ERRNO;
288 break;
291 stream.next_in = inbuf;
293 z_err = inflate (&(stream), Z_NO_FLUSH);
295 if (z_err == Z_STREAM_END)
297 /* Check CRC and original size */
298 crc = crc32 (crc, start, (uInt) (stream.next_out - start));
299 start = stream.next_out;
301 if (getLong () != crc)
303 z_err = Z_DATA_ERROR;
305 else
307 (void) getLong ();
308 /* The uncompressed length returned by above getlong() may
309 * be different from stream.total_out) in case of
310 * concatenated .gz files. Check for such files:
312 check_header ();
313 if (z_err == Z_OK)
315 uLong total_in = stream.total_in;
316 uLong total_out = stream.total_out;
318 inflateReset (&(stream));
319 stream.total_in = total_in;
320 stream.total_out = total_out;
321 crc = crc32 (0L, Z_NULL, 0);
325 if (z_err != Z_OK || z_eof)
326 break;
328 crc = crc32 (crc, start, (uInt) (stream.next_out - start));
330 return (int) (len - stream.avail_out);
334 /* ===========================================================================
335 Writes the given number of uncompressed bytes into the compressed file.
336 gzwrite returns the number of bytes actually written (0 in case of error).
338 ssize_t
339 compress_gz::write (const void *buffer, size_t len)
341 if (mode != 'w')
343 z_err = Z_STREAM_ERROR;
344 return -1;
347 stream.next_in = (Bytef *) buffer;
348 stream.avail_in = len;
350 while (stream.avail_in != 0)
353 if (stream.avail_out == 0)
356 stream.next_out = outbuf;
357 if (original->write (outbuf, 16384) != 16384)
359 z_err = Z_ERRNO;
360 break;
362 stream.avail_out = 16384;
364 z_err = deflate (&(stream), Z_NO_FLUSH);
365 if (z_err != Z_OK)
366 break;
368 crc = crc32 (crc, (const Bytef *) buffer, len);
370 return (int) (len - stream.avail_in);
373 ssize_t
374 compress_gz::peek (void *buffer, size_t len)
376 if (mode != 'r')
378 z_err = Z_STREAM_ERROR;
379 return -1;
381 /* can only peek 512 bytes */
382 if (len > 512)
384 z_err = ENOMEM;
385 return -1;
388 if (len > peeklen)
390 size_t want = len - peeklen;
391 ssize_t got = read (&peekbuf[peeklen], want);
392 if (got >= 0)
393 peeklen += got;
394 else
395 /* error */
396 return got;
397 /* we may have read less than requested. */
398 memcpy (buffer, peekbuf, peeklen);
399 return peeklen;
401 else
403 memcpy (buffer, peekbuf, len);
404 return len;
408 long
409 compress_gz::tell ()
411 throw new logic_error("compress_gz::tell is not implemented");
415 compress_gz::seek (long where, io_stream_seek_t whence)
417 throw new logic_error("compress_gz::seek is not implemented");
421 compress_gz::error ()
423 if (z_err && z_err != Z_STREAM_END)
424 return z_err;
425 return 0;
429 compress_gz::set_mtime (time_t time)
431 if (original)
432 return original->set_mtime (time);
433 return 1;
436 time_t
437 compress_gz::get_mtime ()
439 if (original)
440 return original->get_mtime ();
441 return 0;
444 mode_t
445 compress_gz::get_mode ()
447 if (original)
448 return original->get_mode ();
449 return 0;
452 void
453 compress_gz::release_original ()
455 owns_original = false;
458 void
459 compress_gz::destroy ()
461 if (msg)
462 free (msg);
463 if (stream.state != NULL)
465 if (mode == 'w')
467 z_err = deflateEnd (&(stream));
469 else if (mode == 'r')
471 z_err = inflateEnd (&(stream));
475 if (inbuf)
477 free (inbuf);
478 if (outbuf)
479 free (outbuf);
480 if (original && owns_original)
481 delete original;
484 compress_gz::~compress_gz ()
486 if (mode == 'w')
488 z_err = do_flush (Z_FINISH);
489 if (z_err != Z_OK)
491 destroy ();
492 return;
495 putLong (crc);
496 putLong (stream.total_in);
498 destroy ();
502 compress_gz::do_flush (int flush)
504 uInt len;
505 int done = 0;
506 if (mode != 'w')
507 return Z_STREAM_ERROR;
508 stream.avail_in = 0; /* should be zero already anyway */
509 for (;;)
511 len = 16384 - stream.avail_out;
512 if (len != 0)
514 if ((uInt) original->write (outbuf, len) != len)
516 z_err = Z_ERRNO;
517 return Z_ERRNO;
519 stream.next_out = outbuf;
520 stream.avail_out = 16384;
522 if (done)
523 break;
524 z_err = deflate (&(stream), flush);
525 /* Ignore the second of two consecutive flushes: */
526 if (len == 0 && z_err == Z_BUF_ERROR)
527 z_err = Z_OK;
528 /* deflate has finished flushing only when it hasn't used up
529 * all the available space in the output buffer:
531 done = (stream.avail_out != 0 || z_err == Z_STREAM_END);
532 if (z_err != Z_OK && z_err != Z_STREAM_END)
533 break;
535 return z_err == Z_STREAM_END ? Z_OK : z_err;
539 #if 0
541 gzclose (lst);
542 #endif
543 /* ===========================================================================
544 * Read a byte from a gz_stream; update next_in and avail_in. Return EOF
545 * for end of file.
546 * IN assertion: the stream s has been sucessfully opened for reading.
549 compress_gz::get_byte ()
551 if (z_eof)
552 return EOF;
553 if (stream.avail_in == 0)
555 errno = 0;
556 stream.avail_in = original->read (inbuf, 16384);
557 if (stream.avail_in == 0)
559 z_eof = 1;
560 if (original->error ())
561 z_err = Z_ERRNO;
562 return EOF;
564 stream.next_in = inbuf;
566 stream.avail_in--;
567 return *(stream.next_in)++;
571 /* ===========================================================================
572 Check the gzip header of a gz_stream opened for reading. Set the stream
573 mode to transparent if the gzip magic header is not present; set s->err
574 to Z_DATA_ERROR if the magic header is present but the rest of the header
575 is incorrect.
576 IN assertion: the stream s has already been created sucessfully;
577 s->stream.avail_in is zero for the first time, but may be non-zero
578 for concatenated .gz files.
580 void
581 compress_gz::check_header ()
583 int method; /* method byte */
584 int flags; /* flags byte */
585 uInt len;
586 int c;
587 /* Check the gzip magic header */
588 for (len = 0; len < 2; len++)
590 c = get_byte ();
591 if (c != gz_magic[len])
593 if (len != 0)
594 stream.avail_in++, stream.next_in--;
595 if (c != EOF)
597 stream.avail_in++, stream.next_in--;
598 transparent = 1;
600 z_err = stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
601 return;
604 method = get_byte ();
605 flags = get_byte ();
606 if (method != Z_DEFLATED || (flags & RESERVED) != 0)
608 z_err = Z_DATA_ERROR;
609 return;
612 /* Discard time, xflags and OS code: */
613 for (len = 0; len < 6; len++)
614 (void) get_byte ();
615 if ((flags & EXTRA_FIELD) != 0)
616 { /* skip the extra field */
617 len = (uInt) get_byte ();
618 len += ((uInt) get_byte ()) << 8;
619 /* len is garbage if EOF but the loop below will quit anyway */
620 while (len-- != 0 && get_byte () != EOF);
622 if ((flags & ORIG_NAME) != 0)
623 { /* skip the original file name */
624 while ((c = get_byte ()) != 0 && c != EOF);
626 if ((flags & COMMENT) != 0)
627 { /* skip the .gz file comment */
628 while ((c = get_byte ()) != 0 && c != EOF);
630 if ((flags & HEAD_CRC) != 0)
631 { /* skip the header crc */
632 for (len = 0; len < 2; len++)
633 (void) get_byte ();
635 z_err = z_eof ? Z_DATA_ERROR : Z_OK;