Add our READMEs.
[dragonfly.git] / contrib / libarchive-2.1 / libarchive / archive_write_set_compression_gzip.c
1 /*-
2  * Copyright (c) 2003-2007 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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.
24  */
25
26 #include "archive_platform.h"
27
28 /* Don't compile this if we don't have zlib. */
29 #if HAVE_ZLIB_H
30
31 __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_gzip.c,v 1.13 2007/03/03 07:37:36 kientzle Exp $");
32
33 #ifdef HAVE_ERRNO_H
34 #include <errno.h>
35 #endif
36 #ifdef HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39 #ifdef HAVE_STRING_H
40 #include <string.h>
41 #endif
42 #include <time.h>
43 #ifdef HAVE_ZLIB_H
44 #include <zlib.h>
45 #endif
46
47 #include "archive.h"
48 #include "archive_private.h"
49 #include "archive_write_private.h"
50
51 struct private_data {
52         z_stream         stream;
53         int64_t          total_in;
54         unsigned char   *compressed;
55         size_t           compressed_buffer_size;
56         unsigned long    crc;
57 };
58
59
60 /*
61  * Yuck.  zlib.h is not const-correct, so I need this one bit
62  * of ugly hackery to convert a const * pointer to a non-const pointer.
63  */
64 #define SET_NEXT_IN(st,src)                                     \
65         (st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src)
66
67 static int      archive_compressor_gzip_finish(struct archive_write *);
68 static int      archive_compressor_gzip_init(struct archive_write *);
69 static int      archive_compressor_gzip_write(struct archive_write *,
70                     const void *, size_t);
71 static int      drive_compressor(struct archive_write *, struct private_data *,
72                     int finishing);
73
74
75 /*
76  * Allocate, initialize and return a archive object.
77  */
78 int
79 archive_write_set_compression_gzip(struct archive *_a)
80 {
81         struct archive_write *a = (struct archive_write *)_a;
82         __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
83             ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
84         a->compressor.init = &archive_compressor_gzip_init;
85         a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
86         a->archive.compression_name = "gzip";
87         return (ARCHIVE_OK);
88 }
89
90 /*
91  * Setup callback.
92  */
93 static int
94 archive_compressor_gzip_init(struct archive_write *a)
95 {
96         int ret;
97         struct private_data *state;
98         time_t t;
99
100         a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
101         a->archive.compression_name = "gzip";
102
103         if (a->client_opener != NULL) {
104                 ret = (a->client_opener)(&a->archive, a->client_data);
105                 if (ret != ARCHIVE_OK)
106                         return (ret);
107         }
108
109         state = (struct private_data *)malloc(sizeof(*state));
110         if (state == NULL) {
111                 archive_set_error(&a->archive, ENOMEM,
112                     "Can't allocate data for compression");
113                 return (ARCHIVE_FATAL);
114         }
115         memset(state, 0, sizeof(*state));
116
117         state->compressed_buffer_size = a->bytes_per_block;
118         state->compressed = (unsigned char *)malloc(state->compressed_buffer_size);
119         state->crc = crc32(0L, NULL, 0);
120
121         if (state->compressed == NULL) {
122                 archive_set_error(&a->archive, ENOMEM,
123                     "Can't allocate data for compression buffer");
124                 free(state);
125                 return (ARCHIVE_FATAL);
126         }
127
128         state->stream.next_out = state->compressed;
129         state->stream.avail_out = state->compressed_buffer_size;
130
131         /* Prime output buffer with a gzip header. */
132         t = time(NULL);
133         state->compressed[0] = 0x1f; /* GZip signature bytes */
134         state->compressed[1] = 0x8b;
135         state->compressed[2] = 0x08; /* "Deflate" compression */
136         state->compressed[3] = 0; /* No options */
137         state->compressed[4] = (t)&0xff;  /* Timestamp */
138         state->compressed[5] = (t>>8)&0xff;
139         state->compressed[6] = (t>>16)&0xff;
140         state->compressed[7] = (t>>24)&0xff;
141         state->compressed[8] = 0; /* No deflate options */
142         state->compressed[9] = 3; /* OS=Unix */
143         state->stream.next_out += 10;
144         state->stream.avail_out -= 10;
145
146         a->compressor.write = archive_compressor_gzip_write;
147         a->compressor.finish = archive_compressor_gzip_finish;
148
149         /* Initialize compression library. */
150         ret = deflateInit2(&(state->stream),
151             Z_DEFAULT_COMPRESSION,
152             Z_DEFLATED,
153             -15 /* < 0 to suppress zlib header */,
154             8,
155             Z_DEFAULT_STRATEGY);
156
157         if (ret == Z_OK) {
158                 a->compressor.data = state;
159                 return (0);
160         }
161
162         /* Library setup failed: clean up. */
163         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Internal error "
164             "initializing compression library");
165         free(state->compressed);
166         free(state);
167
168         /* Override the error message if we know what really went wrong. */
169         switch (ret) {
170         case Z_STREAM_ERROR:
171                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
172                     "Internal error initializing "
173                     "compression library: invalid setup parameter");
174                 break;
175         case Z_MEM_ERROR:
176                 archive_set_error(&a->archive, ENOMEM, "Internal error initializing "
177                     "compression library");
178                 break;
179         case Z_VERSION_ERROR:
180                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
181                     "Internal error initializing "
182                     "compression library: invalid library version");
183                 break;
184         }
185
186         return (ARCHIVE_FATAL);
187 }
188
189 /*
190  * Write data to the compressed stream.
191  */
192 static int
193 archive_compressor_gzip_write(struct archive_write *a, const void *buff,
194     size_t length)
195 {
196         struct private_data *state;
197         int ret;
198
199         state = (struct private_data *)a->compressor.data;
200         if (a->client_writer == NULL) {
201                 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
202                     "No write callback is registered?  "
203                     "This is probably an internal programming error.");
204                 return (ARCHIVE_FATAL);
205         }
206
207         /* Update statistics */
208         state->crc = crc32(state->crc, (const Bytef *)buff, length);
209         state->total_in += length;
210
211         /* Compress input data to output buffer */
212         SET_NEXT_IN(state, buff);
213         state->stream.avail_in = length;
214         if ((ret = drive_compressor(a, state, 0)) != ARCHIVE_OK)
215                 return (ret);
216
217         a->archive.file_position += length;
218         return (ARCHIVE_OK);
219 }
220
221
222 /*
223  * Finish the compression...
224  */
225 static int
226 archive_compressor_gzip_finish(struct archive_write *a)
227 {
228         ssize_t block_length, target_block_length, bytes_written;
229         int ret;
230         struct private_data *state;
231         unsigned tocopy;
232         unsigned char trailer[8];
233
234         state = (struct private_data *)a->compressor.data;
235         ret = 0;
236         if (a->client_writer == NULL) {
237                 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
238                     "No write callback is registered?  "
239                     "This is probably an internal programming error.");
240                 ret = ARCHIVE_FATAL;
241                 goto cleanup;
242         }
243
244         /* By default, always pad the uncompressed data. */
245         if (a->pad_uncompressed) {
246                 tocopy = a->bytes_per_block -
247                     (state->total_in % a->bytes_per_block);
248                 while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
249                         SET_NEXT_IN(state, a->nulls);
250                         state->stream.avail_in = tocopy < a->null_length ?
251                             tocopy : a->null_length;
252                         state->crc = crc32(state->crc, a->nulls,
253                             state->stream.avail_in);
254                         state->total_in += state->stream.avail_in;
255                         tocopy -= state->stream.avail_in;
256                         ret = drive_compressor(a, state, 0);
257                         if (ret != ARCHIVE_OK)
258                                 goto cleanup;
259                 }
260         }
261
262         /* Finish compression cycle */
263         if (((ret = drive_compressor(a, state, 1))) != ARCHIVE_OK)
264                 goto cleanup;
265
266         /* Build trailer: 4-byte CRC and 4-byte length. */
267         trailer[0] = (state->crc)&0xff;
268         trailer[1] = (state->crc >> 8)&0xff;
269         trailer[2] = (state->crc >> 16)&0xff;
270         trailer[3] = (state->crc >> 24)&0xff;
271         trailer[4] = (state->total_in)&0xff;
272         trailer[5] = (state->total_in >> 8)&0xff;
273         trailer[6] = (state->total_in >> 16)&0xff;
274         trailer[7] = (state->total_in >> 24)&0xff;
275
276         /* Add trailer to current block. */
277         tocopy = 8;
278         if (tocopy > state->stream.avail_out)
279                 tocopy = state->stream.avail_out;
280         memcpy(state->stream.next_out, trailer, tocopy);
281         state->stream.next_out += tocopy;
282         state->stream.avail_out -= tocopy;
283
284         /* If it overflowed, flush and start a new block. */
285         if (tocopy < 8) {
286                 bytes_written = (a->client_writer)(&a->archive, a->client_data,
287                     state->compressed, state->compressed_buffer_size);
288                 if (bytes_written <= 0) {
289                         ret = ARCHIVE_FATAL;
290                         goto cleanup;
291                 }
292                 a->archive.raw_position += bytes_written;
293                 state->stream.next_out = state->compressed;
294                 state->stream.avail_out = state->compressed_buffer_size;
295                 memcpy(state->stream.next_out, trailer + tocopy, 8-tocopy);
296                 state->stream.next_out += 8-tocopy;
297                 state->stream.avail_out -= 8-tocopy;
298         }
299
300         /* Optionally, pad the final compressed block. */
301         block_length = state->stream.next_out - state->compressed;
302
303
304         /* Tricky calculation to determine size of last block. */
305         target_block_length = block_length;
306         if (a->bytes_in_last_block <= 0)
307                 /* Default or Zero: pad to full block */
308                 target_block_length = a->bytes_per_block;
309         else
310                 /* Round length to next multiple of bytes_in_last_block. */
311                 target_block_length = a->bytes_in_last_block *
312                     ( (block_length + a->bytes_in_last_block - 1) /
313                         a->bytes_in_last_block);
314         if (target_block_length > a->bytes_per_block)
315                 target_block_length = a->bytes_per_block;
316         if (block_length < target_block_length) {
317                 memset(state->stream.next_out, 0,
318                     target_block_length - block_length);
319                 block_length = target_block_length;
320         }
321
322         /* Write the last block */
323         bytes_written = (a->client_writer)(&a->archive, a->client_data,
324             state->compressed, block_length);
325         if (bytes_written <= 0) {
326                 ret = ARCHIVE_FATAL;
327                 goto cleanup;
328         }
329         a->archive.raw_position += bytes_written;
330
331         /* Cleanup: shut down compressor, release memory, etc. */
332 cleanup:
333         switch (deflateEnd(&(state->stream))) {
334         case Z_OK:
335                 break;
336         default:
337                 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
338                     "Failed to clean up compressor");
339                 ret = ARCHIVE_FATAL;
340         }
341         free(state->compressed);
342         free(state);
343         return (ret);
344 }
345
346 /*
347  * Utility function to push input data through compressor,
348  * writing full output blocks as necessary.
349  *
350  * Note that this handles both the regular write case (finishing ==
351  * false) and the end-of-archive case (finishing == true).
352  */
353 static int
354 drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
355 {
356         ssize_t bytes_written;
357         int ret;
358
359         for (;;) {
360                 if (state->stream.avail_out == 0) {
361                         bytes_written = (a->client_writer)(&a->archive,
362                             a->client_data, state->compressed,
363                             state->compressed_buffer_size);
364                         if (bytes_written <= 0) {
365                                 /* TODO: Handle this write failure */
366                                 return (ARCHIVE_FATAL);
367                         } else if ((size_t)bytes_written < state->compressed_buffer_size) {
368                                 /* Short write: Move remaining to
369                                  * front of block and keep filling */
370                                 memmove(state->compressed,
371                                     state->compressed + bytes_written,
372                                     state->compressed_buffer_size - bytes_written);
373                         }
374                         a->archive.raw_position += bytes_written;
375                         state->stream.next_out
376                             = state->compressed +
377                             state->compressed_buffer_size - bytes_written;
378                         state->stream.avail_out = bytes_written;
379                 }
380
381                 ret = deflate(&(state->stream),
382                     finishing ? Z_FINISH : Z_NO_FLUSH );
383
384                 switch (ret) {
385                 case Z_OK:
386                         /* In non-finishing case, check if compressor
387                          * consumed everything */
388                         if (!finishing && state->stream.avail_in == 0)
389                                 return (ARCHIVE_OK);
390                         /* In finishing case, this return always means
391                          * there's more work */
392                         break;
393                 case Z_STREAM_END:
394                         /* This return can only occur in finishing case. */
395                         return (ARCHIVE_OK);
396                 default:
397                         /* Any other return value indicates an error. */
398                         archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
399                             "GZip compression failed");
400                         return (ARCHIVE_FATAL);
401                 }
402         }
403 }
404
405 #endif /* HAVE_ZLIB_H */