]>
cygwin.com Git - cygwin-apps/setup.git/blob - compress_gz.cc
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
12 * Written by Robert Collins <rbtcollins@hotmail.com>
16 /* Archive IO operations for gz files
17 * Portions copyright under the zlib licence - this class was derived from gzio.c in that
22 static const char *cvsid
=
34 #include "io_stream.h"
36 #include "zlib/zlib.h"
37 #include "compress_gz.h"
39 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
40 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
41 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
42 #define COMMENT 0x10 /* bit 4 set: file comment present */
43 #define RESERVED 0xE0 /* bits 5..7: reserved */
46 /* TODO make this a static member and federate the magic logic */
47 static int gz_magic
[2] = { 0x1f, 0x8b }; /* gzip magic header */
50 * Predicate: the stream is open for read. For writing the class constructor variant with
51 * mode must be called directly
53 compress_gz::compress_gz (io_stream
* parent
)
55 construct (parent
, "r");
58 compress_gz::compress_gz (io_stream
* parent
, const char *openmode
)
60 construct (parent
, openmode
);
64 compress_gz::construct (io_stream
* parent
, const char *openmode
)
69 int level
= Z_DEFAULT_COMPRESSION
; /* compression level */
70 int strategy
= Z_DEFAULT_STRATEGY
; /* compression strategy */
71 char *p
= (char *) openmode
;
72 char fmode
[80]; /* copy of openmode, without the compression level */
75 stream
.zalloc
= (alloc_func
) NULL
;
76 stream
.zfree
= (free_func
) NULL
;
77 stream
.opaque
= (voidpf
) NULL
;
78 stream
.next_in
= inbuf
= NULL
;
79 stream
.next_out
= outbuf
= NULL
;
80 stream
.avail_in
= stream
.avail_out
= 0;
83 crc
= crc32 (0L, Z_NULL
, 0);
91 z_err
= Z_STREAM_ERROR
;
99 if (*p
== 'w' || *p
== 'a')
101 if (*p
>= '0' && *p
<= '9')
107 strategy
= Z_FILTERED
;
111 strategy
= Z_HUFFMAN_ONLY
;
115 *m
++ = *p
; /* copy the mode */
118 while (*p
++ && m
!= fmode
+ sizeof (fmode
));
122 z_err
= Z_STREAM_ERROR
;
129 err
= deflateInit2 (&(stream
), level
,
130 Z_DEFLATED
, -MAX_WBITS
, 8, strategy
);
131 /* windowBits is passed < 0 to suppress zlib header */
133 stream
.next_out
= outbuf
= (Byte
*) malloc (16384);
134 if (err
!= Z_OK
|| outbuf
== Z_NULL
)
137 z_err
= Z_STREAM_ERROR
;
144 stream
.next_in
= inbuf
= (unsigned char *) malloc (16384);
145 err
= inflateInit2 (&stream
, -MAX_WBITS
);
146 /* windowBits is passed < 0 to tell that there is no zlib header.
147 * Note that in this case inflate *requires* an extra "dummy" byte
148 * after the compressed stream in order to complete decompression and
149 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
150 * present after the compressed stream.
152 if (err
!= Z_OK
|| inbuf
== Z_NULL
)
155 z_err
= Z_STREAM_ERROR
;
159 stream
.avail_out
= 16384;
164 /* Write a very simple .gz header:
167 sprintf (temp
, "%c%c%c%c%c%c%c%c%c%c", gz_magic
[0], gz_magic
[1],
168 Z_DEFLATED
, 0 /*flags */ , 0, 0, 0, 0 /*time */ ,
169 0 /*xflags */ , 0x0b);
170 original
->write (temp
, 10);
172 /* We use 10L instead of ftell(s->file) to because ftell causes an
173 * fflush on some systems. This version of the library doesn't use
174 * startpos anyway in write mode, so this initialization is not
181 check_header (); /* skip the .gz header */
182 startpos
= (original
->tell () - stream
.avail_in
);
188 /* ===========================================================================
189 Outputs a long in LSB order to the given file
192 compress_gz::putLong (unsigned long x
)
195 for (n
= 0; n
< 4; n
++)
197 unsigned char c
= (unsigned char) (x
& 0xff);
198 original
->write (&c
, 1);
205 compress_gz::getLong ()
207 uLong x
= (uLong
) get_byte ();
210 x
+= ((uLong
) get_byte ()) << 8;
211 x
+= ((uLong
) get_byte ()) << 16;
214 z_err
= Z_DATA_ERROR
;
215 x
+= ((uLong
) c
) << 24;
221 compress_gz::read (void *buffer
, size_t len
)
228 ssize_t tmplen
= std::min (peeklen
, len
);
230 memcpy (buffer
, peekbuf
, tmplen
);
231 memmove (peekbuf
, peekbuf
+ tmplen
, tmplen
);
232 ssize_t tmpread
= read (&((char *) buffer
)[tmplen
], len
- tmplen
);
234 return tmpread
+ tmplen
;
239 Bytef
*start
= (Bytef
*) buffer
; /* starting point for crc computation */
240 Byte
*next_out
; /* == stream.next_out but not forced far (for MSDOS) */
243 return Z_STREAM_ERROR
;
245 if (z_err
== Z_DATA_ERROR
|| z_err
== Z_ERRNO
)
247 if (z_err
== Z_STREAM_END
)
250 next_out
= (Byte
*) buffer
;
251 stream
.next_out
= (Bytef
*) buffer
;
252 stream
.avail_out
= len
;
254 while (stream
.avail_out
!= 0)
259 /* Copy first the lookahead bytes: */
260 uInt n
= stream
.avail_in
;
261 if (n
> stream
.avail_out
)
262 n
= stream
.avail_out
;
265 memcpy (stream
.next_out
, stream
.next_in
, n
);
267 stream
.next_out
= next_out
;
269 stream
.avail_out
-= n
;
270 stream
.avail_in
-= n
;
272 if (stream
.avail_out
> 0)
274 stream
.avail_out
-= original
->read (next_out
, stream
.avail_out
);
276 len
-= stream
.avail_out
;
277 stream
.total_in
+= (uLong
) len
;
278 stream
.total_out
+= (uLong
) len
;
283 if (stream
.avail_in
== 0 && !z_eof
)
287 stream
.avail_in
= original
->read (inbuf
, 16384);
288 if (stream
.avail_in
== 0)
291 if (original
->error ())
297 stream
.next_in
= inbuf
;
299 z_err
= inflate (&(stream
), Z_NO_FLUSH
);
301 if (z_err
== Z_STREAM_END
)
303 /* Check CRC and original size */
304 crc
= crc32 (crc
, start
, (uInt
) (stream
.next_out
- start
));
305 start
= stream
.next_out
;
307 if (getLong () != crc
)
309 z_err
= Z_DATA_ERROR
;
314 /* The uncompressed length returned by above getlong() may
315 * be different from stream.total_out) in case of
316 * concatenated .gz files. Check for such files:
321 uLong total_in
= stream
.total_in
;
322 uLong total_out
= stream
.total_out
;
324 inflateReset (&(stream
));
325 stream
.total_in
= total_in
;
326 stream
.total_out
= total_out
;
327 crc
= crc32 (0L, Z_NULL
, 0);
331 if (z_err
!= Z_OK
|| z_eof
)
334 crc
= crc32 (crc
, start
, (uInt
) (stream
.next_out
- start
));
336 return (int) (len
- stream
.avail_out
);
340 /* ===========================================================================
341 Writes the given number of uncompressed bytes into the compressed file.
342 gzwrite returns the number of bytes actually written (0 in case of error).
345 compress_gz::write (const void *buffer
, size_t len
)
348 return Z_STREAM_ERROR
;
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)
365 stream
.avail_out
= 16384;
367 z_err
= deflate (&(stream
), Z_NO_FLUSH
);
371 crc
= crc32 (crc
, (const Bytef
*) buffer
, len
);
373 return (int) (len
- stream
.avail_in
);
377 compress_gz::peek (void *buffer
, size_t len
)
380 return Z_STREAM_ERROR
;
381 /* can only peek 512 bytes */
387 size_t want
= len
- peeklen
;
388 ssize_t got
= read (&peekbuf
[peeklen
], want
);
394 /* we may have read less than requested. */
395 memcpy (buffer
, peekbuf
, peeklen
);
400 memcpy (buffer
, peekbuf
, len
);
408 log (LOG_TIMESTAMP
, "compress_gz::tell called");
413 compress_gz::seek (long where
, io_stream_seek_t whence
)
415 log (LOG_TIMESTAMP
, "compress_gz::seek called");
420 compress_gz::error ()
422 if (z_err
&& z_err
!= Z_STREAM_END
)
428 compress_gz::set_mtime (int time
)
431 return original
->set_mtime (time
);
436 compress_gz::get_mtime ()
439 return original
->get_mtime ();
444 compress_gz::destroy ()
448 if (stream
.state
!= NULL
)
452 z_err
= deflateEnd (&(stream
));
454 else if (mode
== 'r')
456 z_err
= inflateEnd (&(stream
));
469 compress_gz::~compress_gz ()
473 z_err
= do_flush (Z_FINISH
);
481 putLong (stream
.total_in
);
489 compress_gz::do_flush (int flush
)
494 return Z_STREAM_ERROR
;
495 stream
.avail_in
= 0; /* should be zero already anyway */
498 len
= 16384 - stream
.avail_out
;
501 if ((uInt
) original
->write (outbuf
, len
) != len
)
506 stream
.next_out
= outbuf
;
507 stream
.avail_out
= 16384;
511 z_err
= deflate (&(stream
), flush
);
512 /* Ignore the second of two consecutive flushes: */
513 if (len
== 0 && z_err
== Z_BUF_ERROR
)
515 /* deflate has finished flushing only when it hasn't used up
516 * all the available space in the output buffer:
518 done
= (stream
.avail_out
!= 0 || z_err
== Z_STREAM_END
);
519 if (z_err
!= Z_OK
&& z_err
!= Z_STREAM_END
)
522 return z_err
== Z_STREAM_END
? Z_OK
: z_err
;
530 /* ===========================================================================
531 * Read a byte from a gz_stream; update next_in and avail_in. Return EOF
533 * IN assertion: the stream s has been sucessfully opened for reading.
536 compress_gz::get_byte ()
540 if (stream
.avail_in
== 0)
543 stream
.avail_in
= original
->read (inbuf
, 16384);
544 if (stream
.avail_in
== 0)
547 if (original
->error ())
551 stream
.next_in
= inbuf
;
554 return *(stream
.next_in
)++;
558 /* ===========================================================================
559 Check the gzip header of a gz_stream opened for reading. Set the stream
560 mode to transparent if the gzip magic header is not present; set s->err
561 to Z_DATA_ERROR if the magic header is present but the rest of the header
563 IN assertion: the stream s has already been created sucessfully;
564 s->stream.avail_in is zero for the first time, but may be non-zero
565 for concatenated .gz files.
568 compress_gz::check_header ()
570 int method
; /* method byte */
571 int flags
; /* flags byte */
574 /* Check the gzip magic header */
575 for (len
= 0; len
< 2; len
++)
578 if (c
!= gz_magic
[len
])
581 stream
.avail_in
++, stream
.next_in
--;
584 stream
.avail_in
++, stream
.next_in
--;
587 z_err
= stream
.avail_in
!= 0 ? Z_OK
: Z_STREAM_END
;
591 method
= get_byte ();
593 if (method
!= Z_DEFLATED
|| (flags
& RESERVED
) != 0)
595 z_err
= Z_DATA_ERROR
;
599 /* Discard time, xflags and OS code: */
600 for (len
= 0; len
< 6; len
++)
602 if ((flags
& EXTRA_FIELD
) != 0)
603 { /* skip the extra field */
604 len
= (uInt
) get_byte ();
605 len
+= ((uInt
) get_byte ()) << 8;
606 /* len is garbage if EOF but the loop below will quit anyway */
607 while (len
-- != 0 && get_byte () != EOF
);
609 if ((flags
& ORIG_NAME
) != 0)
610 { /* skip the original file name */
611 while ((c
= get_byte ()) != 0 && c
!= EOF
);
613 if ((flags
& COMMENT
) != 0)
614 { /* skip the .gz file comment */
615 while ((c
= get_byte ()) != 0 && c
!= EOF
);
617 if ((flags
& HEAD_CRC
) != 0)
618 { /* skip the header crc */
619 for (len
= 0; len
< 2; len
++)
622 z_err
= z_eof
? Z_DATA_ERROR
: Z_OK
;
This page took 0.060856 seconds and 5 git commands to generate.