2 * Copyright (c) 2009 Michihiro NAKAJIMA
3 * Copyright (c) 2003-2007 Tim Kientzle
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "archive_platform.h"
29 __FBSDID("$FreeBSD$");
46 #include "archive_private.h"
47 #include "archive_write_private.h"
51 archive_write_set_compression_xz(struct archive *a)
53 archive_set_error(a, ARCHIVE_ERRNO_MISC,
54 "xz compression not supported on this platform");
55 return (ARCHIVE_FATAL);
59 archive_write_set_compression_lzma(struct archive *a)
61 archive_set_error(a, ARCHIVE_ERRNO_MISC,
62 "lzma compression not supported on this platform");
63 return (ARCHIVE_FATAL);
66 /* Don't compile this if we don't have liblzma. */
70 lzma_filter lzmafilters[2];
71 lzma_options_lzma lzma_opt;
73 unsigned char *compressed;
74 size_t compressed_buffer_size;
77 struct private_config {
78 int compression_level;
81 static int archive_compressor_xz_init(struct archive_write *);
82 static int archive_compressor_xz_options(struct archive_write *,
83 const char *, const char *);
84 static int archive_compressor_xz_finish(struct archive_write *);
85 static int archive_compressor_xz_write(struct archive_write *,
86 const void *, size_t);
87 static int drive_compressor(struct archive_write *, struct private_data *,
92 * Allocate, initialize and return a archive object.
95 archive_write_set_compression_xz(struct archive *_a)
97 struct private_config *config;
98 struct archive_write *a = (struct archive_write *)_a;
99 __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
100 ARCHIVE_STATE_NEW, "archive_write_set_compression_xz");
101 config = calloc(1, sizeof(*config));
102 if (config == NULL) {
103 archive_set_error(&a->archive, ENOMEM, "Out of memory");
104 return (ARCHIVE_FATAL);
106 a->compressor.config = config;
107 a->compressor.finish = archive_compressor_xz_finish;
108 config->compression_level = LZMA_PRESET_DEFAULT;
109 a->compressor.init = &archive_compressor_xz_init;
110 a->compressor.options = &archive_compressor_xz_options;
111 a->archive.compression_code = ARCHIVE_COMPRESSION_XZ;
112 a->archive.compression_name = "xz";
116 /* LZMA is handled identically, we just need a different compression
117 * code set. (The liblzma setup looks at the code to determine
118 * the one place that XZ and LZMA require different handling.) */
120 archive_write_set_compression_lzma(struct archive *_a)
122 struct archive_write *a = (struct archive_write *)_a;
123 int r = archive_write_set_compression_xz(_a);
126 a->archive.compression_code = ARCHIVE_COMPRESSION_LZMA;
127 a->archive.compression_name = "lzma";
132 archive_compressor_xz_init_stream(struct archive_write *a,
133 struct private_data *state)
135 static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT;
138 state->stream = lzma_stream_init_data;
139 state->stream.next_out = state->compressed;
140 state->stream.avail_out = state->compressed_buffer_size;
141 if (a->archive.compression_code == ARCHIVE_COMPRESSION_XZ)
142 ret = lzma_stream_encoder(&(state->stream),
143 state->lzmafilters, LZMA_CHECK_CRC64);
145 ret = lzma_alone_encoder(&(state->stream), &state->lzma_opt);
151 archive_set_error(&a->archive, ENOMEM,
152 "Internal error initializing compression library: "
153 "Cannot allocate memory");
156 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
157 "Internal error initializing compression library: "
158 "It's a bug in liblzma");
161 return (ARCHIVE_FATAL);
168 archive_compressor_xz_init(struct archive_write *a)
171 struct private_data *state;
172 struct private_config *config;
174 if (a->client_opener != NULL) {
175 ret = (a->client_opener)(&a->archive, a->client_data);
176 if (ret != ARCHIVE_OK)
180 state = (struct private_data *)malloc(sizeof(*state));
182 archive_set_error(&a->archive, ENOMEM,
183 "Can't allocate data for compression");
184 return (ARCHIVE_FATAL);
186 memset(state, 0, sizeof(*state));
187 config = a->compressor.config;
190 * See comment above. We should set compressed_buffer_size to
191 * max(bytes_per_block, 65536), but the code can't handle that yet.
193 state->compressed_buffer_size = a->bytes_per_block;
194 state->compressed = (unsigned char *)malloc(state->compressed_buffer_size);
195 if (state->compressed == NULL) {
196 archive_set_error(&a->archive, ENOMEM,
197 "Can't allocate data for compression buffer");
199 return (ARCHIVE_FATAL);
201 a->compressor.write = archive_compressor_xz_write;
203 /* Initialize compression library. */
204 if (lzma_lzma_preset(&state->lzma_opt, config->compression_level)) {
205 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
206 "Internal error initializing compression library");
207 free(state->compressed);
210 state->lzmafilters[0].id = LZMA_FILTER_LZMA2;
211 state->lzmafilters[0].options = &state->lzma_opt;
212 state->lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
213 ret = archive_compressor_xz_init_stream(a, state);
214 if (ret == LZMA_OK) {
215 a->compressor.data = state;
218 /* Library setup failed: clean up. */
219 free(state->compressed);
222 return (ARCHIVE_FATAL);
229 archive_compressor_xz_options(struct archive_write *a, const char *key,
232 struct private_config *config;
234 config = (struct private_config *)a->compressor.config;
235 if (strcmp(key, "compression-level") == 0) {
236 if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
238 return (ARCHIVE_WARN);
239 config->compression_level = value[0] - '0';
240 if (config->compression_level > 6)
241 config->compression_level = 6;
245 return (ARCHIVE_WARN);
249 * Write data to the compressed stream.
252 archive_compressor_xz_write(struct archive_write *a, const void *buff,
255 struct private_data *state;
258 state = (struct private_data *)a->compressor.data;
259 if (a->client_writer == NULL) {
260 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
261 "No write callback is registered? "
262 "This is probably an internal programming error.");
263 return (ARCHIVE_FATAL);
266 /* Update statistics */
267 state->total_in += length;
269 /* Compress input data to output buffer */
270 state->stream.next_in = buff;
271 state->stream.avail_in = length;
272 if ((ret = drive_compressor(a, state, 0)) != ARCHIVE_OK)
275 a->archive.file_position += length;
281 * Finish the compression...
284 archive_compressor_xz_finish(struct archive_write *a)
286 ssize_t block_length, target_block_length, bytes_written;
288 struct private_data *state;
292 state = (struct private_data *)a->compressor.data;
294 if (a->client_writer == NULL) {
295 archive_set_error(&a->archive,
296 ARCHIVE_ERRNO_PROGRAMMER,
297 "No write callback is registered? "
298 "This is probably an internal programming error.");
303 /* By default, always pad the uncompressed data. */
304 if (a->pad_uncompressed) {
305 tocopy = a->bytes_per_block -
306 (state->total_in % a->bytes_per_block);
307 while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
308 state->stream.next_in = a->nulls;
309 state->stream.avail_in = tocopy < a->null_length ?
310 tocopy : a->null_length;
311 state->total_in += state->stream.avail_in;
312 tocopy -= state->stream.avail_in;
313 ret = drive_compressor(a, state, 0);
314 if (ret != ARCHIVE_OK)
319 /* Finish compression cycle */
320 if (((ret = drive_compressor(a, state, 1))) != ARCHIVE_OK)
323 /* Optionally, pad the final compressed block. */
324 block_length = state->stream.next_out - state->compressed;
326 /* Tricky calculation to determine size of last block. */
327 if (a->bytes_in_last_block <= 0)
328 /* Default or Zero: pad to full block */
329 target_block_length = a->bytes_per_block;
331 /* Round length to next multiple of bytes_in_last_block. */
332 target_block_length = a->bytes_in_last_block *
333 ( (block_length + a->bytes_in_last_block - 1) /
334 a->bytes_in_last_block);
335 if (target_block_length > a->bytes_per_block)
336 target_block_length = a->bytes_per_block;
337 if (block_length < target_block_length) {
338 memset(state->stream.next_out, 0,
339 target_block_length - block_length);
340 block_length = target_block_length;
343 /* Write the last block */
344 bytes_written = (a->client_writer)(&a->archive, a->client_data,
345 state->compressed, block_length);
346 if (bytes_written <= 0) {
350 a->archive.raw_position += bytes_written;
352 /* Cleanup: shut down compressor, release memory, etc. */
354 lzma_end(&(state->stream));
355 free(state->compressed);
358 free(a->compressor.config);
359 a->compressor.config = NULL;
364 * Utility function to push input data through compressor,
365 * writing full output blocks as necessary.
367 * Note that this handles both the regular write case (finishing ==
368 * false) and the end-of-archive case (finishing == true).
371 drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
373 ssize_t bytes_written;
377 if (state->stream.avail_out == 0) {
378 bytes_written = (a->client_writer)(&a->archive,
379 a->client_data, state->compressed,
380 state->compressed_buffer_size);
381 if (bytes_written <= 0) {
382 /* TODO: Handle this write failure */
383 return (ARCHIVE_FATAL);
384 } else if ((size_t)bytes_written < state->compressed_buffer_size) {
385 /* Short write: Move remaining to
386 * front of block and keep filling */
387 memmove(state->compressed,
388 state->compressed + bytes_written,
389 state->compressed_buffer_size - bytes_written);
391 a->archive.raw_position += bytes_written;
392 state->stream.next_out
393 = state->compressed +
394 state->compressed_buffer_size - bytes_written;
395 state->stream.avail_out = bytes_written;
398 /* If there's nothing to do, we're done. */
399 if (!finishing && state->stream.avail_in == 0)
402 ret = lzma_code(&(state->stream),
403 finishing ? LZMA_FINISH : LZMA_RUN );
407 /* In non-finishing case, check if compressor
408 * consumed everything */
409 if (!finishing && state->stream.avail_in == 0)
411 /* In finishing case, this return always means
412 * there's more work */
414 case LZMA_STREAM_END:
415 /* This return can only occur in finishing case. */
418 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
419 "lzma compression data error");
420 return (ARCHIVE_FATAL);
421 case LZMA_MEMLIMIT_ERROR:
422 archive_set_error(&a->archive, ENOMEM,
423 "lzma compression error: "
424 "%ju MiB would have been needed",
425 (uintmax_t)((lzma_memusage(&(state->stream)) + 1024 * 1024 -1)
427 return (ARCHIVE_FATAL);
429 /* Any other return value indicates an error. */
430 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
431 "lzma compression failed:"
432 " lzma_code() call returned status %d",
434 return (ARCHIVE_FATAL);
439 #endif /* HAVE_LZMA_H */