Add command-line option help-text localization
[cygwin-setup.git] / compress_gz.cc
blobe73ccd3315516d203e3abf7932ef7118ac26e5c6
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>
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 */
35 /* TODO make this a static member and federate the magic logic */
36 static int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
39 * Predicate: the stream is open for read. For writing the class constructor variant with
40 * mode must be called directly
42 compress_gz::compress_gz (io_stream * parent)
44 original = parent;
45 owns_original = true;
46 openmode = "r";
47 construct ();
50 compress_gz::compress_gz (io_stream * parent, const char *_openmode)
52 original = parent;
53 owns_original = true;
54 openmode = _openmode;
55 construct ();
58 void
59 compress_gz::construct ()
61 peeklen = 0;
62 int err;
63 int level = Z_DEFAULT_COMPRESSION; /* compression level */
64 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
65 char *p = (char *) openmode;
66 char fmode[80]; /* copy of openmode, without the compression level */
67 char *m = fmode;
69 stream.zalloc = (alloc_func) NULL;
70 stream.zfree = (free_func) NULL;
71 stream.opaque = (voidpf) NULL;
72 stream.next_in = inbuf = NULL;
73 stream.next_out = outbuf = NULL;
74 stream.avail_in = stream.avail_out = 0;
75 z_err = Z_OK;
76 z_eof = 0;
77 crc = crc32 (0L, Z_NULL, 0);
78 msg = NULL;
79 transparent = 0;
81 mode = '\0';
83 if (!original)
85 z_err = Z_STREAM_ERROR;
86 return;
91 if (*p == 'r')
92 mode = 'r';
93 if (*p == 'w' || *p == 'a')
94 mode = 'w';
95 if (*p >= '0' && *p <= '9')
97 level = *p - '0';
99 else if (*p == 'f')
101 strategy = Z_FILTERED;
103 else if (*p == 'h')
105 strategy = Z_HUFFMAN_ONLY;
107 else
109 *m++ = *p; /* copy the mode */
112 while (*p++ && m != fmode + sizeof (fmode));
113 if (mode == '\0')
115 destroy ();
116 z_err = Z_STREAM_ERROR;
117 return;
121 if (mode == 'w')
123 err = deflateInit2 (&(stream), level,
124 Z_DEFLATED, -MAX_WBITS, 8, strategy);
125 /* windowBits is passed < 0 to suppress zlib header */
127 stream.next_out = outbuf = (Byte *) malloc (16384);
128 if (err != Z_OK || outbuf == Z_NULL)
130 destroy ();
131 z_err = Z_STREAM_ERROR;
132 return;
135 else
138 stream.next_in = inbuf = (unsigned char *) malloc (16384);
139 err = inflateInit2 (&stream, -MAX_WBITS);
140 /* windowBits is passed < 0 to tell that there is no zlib header.
141 * Note that in this case inflate *requires* an extra "dummy" byte
142 * after the compressed stream in order to complete decompression and
143 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
144 * present after the compressed stream.
146 if (err != Z_OK || inbuf == Z_NULL)
148 destroy ();
149 z_err = Z_STREAM_ERROR;
150 return;
153 stream.avail_out = 16384;
155 errno = 0;
156 if (mode == 'w')
158 /* Write a very simple .gz header:
160 char temp[20];
161 sprintf (temp, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
162 Z_DEFLATED, 0 /*flags */ , 0, 0, 0, 0 /*time */ ,
163 0 /*xflags */ , 0x0b);
164 original->write (temp, 10);
165 startpos = 10L;
166 /* We use 10L instead of ftell(s->file) to because ftell causes an
167 * fflush on some systems. This version of the library doesn't use
168 * startpos anyway in write mode, so this initialization is not
169 * necessary.
172 else
175 check_header (); /* skip the .gz header */
176 startpos = (original->tell () - stream.avail_in);
179 return;
182 /* ===========================================================================
183 Outputs a long in LSB order to the given file
185 void
186 compress_gz::putLong (unsigned long x)
188 int n;
189 for (n = 0; n < 4; n++)
191 unsigned char c = (unsigned char) (x & 0xff);
192 original->write (&c, 1);
193 x = x >> 8;
198 uLong
199 compress_gz::getLong ()
201 uLong x = (uLong) get_byte ();
202 int c;
204 x += ((uLong) get_byte ()) << 8;
205 x += ((uLong) get_byte ()) << 16;
206 c = get_byte ();
207 if (c == EOF)
208 z_err = Z_DATA_ERROR;
209 x += ((uLong) c) << 24;
210 return x;
214 ssize_t
215 compress_gz::read (void *buffer, size_t len)
217 if (!len)
218 return 0;
220 if (peeklen)
222 ssize_t tmplen = std::min (peeklen, len);
223 peeklen -= tmplen;
224 memcpy (buffer, peekbuf, tmplen);
225 memmove (peekbuf, peekbuf + tmplen, tmplen);
226 ssize_t tmpread = read (&((char *) buffer)[tmplen], len - tmplen);
227 if (tmpread >= 0)
228 return tmpread + tmplen;
229 else
230 return tmpread;
233 Bytef *start = (Bytef *) buffer; /* starting point for crc computation */
234 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
236 if (mode != 'r')
238 z_err = Z_STREAM_ERROR;
239 return -1;
242 if (z_err == Z_DATA_ERROR || z_err == Z_ERRNO)
243 return -1;
244 if (z_err == Z_STREAM_END)
245 return 0; /* EOF */
247 next_out = (Byte *) buffer;
248 stream.next_out = (Bytef *) buffer;
249 stream.avail_out = len;
251 while (stream.avail_out != 0)
254 if (transparent)
256 /* Copy first the lookahead bytes: */
257 uInt n = stream.avail_in;
258 if (n > stream.avail_out)
259 n = stream.avail_out;
260 if (n > 0)
262 memcpy (stream.next_out, stream.next_in, n);
263 next_out += n;
264 stream.next_out = next_out;
265 stream.next_in += n;
266 stream.avail_out -= n;
267 stream.avail_in -= n;
269 if (stream.avail_out > 0)
271 stream.avail_out -= original->read (next_out, stream.avail_out);
273 len -= stream.avail_out;
274 stream.total_in += (uLong) len;
275 stream.total_out += (uLong) len;
276 if (len == 0)
277 z_eof = 1;
278 return (int) len;
280 if (stream.avail_in == 0 && !z_eof)
283 errno = 0;
284 stream.avail_in = original->read (inbuf, 16384);
285 if (stream.avail_in == 0)
287 z_eof = 1;
288 if (original->error ())
290 z_err = Z_ERRNO;
291 break;
294 stream.next_in = inbuf;
296 z_err = inflate (&(stream), Z_NO_FLUSH);
298 if (z_err == Z_STREAM_END)
300 /* Check CRC and original size */
301 crc = crc32 (crc, start, (uInt) (stream.next_out - start));
302 start = stream.next_out;
304 if (getLong () != crc)
306 z_err = Z_DATA_ERROR;
308 else
310 (void) getLong ();
311 /* The uncompressed length returned by above getlong() may
312 * be different from stream.total_out) in case of
313 * concatenated .gz files. Check for such files:
315 check_header ();
316 if (z_err == Z_OK)
318 uLong total_in = stream.total_in;
319 uLong total_out = stream.total_out;
321 inflateReset (&(stream));
322 stream.total_in = total_in;
323 stream.total_out = total_out;
324 crc = crc32 (0L, Z_NULL, 0);
328 if (z_err != Z_OK || z_eof)
329 break;
331 crc = crc32 (crc, start, (uInt) (stream.next_out - start));
333 return (int) (len - stream.avail_out);
337 /* ===========================================================================
338 Writes the given number of uncompressed bytes into the compressed file.
339 gzwrite returns the number of bytes actually written (0 in case of error).
341 ssize_t
342 compress_gz::write (const void *buffer, size_t len)
344 if (mode != 'w')
346 z_err = Z_STREAM_ERROR;
347 return -1;
350 stream.next_in = (Bytef *) buffer;
351 stream.avail_in = len;
353 while (stream.avail_in != 0)
356 if (stream.avail_out == 0)
359 stream.next_out = outbuf;
360 if (original->write (outbuf, 16384) != 16384)
362 z_err = Z_ERRNO;
363 break;
365 stream.avail_out = 16384;
367 z_err = deflate (&(stream), Z_NO_FLUSH);
368 if (z_err != Z_OK)
369 break;
371 crc = crc32 (crc, (const Bytef *) buffer, len);
373 return (int) (len - stream.avail_in);
376 ssize_t
377 compress_gz::peek (void *buffer, size_t len)
379 if (mode != 'r')
381 z_err = Z_STREAM_ERROR;
382 return -1;
384 /* can only peek 512 bytes */
385 if (len > 512)
387 z_err = ENOMEM;
388 return -1;
391 if (len > peeklen)
393 size_t want = len - peeklen;
394 ssize_t got = read (&peekbuf[peeklen], want);
395 if (got >= 0)
396 peeklen += got;
397 else
398 /* error */
399 return got;
400 /* we may have read less than requested. */
401 memcpy (buffer, peekbuf, peeklen);
402 return peeklen;
404 else
406 memcpy (buffer, peekbuf, len);
407 return len;
411 long
412 compress_gz::tell ()
414 throw new std::logic_error("compress_gz::tell is not implemented");
418 compress_gz::seek (long where, io_stream_seek_t whence)
420 if ((whence == IO_SEEK_SET) && (where == 0))
422 int result = original->seek(where, whence);
423 destroy();
424 construct();
425 return result;
428 throw new std::logic_error("compress_gz::seek is not implemented");
432 compress_gz::error ()
434 if (z_err && z_err != Z_STREAM_END)
435 return z_err;
436 return 0;
440 compress_gz::set_mtime (time_t time)
442 if (original)
443 return original->set_mtime (time);
444 return 1;
447 time_t
448 compress_gz::get_mtime ()
450 if (original)
451 return original->get_mtime ();
452 return 0;
455 mode_t
456 compress_gz::get_mode ()
458 if (original)
459 return original->get_mode ();
460 return 0;
463 void
464 compress_gz::release_original ()
466 owns_original = false;
469 void
470 compress_gz::destroy ()
472 if (msg)
474 free (msg);
475 msg = NULL;
478 if (stream.state != NULL)
480 if (mode == 'w')
482 z_err = deflateEnd (&(stream));
484 else if (mode == 'r')
486 z_err = inflateEnd (&(stream));
490 if (inbuf)
492 free (inbuf);
493 inbuf = NULL;
495 if (outbuf)
497 free (outbuf);
498 outbuf = NULL;
502 compress_gz::~compress_gz ()
504 if (mode == 'w')
506 z_err = do_flush (Z_FINISH);
507 if (z_err == Z_OK)
509 putLong (crc);
510 putLong (stream.total_in);
513 destroy ();
514 if (original && owns_original)
515 delete original;
519 compress_gz::do_flush (int flush)
521 uInt len;
522 int done = 0;
523 if (mode != 'w')
524 return Z_STREAM_ERROR;
525 stream.avail_in = 0; /* should be zero already anyway */
526 for (;;)
528 len = 16384 - stream.avail_out;
529 if (len != 0)
531 if ((uInt) original->write (outbuf, len) != len)
533 z_err = Z_ERRNO;
534 return Z_ERRNO;
536 stream.next_out = outbuf;
537 stream.avail_out = 16384;
539 if (done)
540 break;
541 z_err = deflate (&(stream), flush);
542 /* Ignore the second of two consecutive flushes: */
543 if (len == 0 && z_err == Z_BUF_ERROR)
544 z_err = Z_OK;
545 /* deflate has finished flushing only when it hasn't used up
546 * all the available space in the output buffer:
548 done = (stream.avail_out != 0 || z_err == Z_STREAM_END);
549 if (z_err != Z_OK && z_err != Z_STREAM_END)
550 break;
552 return z_err == Z_STREAM_END ? Z_OK : z_err;
555 /* ===========================================================================
556 * Read a byte from a gz_stream; update next_in and avail_in. Return EOF
557 * for end of file.
558 * IN assertion: the stream s has been sucessfully opened for reading.
561 compress_gz::get_byte ()
563 if (z_eof)
564 return EOF;
565 if (stream.avail_in == 0)
567 errno = 0;
568 stream.avail_in = original->read (inbuf, 16384);
569 if (stream.avail_in == 0)
571 z_eof = 1;
572 if (original->error ())
573 z_err = Z_ERRNO;
574 return EOF;
576 stream.next_in = inbuf;
578 stream.avail_in--;
579 return *(stream.next_in)++;
583 /* ===========================================================================
584 Check the gzip header of a gz_stream opened for reading. Set the stream
585 mode to transparent if the gzip magic header is not present; set s->err
586 to Z_DATA_ERROR if the magic header is present but the rest of the header
587 is incorrect.
588 IN assertion: the stream s has already been created sucessfully;
589 s->stream.avail_in is zero for the first time, but may be non-zero
590 for concatenated .gz files.
592 void
593 compress_gz::check_header ()
595 int method; /* method byte */
596 int flags; /* flags byte */
597 uInt len;
598 int c;
599 /* Check the gzip magic header */
600 for (len = 0; len < 2; len++)
602 c = get_byte ();
603 if (c != gz_magic[len])
605 if (len != 0)
606 stream.avail_in++, stream.next_in--;
607 if (c != EOF)
609 stream.avail_in++, stream.next_in--;
610 transparent = 1;
612 z_err = stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
613 return;
616 method = get_byte ();
617 flags = get_byte ();
618 if (method != Z_DEFLATED || (flags & RESERVED) != 0)
620 z_err = Z_DATA_ERROR;
621 return;
624 /* Discard time, xflags and OS code: */
625 for (len = 0; len < 6; len++)
626 (void) get_byte ();
627 if ((flags & EXTRA_FIELD) != 0)
628 { /* skip the extra field */
629 len = (uInt) get_byte ();
630 len += ((uInt) get_byte ()) << 8;
631 /* len is garbage if EOF but the loop below will quit anyway */
632 while (len-- != 0 && get_byte () != EOF);
634 if ((flags & ORIG_NAME) != 0)
635 { /* skip the original file name */
636 while ((c = get_byte ()) != 0 && c != EOF);
638 if ((flags & COMMENT) != 0)
639 { /* skip the .gz file comment */
640 while ((c = get_byte ()) != 0 && c != EOF);
642 if ((flags & HEAD_CRC) != 0)
643 { /* skip the header crc */
644 for (len = 0; len < 2; len++)
645 (void) get_byte ();
647 z_err = z_eof ? Z_DATA_ERROR : Z_OK;