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$");
45 #include "archive_private.h"
46 #include "archive_write_private.h"
50 archive_write_set_compression_bzip2(struct archive *_a)
52 /* Unsupported bzip2 compression, we don't have bzlib */
53 return (ARCHIVE_FATAL);
56 /* Don't compile this if we don't have bzlib. */
62 size_t compressed_buffer_size;
67 * Yuck. bzlib.h is not const-correct, so I need this one bit
68 * of ugly hackery to convert a const * pointer to a non-const pointer.
70 #define SET_NEXT_IN(st,src) \
71 (st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
73 static int archive_compressor_bzip2_finish(struct archive_write *);
74 static int archive_compressor_bzip2_init(struct archive_write *);
75 static int archive_compressor_bzip2_write(struct archive_write *,
76 const void *, size_t);
77 static int drive_compressor(struct archive_write *, struct private_data *,
81 * Allocate, initialize and return an archive object.
84 archive_write_set_compression_bzip2(struct archive *_a)
86 struct archive_write *a = (struct archive_write *)_a;
87 __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
88 ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
89 a->compressor.init = &archive_compressor_bzip2_init;
97 archive_compressor_bzip2_init(struct archive_write *a)
100 struct private_data *state;
102 a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
103 a->archive.compression_name = "bzip2";
105 if (a->client_opener != NULL) {
106 ret = (a->client_opener)(&a->archive, a->client_data);
111 state = (struct private_data *)malloc(sizeof(*state));
113 archive_set_error(&a->archive, ENOMEM,
114 "Can't allocate data for compression");
115 return (ARCHIVE_FATAL);
117 memset(state, 0, sizeof(*state));
119 state->compressed_buffer_size = a->bytes_per_block;
120 state->compressed = (char *)malloc(state->compressed_buffer_size);
122 if (state->compressed == NULL) {
123 archive_set_error(&a->archive, ENOMEM,
124 "Can't allocate data for compression buffer");
126 return (ARCHIVE_FATAL);
129 state->stream.next_out = state->compressed;
130 state->stream.avail_out = state->compressed_buffer_size;
131 a->compressor.write = archive_compressor_bzip2_write;
132 a->compressor.finish = archive_compressor_bzip2_finish;
134 /* Initialize compression library */
135 ret = BZ2_bzCompressInit(&(state->stream), 9, 0, 30);
137 a->compressor.data = state;
141 /* Library setup failed: clean up. */
142 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
143 "Internal error initializing compression library");
144 free(state->compressed);
147 /* Override the error message if we know what really went wrong. */
150 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
151 "Internal error initializing compression library: "
152 "invalid setup parameter");
155 archive_set_error(&a->archive, ENOMEM,
156 "Internal error initializing compression library: "
159 case BZ_CONFIG_ERROR:
160 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
161 "Internal error initializing compression library: "
162 "mis-compiled library");
166 return (ARCHIVE_FATAL);
171 * Write data to the compressed stream.
173 * Returns ARCHIVE_OK if all data written, error otherwise.
176 archive_compressor_bzip2_write(struct archive_write *a, const void *buff,
179 struct private_data *state;
181 state = (struct private_data *)a->compressor.data;
182 if (a->client_writer == NULL) {
183 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
184 "No write callback is registered? "
185 "This is probably an internal programming error.");
186 return (ARCHIVE_FATAL);
189 /* Update statistics */
190 state->total_in += length;
192 /* Compress input data to output buffer */
193 SET_NEXT_IN(state, buff);
194 state->stream.avail_in = length;
195 if (drive_compressor(a, state, 0))
196 return (ARCHIVE_FATAL);
197 a->archive.file_position += length;
203 * Finish the compression.
206 archive_compressor_bzip2_finish(struct archive_write *a)
208 ssize_t block_length;
210 struct private_data *state;
211 ssize_t target_block_length;
212 ssize_t bytes_written;
215 state = (struct private_data *)a->compressor.data;
217 if (a->client_writer == NULL) {
218 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
219 "No write callback is registered?\n"
220 "This is probably an internal programming error.");
225 /* By default, always pad the uncompressed data. */
226 if (a->pad_uncompressed) {
227 tocopy = a->bytes_per_block -
228 (state->total_in % a->bytes_per_block);
229 while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
230 SET_NEXT_IN(state, a->nulls);
231 state->stream.avail_in = tocopy < a->null_length ?
232 tocopy : a->null_length;
233 state->total_in += state->stream.avail_in;
234 tocopy -= state->stream.avail_in;
235 ret = drive_compressor(a, state, 0);
236 if (ret != ARCHIVE_OK)
241 /* Finish compression cycle. */
242 if ((ret = drive_compressor(a, state, 1)))
245 /* Optionally, pad the final compressed block. */
246 block_length = state->stream.next_out - state->compressed;
249 /* Tricky calculation to determine size of last block. */
250 target_block_length = block_length;
251 if (a->bytes_in_last_block <= 0)
252 /* Default or Zero: pad to full block */
253 target_block_length = a->bytes_per_block;
255 /* Round length to next multiple of bytes_in_last_block. */
256 target_block_length = a->bytes_in_last_block *
257 ( (block_length + a->bytes_in_last_block - 1) /
258 a->bytes_in_last_block);
259 if (target_block_length > a->bytes_per_block)
260 target_block_length = a->bytes_per_block;
261 if (block_length < target_block_length) {
262 memset(state->stream.next_out, 0,
263 target_block_length - block_length);
264 block_length = target_block_length;
267 /* Write the last block */
268 bytes_written = (a->client_writer)(&a->archive, a->client_data,
269 state->compressed, block_length);
271 /* TODO: Handle short write of final block. */
272 if (bytes_written <= 0)
275 a->archive.raw_position += ret;
279 /* Cleanup: shut down compressor, release memory, etc. */
281 switch (BZ2_bzCompressEnd(&(state->stream))) {
285 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
286 "Failed to clean up compressor");
290 free(state->compressed);
296 * Utility function to push input data through compressor, writing
297 * full output blocks as necessary.
299 * Note that this handles both the regular write case (finishing ==
300 * false) and the end-of-archive case (finishing == true).
303 drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
305 ssize_t bytes_written;
309 if (state->stream.avail_out == 0) {
310 bytes_written = (a->client_writer)(&a->archive,
311 a->client_data, state->compressed,
312 state->compressed_buffer_size);
313 if (bytes_written <= 0) {
314 /* TODO: Handle this write failure */
315 return (ARCHIVE_FATAL);
316 } else if ((size_t)bytes_written < state->compressed_buffer_size) {
317 /* Short write: Move remainder to
318 * front and keep filling */
319 memmove(state->compressed,
320 state->compressed + bytes_written,
321 state->compressed_buffer_size - bytes_written);
324 a->archive.raw_position += bytes_written;
325 state->stream.next_out = state->compressed +
326 state->compressed_buffer_size - bytes_written;
327 state->stream.avail_out = bytes_written;
330 /* If there's nothing to do, we're done. */
331 if (!finishing && state->stream.avail_in == 0)
334 ret = BZ2_bzCompress(&(state->stream),
335 finishing ? BZ_FINISH : BZ_RUN);
339 /* In non-finishing case, did compressor
340 * consume everything? */
341 if (!finishing && state->stream.avail_in == 0)
344 case BZ_FINISH_OK: /* Finishing: There's more work to do */
346 case BZ_STREAM_END: /* Finishing: all done */
347 /* Only occurs in finishing case */
350 /* Any other return value indicates an error */
351 archive_set_error(&a->archive,
352 ARCHIVE_ERRNO_PROGRAMMER,
353 "Bzip2 compression failed;"
354 " BZ2_bzCompress() returned %d",
356 return (ARCHIVE_FATAL);
361 #endif /* HAVE_BZLIB_H */