]> cygwin.com Git - cygwin-apps/setup.git/blob - compress_gz.cc
2001-11-13 Robert Collins <rbtcollins@hotmail.com>
[cygwin-apps/setup.git] / compress_gz.cc
1 /*
2 * Copyright (c) 2001, Robert Collins.
3 *
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.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Robert Collins <rbtcollins@hotmail.com>
13 *
14 */
15
16 /* Archive IO operations for gz files
17 * Portions copyright under the zlib licence - this class was derived from gzio.c in that
18 * library.
19 */
20
21 #if 0
22 static const char *cvsid =
23 "\n%%% $Id$\n";
24 #endif
25
26 #include "win32.h"
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include "log.h"
31 #include "port.h"
32
33 #include "io_stream.h"
34 #include "compress.h"
35 #include "zlib/zlib.h"
36 #include "compress_gz.h"
37
38 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
39 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
40 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
41 #define COMMENT 0x10 /* bit 4 set: file comment present */
42 #define RESERVED 0xE0 /* bits 5..7: reserved */
43
44
45 /* TODO make this a static member and federate the magic logic */
46 static int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
47
48 /*
49 * Predicate: the stream is open for read. For writing the class constructor variant with
50 * mode must be called directly
51 */
52 compress_gz::compress_gz (io_stream * parent)
53 {
54 construct (parent, "r");
55 }
56
57 compress_gz::compress_gz (io_stream * parent, const char *openmode)
58 {
59 construct (parent, openmode);
60 }
61
62 void
63 compress_gz::construct (io_stream * parent, const char *openmode)
64 {
65 if (!parent)
66 {
67 z_err = Z_STREAM_ERROR;
68 return;
69 }
70
71 original = parent;
72 peeklen = 0;
73 int err;
74 int level = Z_DEFAULT_COMPRESSION; /* compression level */
75 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
76 char *p = (char *) openmode;
77 char fmode[80]; /* copy of openmode, without the compression level */
78 char *m = fmode;
79
80 stream.zalloc = (alloc_func) NULL;
81 stream.zfree = (free_func) NULL;
82 stream.opaque = (voidpf) NULL;
83 stream.next_in = inbuf = NULL;
84 stream.next_out = outbuf = NULL;
85 stream.avail_in = stream.avail_out = 0;
86 z_err = Z_OK;
87 z_eof = 0;
88 crc = crc32 (0L, Z_NULL, 0);
89 msg = NULL;
90 transparent = 0;
91
92 mode = '\0';
93 do
94 {
95 if (*p == 'r')
96 mode = 'r';
97 if (*p == 'w' || *p == 'a')
98 mode = 'w';
99 if (*p >= '0' && *p <= '9')
100 {
101 level = *p - '0';
102 }
103 else if (*p == 'f')
104 {
105 strategy = Z_FILTERED;
106 }
107 else if (*p == 'h')
108 {
109 strategy = Z_HUFFMAN_ONLY;
110 }
111 else
112 {
113 *m++ = *p; /* copy the mode */
114 }
115 }
116 while (*p++ && m != fmode + sizeof (fmode));
117 if (mode == '\0')
118 {
119 destroy ();
120 z_err = Z_STREAM_ERROR;
121 return;
122 }
123
124
125 if (mode == 'w')
126 {
127 err = deflateInit2 (&(stream), level,
128 Z_DEFLATED, -MAX_WBITS, 8, strategy);
129 /* windowBits is passed < 0 to suppress zlib header */
130
131 stream.next_out = outbuf = (Byte *) malloc (16384);
132 if (err != Z_OK || outbuf == Z_NULL)
133 {
134 destroy ();
135 z_err = Z_STREAM_ERROR;
136 return;
137 }
138 }
139 else
140 {
141
142 stream.next_in = inbuf = (unsigned char *) malloc (16384);
143 err = inflateInit2 (&stream, -MAX_WBITS);
144 /* windowBits is passed < 0 to tell that there is no zlib header.
145 * Note that in this case inflate *requires* an extra "dummy" byte
146 * after the compressed stream in order to complete decompression and
147 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
148 * present after the compressed stream.
149 */
150 if (err != Z_OK || inbuf == Z_NULL)
151 {
152 destroy ();
153 z_err = Z_STREAM_ERROR;
154 return;
155 }
156 }
157 stream.avail_out = 16384;
158
159 errno = 0;
160 if (mode == 'w')
161 {
162 /* Write a very simple .gz header:
163 */
164 char temp[20];
165 sprintf (temp, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
166 Z_DEFLATED, 0 /*flags */ , 0, 0, 0, 0 /*time */ ,
167 0 /*xflags */ , 0x0b);
168 original->write (temp, 10);
169 startpos = 10L;
170 /* We use 10L instead of ftell(s->file) to because ftell causes an
171 * fflush on some systems. This version of the library doesn't use
172 * startpos anyway in write mode, so this initialization is not
173 * necessary.
174 */
175 }
176 else
177 {
178
179 check_header (); /* skip the .gz header */
180 startpos = (original->tell () - stream.avail_in);
181 }
182
183 return;
184 }
185
186 /* ===========================================================================
187 Outputs a long in LSB order to the given file
188 */
189 void
190 compress_gz::putLong (unsigned long x)
191 {
192 int n;
193 for (n = 0; n < 4; n++)
194 {
195 unsigned char c = (unsigned char) (x & 0xff);
196 original->write (&c, 1);
197 x = x >> 8;
198 }
199 }
200
201
202 uLong
203 compress_gz::getLong ()
204 {
205 uLong x = (uLong) get_byte ();
206 int c;
207
208 x += ((uLong) get_byte ()) << 8;
209 x += ((uLong) get_byte ()) << 16;
210 c = get_byte ();
211 if (c == EOF)
212 z_err = Z_DATA_ERROR;
213 x += ((uLong) c) << 24;
214 return x;
215 }
216
217
218 ssize_t
219 compress_gz::read (void *buffer, size_t len)
220 {
221 if (!len)
222 return 0;
223
224 if (peeklen)
225 {
226 ssize_t tmplen = min (peeklen, len);
227 peeklen -= tmplen;
228 memcpy (buffer, peekbuf, tmplen);
229 memmove (peekbuf, peekbuf + tmplen, tmplen);
230 ssize_t tmpread = read (&((char *) buffer)[tmplen], len - tmplen);
231 if (tmpread >= 0)
232 return tmpread + tmplen;
233 else
234 return tmpread;
235 }
236
237 Bytef *start = (Bytef *) buffer; /* starting point for crc computation */
238 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
239
240 if (mode != 'r')
241 return Z_STREAM_ERROR;
242
243 if (z_err == Z_DATA_ERROR || z_err == Z_ERRNO)
244 return -1;
245 if (z_err == Z_STREAM_END)
246 return 0; /* EOF */
247
248 next_out = (Byte *) buffer;
249 stream.next_out = (Bytef *) buffer;
250 stream.avail_out = len;
251
252 while (stream.avail_out != 0)
253 {
254
255 if (transparent)
256 {
257 /* Copy first the lookahead bytes: */
258 uInt n = stream.avail_in;
259 if (n > stream.avail_out)
260 n = stream.avail_out;
261 if (n > 0)
262 {
263 memcpy (stream.next_out, stream.next_in, n);
264 next_out += n;
265 stream.next_out = next_out;
266 stream.next_in += n;
267 stream.avail_out -= n;
268 stream.avail_in -= n;
269 }
270 if (stream.avail_out > 0)
271 {
272 stream.avail_out -= original->read (next_out, stream.avail_out);
273 }
274 len -= stream.avail_out;
275 stream.total_in += (uLong) len;
276 stream.total_out += (uLong) len;
277 if (len == 0)
278 z_eof = 1;
279 return (int) len;
280 }
281 if (stream.avail_in == 0 && !z_eof)
282 {
283
284 errno = 0;
285 stream.avail_in = original->read (inbuf, 16384);
286 if (stream.avail_in == 0)
287 {
288 z_eof = 1;
289 if (original->error ())
290 {
291 z_err = Z_ERRNO;
292 break;
293 }
294 }
295 stream.next_in = inbuf;
296 }
297 z_err = inflate (&(stream), Z_NO_FLUSH);
298
299 if (z_err == Z_STREAM_END)
300 {
301 /* Check CRC and original size */
302 crc = crc32 (crc, start, (uInt) (stream.next_out - start));
303 start = stream.next_out;
304
305 if (getLong () != crc)
306 {
307 z_err = Z_DATA_ERROR;
308 }
309 else
310 {
311 (void) getLong ();
312 /* The uncompressed length returned by above getlong() may
313 * be different from stream.total_out) in case of
314 * concatenated .gz files. Check for such files:
315 */
316 check_header ();
317 if (z_err == Z_OK)
318 {
319 uLong total_in = stream.total_in;
320 uLong total_out = stream.total_out;
321
322 inflateReset (&(stream));
323 stream.total_in = total_in;
324 stream.total_out = total_out;
325 crc = crc32 (0L, Z_NULL, 0);
326 }
327 }
328 }
329 if (z_err != Z_OK || z_eof)
330 break;
331 }
332 crc = crc32 (crc, start, (uInt) (stream.next_out - start));
333
334 return (int) (len - stream.avail_out);
335 }
336
337
338 /* ===========================================================================
339 Writes the given number of uncompressed bytes into the compressed file.
340 gzwrite returns the number of bytes actually written (0 in case of error).
341 */
342 ssize_t
343 compress_gz::write (void *buffer, size_t len)
344 {
345 if (mode != 'w')
346 return Z_STREAM_ERROR;
347
348 stream.next_in = (Bytef *) buffer;
349 stream.avail_in = len;
350
351 while (stream.avail_in != 0)
352 {
353
354 if (stream.avail_out == 0)
355 {
356
357 stream.next_out = outbuf;
358 if (original->write (outbuf, 16384) != 16384)
359 {
360 z_err = Z_ERRNO;
361 break;
362 }
363 stream.avail_out = 16384;
364 }
365 z_err = deflate (&(stream), Z_NO_FLUSH);
366 if (z_err != Z_OK)
367 break;
368 }
369 crc = crc32 (crc, (const Bytef *) buffer, len);
370
371 return (int) (len - stream.avail_in);
372 }
373
374 ssize_t
375 compress_gz::peek (void *buffer, size_t len)
376 {
377 log (LOG_TIMESTAMP, "compress_gz::peek called");
378 if (mode != 'r')
379 return Z_STREAM_ERROR;
380 /* can only peek 512 bytes */
381 if (len > 512)
382 return ENOMEM;
383
384 if (len > peeklen)
385 {
386 size_t want = len - peeklen;
387 ssize_t got = read (&peekbuf[peeklen], want);
388 if (got >= 0)
389 peeklen += got;
390 else
391 /* error */
392 return got;
393 /* we may have read less than requested. */
394 memcpy (buffer, peekbuf, peeklen);
395 return peeklen;
396 }
397 else
398 {
399 memcpy (buffer, peekbuf, len);
400 return len;
401 }
402 }
403
404 long
405 compress_gz::tell ()
406 {
407 log (LOG_TIMESTAMP, "compress_gz::tell called");
408 return 0;
409 }
410
411 int
412 compress_gz::error ()
413 {
414 // log (LOG_TIMESTAMP, "compress_gz::error called");
415 return z_err;
416 }
417
418 int
419 compress_gz::set_mtime (int time)
420 {
421 if (original)
422 return original->set_mtime (time);
423 return 1;
424 }
425
426 int
427 compress_gz::get_mtime ()
428 {
429 if (original)
430 return original->get_mtime ();
431 return 0;
432 }
433
434 void
435 compress_gz::destroy ()
436 {
437 if (msg)
438 free (msg);
439 if (stream.state != NULL)
440 {
441 if (mode == 'w')
442 {
443 z_err = deflateEnd (&(stream));
444 }
445 else if (mode == 'r')
446 {
447 z_err = inflateEnd (&(stream));
448 }
449 }
450
451 if (inbuf)
452
453 free (inbuf);
454 if (outbuf)
455 free (outbuf);
456 if (original)
457 delete original;
458 }
459
460 compress_gz::~compress_gz ()
461 {
462 log (LOG_TIMESTAMP, "compress_gz::~gz called");
463 if (mode == 'w')
464 {
465 z_err = do_flush (Z_FINISH);
466 if (z_err != Z_OK)
467 {
468 destroy ();
469 return;
470 }
471
472 putLong (crc);
473 putLong (stream.total_in);
474 }
475 destroy ();
476 return;
477 }
478
479 int
480 compress_gz::do_flush (int flush)
481 {
482 uInt len;
483 int done = 0;
484 if (mode != 'w')
485 return Z_STREAM_ERROR;
486 stream.avail_in = 0; /* should be zero already anyway */
487 for (;;)
488 {
489 len = 16384 - stream.avail_out;
490 if (len != 0)
491 {
492 if ((uInt) original->write (outbuf, len) != len)
493 {
494 z_err = Z_ERRNO;
495 return Z_ERRNO;
496 }
497 stream.next_out = outbuf;
498 stream.avail_out = 16384;
499 }
500 if (done)
501 break;
502 z_err = deflate (&(stream), flush);
503 /* Ignore the second of two consecutive flushes: */
504 if (len == 0 && z_err == Z_BUF_ERROR)
505 z_err = Z_OK;
506 /* deflate has finished flushing only when it hasn't used up
507 * all the available space in the output buffer:
508 */
509 done = (stream.avail_out != 0 || z_err == Z_STREAM_END);
510 if (z_err != Z_OK && z_err != Z_STREAM_END)
511 break;
512 }
513 return z_err == Z_STREAM_END ? Z_OK : z_err;
514 }
515
516
517 #if 0
518
519 gzclose (lst);
520 #endif
521 /* ===========================================================================
522 * Read a byte from a gz_stream; update next_in and avail_in. Return EOF
523 * for end of file.
524 * IN assertion: the stream s has been sucessfully opened for reading.
525 */
526 int
527 compress_gz::get_byte ()
528 {
529 if (z_eof)
530 return EOF;
531 if (stream.avail_in == 0)
532 {
533 errno = 0;
534 stream.avail_in = original->read (inbuf, 16384);
535 if (stream.avail_in == 0)
536 {
537 z_eof = 1;
538 if (original->error ())
539 z_err = Z_ERRNO;
540 return EOF;
541 }
542 stream.next_in = inbuf;
543 }
544 stream.avail_in--;
545 return *(stream.next_in)++;
546 }
547
548
549 /* ===========================================================================
550 Check the gzip header of a gz_stream opened for reading. Set the stream
551 mode to transparent if the gzip magic header is not present; set s->err
552 to Z_DATA_ERROR if the magic header is present but the rest of the header
553 is incorrect.
554 IN assertion: the stream s has already been created sucessfully;
555 s->stream.avail_in is zero for the first time, but may be non-zero
556 for concatenated .gz files.
557 */
558 void
559 compress_gz::check_header ()
560 {
561 int method; /* method byte */
562 int flags; /* flags byte */
563 uInt len;
564 int c;
565 /* Check the gzip magic header */
566 for (len = 0; len < 2; len++)
567 {
568 c = get_byte ();
569 if (c != gz_magic[len])
570 {
571 if (len != 0)
572 stream.avail_in++, stream.next_in--;
573 if (c != EOF)
574 {
575 stream.avail_in++, stream.next_in--;
576 transparent = 1;
577 }
578 z_err = stream.avail_in != 0 ? Z_OK : Z_STREAM_END;
579 return;
580 }
581 }
582 method = get_byte ();
583 flags = get_byte ();
584 if (method != Z_DEFLATED || (flags & RESERVED) != 0)
585 {
586 z_err = Z_DATA_ERROR;
587 return;
588 }
589
590 /* Discard time, xflags and OS code: */
591 for (len = 0; len < 6; len++)
592 (void) get_byte ();
593 if ((flags & EXTRA_FIELD) != 0)
594 { /* skip the extra field */
595 len = (uInt) get_byte ();
596 len += ((uInt) get_byte ()) << 8;
597 /* len is garbage if EOF but the loop below will quit anyway */
598 while (len-- != 0 && get_byte () != EOF);
599 }
600 if ((flags & ORIG_NAME) != 0)
601 { /* skip the original file name */
602 while ((c = get_byte ()) != 0 && c != EOF);
603 }
604 if ((flags & COMMENT) != 0)
605 { /* skip the .gz file comment */
606 while ((c = get_byte ()) != 0 && c != EOF);
607 }
608 if ((flags & HEAD_CRC) != 0)
609 { /* skip the header crc */
610 for (len = 0; len < 2; len++)
611 (void) get_byte ();
612 }
613 z_err = z_eof ? Z_DATA_ERROR : Z_OK;
614 }
This page took 0.059739 seconds and 5 git commands to generate.