2 * Copyright (c) 2003-2007 Tim Kientzle
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_gzip.c,v 1.16 2008/02/21 03:21:50 kientzle Exp $");
45 #include "archive_private.h"
46 #include "archive_write_private.h"
50 archive_write_set_compression_gzip(struct archive
*a
)
52 archive_set_error(a
, ARCHIVE_ERRNO_MISC
,
53 "gzip compression not supported on this platform");
54 return (ARCHIVE_FATAL
);
57 /* Don't compile this if we don't have zlib. */
62 unsigned char *compressed
;
63 size_t compressed_buffer_size
;
67 struct private_config
{
68 int compression_level
;
73 * Yuck. zlib.h is not const-correct, so I need this one bit
74 * of ugly hackery to convert a const * pointer to a non-const pointer.
76 #define SET_NEXT_IN(st,src) \
77 (st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src)
79 static int archive_compressor_gzip_finish(struct archive_write
*);
80 static int archive_compressor_gzip_init(struct archive_write
*);
81 static int archive_compressor_gzip_options(struct archive_write
*,
82 const char *, const char *);
83 static int archive_compressor_gzip_write(struct archive_write
*,
84 const void *, size_t);
85 static int drive_compressor(struct archive_write
*, struct private_data
*,
90 * Allocate, initialize and return a archive object.
93 archive_write_set_compression_gzip(struct archive
*_a
)
95 struct archive_write
*a
= (struct archive_write
*)_a
;
96 struct private_config
*config
;
97 __archive_check_magic(&a
->archive
, ARCHIVE_WRITE_MAGIC
,
98 ARCHIVE_STATE_NEW
, "archive_write_set_compression_gzip");
99 config
= malloc(sizeof(*config
));
100 if (config
== NULL
) {
101 archive_set_error(&a
->archive
, ENOMEM
, "Out of memory");
102 return (ARCHIVE_FATAL
);
104 a
->compressor
.config
= config
;
105 a
->compressor
.finish
= &archive_compressor_gzip_finish
;
106 config
->compression_level
= Z_DEFAULT_COMPRESSION
;
107 a
->compressor
.init
= &archive_compressor_gzip_init
;
108 a
->compressor
.options
= &archive_compressor_gzip_options
;
109 a
->archive
.compression_code
= ARCHIVE_COMPRESSION_GZIP
;
110 a
->archive
.compression_name
= "gzip";
118 archive_compressor_gzip_init(struct archive_write
*a
)
121 struct private_data
*state
;
122 struct private_config
*config
;
125 config
= (struct private_config
*)a
->compressor
.config
;
127 if (a
->client_opener
!= NULL
) {
128 ret
= (a
->client_opener
)(&a
->archive
, a
->client_data
);
129 if (ret
!= ARCHIVE_OK
)
134 * The next check is a temporary workaround until the gzip
135 * code can be overhauled some. The code should not require
136 * that compressed_buffer_size == bytes_per_block. Removing
137 * this assumption will allow us to compress larger chunks at
138 * a time, which should improve overall performance
139 * marginally. As a minor side-effect, such a cleanup would
140 * allow us to support truly arbitrary block sizes.
142 if (a
->bytes_per_block
< 10) {
143 archive_set_error(&a
->archive
, EINVAL
,
144 "GZip compressor requires a minimum 10 byte block size");
145 return (ARCHIVE_FATAL
);
148 state
= (struct private_data
*)malloc(sizeof(*state
));
150 archive_set_error(&a
->archive
, ENOMEM
,
151 "Can't allocate data for compression");
152 return (ARCHIVE_FATAL
);
154 memset(state
, 0, sizeof(*state
));
157 * See comment above. We should set compressed_buffer_size to
158 * max(bytes_per_block, 65536), but the code can't handle that yet.
160 state
->compressed_buffer_size
= a
->bytes_per_block
;
161 state
->compressed
= (unsigned char *)malloc(state
->compressed_buffer_size
);
162 state
->crc
= crc32(0L, NULL
, 0);
164 if (state
->compressed
== NULL
) {
165 archive_set_error(&a
->archive
, ENOMEM
,
166 "Can't allocate data for compression buffer");
168 return (ARCHIVE_FATAL
);
171 state
->stream
.next_out
= state
->compressed
;
172 state
->stream
.avail_out
= state
->compressed_buffer_size
;
174 /* Prime output buffer with a gzip header. */
176 state
->compressed
[0] = 0x1f; /* GZip signature bytes */
177 state
->compressed
[1] = 0x8b;
178 state
->compressed
[2] = 0x08; /* "Deflate" compression */
179 state
->compressed
[3] = 0; /* No options */
180 state
->compressed
[4] = (t
)&0xff; /* Timestamp */
181 state
->compressed
[5] = (t
>>8)&0xff;
182 state
->compressed
[6] = (t
>>16)&0xff;
183 state
->compressed
[7] = (t
>>24)&0xff;
184 state
->compressed
[8] = 0; /* No deflate options */
185 state
->compressed
[9] = 3; /* OS=Unix */
186 state
->stream
.next_out
+= 10;
187 state
->stream
.avail_out
-= 10;
189 a
->compressor
.write
= archive_compressor_gzip_write
;
191 /* Initialize compression library. */
192 ret
= deflateInit2(&(state
->stream
),
193 config
->compression_level
,
195 -15 /* < 0 to suppress zlib header */,
200 a
->compressor
.data
= state
;
204 /* Library setup failed: clean up. */
205 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_MISC
, "Internal error "
206 "initializing compression library");
207 free(state
->compressed
);
210 /* Override the error message if we know what really went wrong. */
213 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_MISC
,
214 "Internal error initializing "
215 "compression library: invalid setup parameter");
218 archive_set_error(&a
->archive
, ENOMEM
, "Internal error initializing "
219 "compression library");
221 case Z_VERSION_ERROR
:
222 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_MISC
,
223 "Internal error initializing "
224 "compression library: invalid library version");
228 return (ARCHIVE_FATAL
);
235 archive_compressor_gzip_options(struct archive_write
*a
, const char *key
,
238 struct private_config
*config
;
240 config
= (struct private_config
*)a
->compressor
.config
;
241 if (strcmp(key
, "compression-level") == 0) {
242 if (value
== NULL
|| !(value
[0] >= '0' && value
[0] <= '9') ||
244 return (ARCHIVE_WARN
);
245 config
->compression_level
= value
[0] - '0';
249 return (ARCHIVE_WARN
);
253 * Write data to the compressed stream.
256 archive_compressor_gzip_write(struct archive_write
*a
, const void *buff
,
259 struct private_data
*state
;
262 state
= (struct private_data
*)a
->compressor
.data
;
263 if (a
->client_writer
== NULL
) {
264 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_PROGRAMMER
,
265 "No write callback is registered? "
266 "This is probably an internal programming error.");
267 return (ARCHIVE_FATAL
);
270 /* Update statistics */
271 state
->crc
= crc32(state
->crc
, (const Bytef
*)buff
, length
);
272 state
->total_in
+= length
;
274 /* Compress input data to output buffer */
275 SET_NEXT_IN(state
, buff
);
276 state
->stream
.avail_in
= length
;
277 if ((ret
= drive_compressor(a
, state
, 0)) != ARCHIVE_OK
)
280 a
->archive
.file_position
+= length
;
285 * Finish the compression...
288 archive_compressor_gzip_finish(struct archive_write
*a
)
290 ssize_t block_length
, target_block_length
, bytes_written
;
292 struct private_data
*state
;
294 unsigned char trailer
[8];
296 state
= (struct private_data
*)a
->compressor
.data
;
299 if (a
->client_writer
== NULL
) {
300 archive_set_error(&a
->archive
,
301 ARCHIVE_ERRNO_PROGRAMMER
,
302 "No write callback is registered? "
303 "This is probably an internal programming error.");
308 /* By default, always pad the uncompressed data. */
309 if (a
->pad_uncompressed
) {
310 tocopy
= a
->bytes_per_block
-
311 (state
->total_in
% a
->bytes_per_block
);
312 while (tocopy
> 0 && tocopy
< (unsigned)a
->bytes_per_block
) {
313 SET_NEXT_IN(state
, a
->nulls
);
314 state
->stream
.avail_in
= tocopy
< a
->null_length
?
315 tocopy
: a
->null_length
;
316 state
->crc
= crc32(state
->crc
, a
->nulls
,
317 state
->stream
.avail_in
);
318 state
->total_in
+= state
->stream
.avail_in
;
319 tocopy
-= state
->stream
.avail_in
;
320 ret
= drive_compressor(a
, state
, 0);
321 if (ret
!= ARCHIVE_OK
)
326 /* Finish compression cycle */
327 if (((ret
= drive_compressor(a
, state
, 1))) != ARCHIVE_OK
)
330 /* Build trailer: 4-byte CRC and 4-byte length. */
331 trailer
[0] = (state
->crc
)&0xff;
332 trailer
[1] = (state
->crc
>> 8)&0xff;
333 trailer
[2] = (state
->crc
>> 16)&0xff;
334 trailer
[3] = (state
->crc
>> 24)&0xff;
335 trailer
[4] = (state
->total_in
)&0xff;
336 trailer
[5] = (state
->total_in
>> 8)&0xff;
337 trailer
[6] = (state
->total_in
>> 16)&0xff;
338 trailer
[7] = (state
->total_in
>> 24)&0xff;
340 /* Add trailer to current block. */
342 if (tocopy
> state
->stream
.avail_out
)
343 tocopy
= state
->stream
.avail_out
;
344 memcpy(state
->stream
.next_out
, trailer
, tocopy
);
345 state
->stream
.next_out
+= tocopy
;
346 state
->stream
.avail_out
-= tocopy
;
348 /* If it overflowed, flush and start a new block. */
350 bytes_written
= (a
->client_writer
)(&a
->archive
, a
->client_data
,
351 state
->compressed
, state
->compressed_buffer_size
);
352 if (bytes_written
<= 0) {
356 a
->archive
.raw_position
+= bytes_written
;
357 state
->stream
.next_out
= state
->compressed
;
358 state
->stream
.avail_out
= state
->compressed_buffer_size
;
359 memcpy(state
->stream
.next_out
, trailer
+ tocopy
, 8-tocopy
);
360 state
->stream
.next_out
+= 8-tocopy
;
361 state
->stream
.avail_out
-= 8-tocopy
;
364 /* Optionally, pad the final compressed block. */
365 block_length
= state
->stream
.next_out
- state
->compressed
;
367 /* Tricky calculation to determine size of last block. */
368 target_block_length
= block_length
;
369 if (a
->bytes_in_last_block
<= 0)
370 /* Default or Zero: pad to full block */
371 target_block_length
= a
->bytes_per_block
;
373 /* Round length to next multiple of bytes_in_last_block. */
374 target_block_length
= a
->bytes_in_last_block
*
375 ( (block_length
+ a
->bytes_in_last_block
- 1) /
376 a
->bytes_in_last_block
);
377 if (target_block_length
> a
->bytes_per_block
)
378 target_block_length
= a
->bytes_per_block
;
379 if (block_length
< target_block_length
) {
380 memset(state
->stream
.next_out
, 0,
381 target_block_length
- block_length
);
382 block_length
= target_block_length
;
385 /* Write the last block */
386 bytes_written
= (a
->client_writer
)(&a
->archive
, a
->client_data
,
387 state
->compressed
, block_length
);
388 if (bytes_written
<= 0) {
392 a
->archive
.raw_position
+= bytes_written
;
394 /* Cleanup: shut down compressor, release memory, etc. */
396 switch (deflateEnd(&(state
->stream
))) {
400 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_MISC
,
401 "Failed to clean up compressor");
404 free(state
->compressed
);
407 /* Clean up config area even if we never initialized. */
408 free(a
->compressor
.config
);
409 a
->compressor
.config
= NULL
;
414 * Utility function to push input data through compressor,
415 * writing full output blocks as necessary.
417 * Note that this handles both the regular write case (finishing ==
418 * false) and the end-of-archive case (finishing == true).
421 drive_compressor(struct archive_write
*a
, struct private_data
*state
, int finishing
)
423 ssize_t bytes_written
;
427 if (state
->stream
.avail_out
== 0) {
428 bytes_written
= (a
->client_writer
)(&a
->archive
,
429 a
->client_data
, state
->compressed
,
430 state
->compressed_buffer_size
);
431 if (bytes_written
<= 0) {
432 /* TODO: Handle this write failure */
433 return (ARCHIVE_FATAL
);
434 } else if ((size_t)bytes_written
< state
->compressed_buffer_size
) {
435 /* Short write: Move remaining to
436 * front of block and keep filling */
437 memmove(state
->compressed
,
438 state
->compressed
+ bytes_written
,
439 state
->compressed_buffer_size
- bytes_written
);
441 a
->archive
.raw_position
+= bytes_written
;
442 state
->stream
.next_out
443 = state
->compressed
+
444 state
->compressed_buffer_size
- bytes_written
;
445 state
->stream
.avail_out
= bytes_written
;
448 /* If there's nothing to do, we're done. */
449 if (!finishing
&& state
->stream
.avail_in
== 0)
452 ret
= deflate(&(state
->stream
),
453 finishing
? Z_FINISH
: Z_NO_FLUSH
);
457 /* In non-finishing case, check if compressor
458 * consumed everything */
459 if (!finishing
&& state
->stream
.avail_in
== 0)
461 /* In finishing case, this return always means
462 * there's more work */
465 /* This return can only occur in finishing case. */
468 /* Any other return value indicates an error. */
469 archive_set_error(&a
->archive
, ARCHIVE_ERRNO_MISC
,
470 "GZip compression failed:"
471 " deflate() call returned status %d",
473 return (ARCHIVE_FATAL
);
478 #endif /* HAVE_ZLIB_H */