summaryrefslogtreecommitdiffstats
path: root/lib/libarchive/archive_write_set_compression_bzip2.c
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2009-04-17 00:42:45 +0000
committerkientzle <kientzle@FreeBSD.org>2009-04-17 00:42:45 +0000
commite0de5527ea12a738c8fdf4afc729b567136f0b3f (patch)
treec0500748e75cb0cbf40bc51246e3edb6e03f5b75 /lib/libarchive/archive_write_set_compression_bzip2.c
parente5db25af2500a5b85ad55c100e01bfa6a282cdcc (diff)
downloadFreeBSD-src-e0de5527ea12a738c8fdf4afc729b567136f0b3f.zip
FreeBSD-src-e0de5527ea12a738c8fdf4afc729b567136f0b3f.tar.gz
Merge from libarchive.googlecode.com: Numerous fixes to the
write options handling, including documentation.
Diffstat (limited to 'lib/libarchive/archive_write_set_compression_bzip2.c')
-rw-r--r--lib/libarchive/archive_write_set_compression_bzip2.c198
1 files changed, 123 insertions, 75 deletions
diff --git a/lib/libarchive/archive_write_set_compression_bzip2.c b/lib/libarchive/archive_write_set_compression_bzip2.c
index 592c526..ccf2229 100644
--- a/lib/libarchive/archive_write_set_compression_bzip2.c
+++ b/lib/libarchive/archive_write_set_compression_bzip2.c
@@ -47,9 +47,10 @@ __FBSDID("$FreeBSD$");
#ifndef HAVE_BZLIB_H
int
-archive_write_set_compression_bzip2(struct archive *_a)
+archive_write_set_compression_bzip2(struct archive *a)
{
- /* Unsupported bzip2 compression, we don't have bzlib */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "bzip2 compression not supported on this platform");
return (ARCHIVE_FATAL);
}
#else
@@ -62,6 +63,9 @@ struct private_data {
size_t compressed_buffer_size;
};
+struct private_config {
+ int compression_level;
+};
/*
* Yuck. bzlib.h is not const-correct, so I need this one bit
@@ -72,6 +76,8 @@ struct private_data {
static int archive_compressor_bzip2_finish(struct archive_write *);
static int archive_compressor_bzip2_init(struct archive_write *);
+static int archive_compressor_bzip2_options(struct archive_write *,
+ const char *, const char *);
static int archive_compressor_bzip2_write(struct archive_write *,
const void *, size_t);
static int drive_compressor(struct archive_write *, struct private_data *,
@@ -84,9 +90,21 @@ int
archive_write_set_compression_bzip2(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
+ struct private_config *config;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
+ config = malloc(sizeof(*config));
+ if (config == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ a->compressor.config = config;
+ a->compressor.finish = archive_compressor_bzip2_finish;
+ config->compression_level = 9; /* default */
a->compressor.init = &archive_compressor_bzip2_init;
+ a->compressor.options = &archive_compressor_bzip2_options;
+ a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
+ a->archive.compression_name = "bzip2";
return (ARCHIVE_OK);
}
@@ -98,10 +116,9 @@ archive_compressor_bzip2_init(struct archive_write *a)
{
int ret;
struct private_data *state;
+ struct private_config *config;
- a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
- a->archive.compression_name = "bzip2";
-
+ config = (struct private_config *)a->compressor.config;
if (a->client_opener != NULL) {
ret = (a->client_opener)(&a->archive, a->client_data);
if (ret != 0)
@@ -129,10 +146,10 @@ archive_compressor_bzip2_init(struct archive_write *a)
state->stream.next_out = state->compressed;
state->stream.avail_out = state->compressed_buffer_size;
a->compressor.write = archive_compressor_bzip2_write;
- a->compressor.finish = archive_compressor_bzip2_finish;
/* Initialize compression library */
- ret = BZ2_bzCompressInit(&(state->stream), 9, 0, 30);
+ ret = BZ2_bzCompressInit(&(state->stream),
+ config->compression_level, 0, 30);
if (ret == BZ_OK) {
a->compressor.data = state;
return (ARCHIVE_OK);
@@ -168,6 +185,32 @@ archive_compressor_bzip2_init(struct archive_write *a)
}
/*
+ * Set write options.
+ */
+static int
+archive_compressor_bzip2_options(struct archive_write *a, const char *key,
+ const char *value)
+{
+ struct private_config *config;
+
+ config = (struct private_config *)a->compressor.config;
+ if (strcmp(key, "compression-level") == 0) {
+ if (value == NULL || !(value[0] >= '0' && value[0] <= '9') ||
+ value[1] != '\0')
+ return (ARCHIVE_WARN);
+ config->compression_level = value[0] - '0';
+ /* Make '0' be a synonym for '1'. */
+ /* This way, bzip2 compressor supports the same 0..9
+ * range of levels as gzip. */
+ if (config->compression_level < 1)
+ config->compression_level = 1;
+ return (ARCHIVE_OK);
+ }
+
+ return (ARCHIVE_WARN);
+}
+
+/*
* Write data to the compressed stream.
*
* Returns ARCHIVE_OK if all data written, error otherwise.
@@ -212,83 +255,88 @@ archive_compressor_bzip2_finish(struct archive_write *a)
ssize_t bytes_written;
unsigned tocopy;
- state = (struct private_data *)a->compressor.data;
ret = ARCHIVE_OK;
- if (a->client_writer == NULL) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No write callback is registered?\n"
- "This is probably an internal programming error.");
- ret = ARCHIVE_FATAL;
- goto cleanup;
- }
+ state = (struct private_data *)a->compressor.data;
+ if (state != NULL) {
+ if (a->client_writer == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_PROGRAMMER,
+ "No write callback is registered?\n"
+ "This is probably an internal programming error.");
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
- /* By default, always pad the uncompressed data. */
- if (a->pad_uncompressed) {
- tocopy = a->bytes_per_block -
- (state->total_in % a->bytes_per_block);
- while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
- SET_NEXT_IN(state, a->nulls);
- state->stream.avail_in = tocopy < a->null_length ?
- tocopy : a->null_length;
- state->total_in += state->stream.avail_in;
- tocopy -= state->stream.avail_in;
- ret = drive_compressor(a, state, 0);
- if (ret != ARCHIVE_OK)
- goto cleanup;
+ /* By default, always pad the uncompressed data. */
+ if (a->pad_uncompressed) {
+ tocopy = a->bytes_per_block -
+ (state->total_in % a->bytes_per_block);
+ while (tocopy > 0 && tocopy < (unsigned)a->bytes_per_block) {
+ SET_NEXT_IN(state, a->nulls);
+ state->stream.avail_in = tocopy < a->null_length ?
+ tocopy : a->null_length;
+ state->total_in += state->stream.avail_in;
+ tocopy -= state->stream.avail_in;
+ ret = drive_compressor(a, state, 0);
+ if (ret != ARCHIVE_OK)
+ goto cleanup;
+ }
}
- }
- /* Finish compression cycle. */
- if ((ret = drive_compressor(a, state, 1)))
- goto cleanup;
-
- /* Optionally, pad the final compressed block. */
- block_length = state->stream.next_out - state->compressed;
-
-
- /* Tricky calculation to determine size of last block. */
- target_block_length = block_length;
- if (a->bytes_in_last_block <= 0)
- /* Default or Zero: pad to full block */
- target_block_length = a->bytes_per_block;
- else
- /* Round length to next multiple of bytes_in_last_block. */
- target_block_length = a->bytes_in_last_block *
- ( (block_length + a->bytes_in_last_block - 1) /
- a->bytes_in_last_block);
- if (target_block_length > a->bytes_per_block)
- target_block_length = a->bytes_per_block;
- if (block_length < target_block_length) {
- memset(state->stream.next_out, 0,
- target_block_length - block_length);
- block_length = target_block_length;
- }
+ /* Finish compression cycle. */
+ if ((ret = drive_compressor(a, state, 1)))
+ goto cleanup;
+
+ /* Optionally, pad the final compressed block. */
+ block_length = state->stream.next_out - state->compressed;
+
+ /* Tricky calculation to determine size of last block. */
+ target_block_length = block_length;
+ if (a->bytes_in_last_block <= 0)
+ /* Default or Zero: pad to full block */
+ target_block_length = a->bytes_per_block;
+ else
+ /* Round length to next multiple of bytes_in_last_block. */
+ target_block_length = a->bytes_in_last_block *
+ ( (block_length + a->bytes_in_last_block - 1) /
+ a->bytes_in_last_block);
+ if (target_block_length > a->bytes_per_block)
+ target_block_length = a->bytes_per_block;
+ if (block_length < target_block_length) {
+ memset(state->stream.next_out, 0,
+ target_block_length - block_length);
+ block_length = target_block_length;
+ }
- /* Write the last block */
- bytes_written = (a->client_writer)(&a->archive, a->client_data,
- state->compressed, block_length);
+ /* Write the last block */
+ bytes_written = (a->client_writer)(&a->archive, a->client_data,
+ state->compressed, block_length);
- /* TODO: Handle short write of final block. */
- if (bytes_written <= 0)
- ret = ARCHIVE_FATAL;
- else {
- a->archive.raw_position += ret;
- ret = ARCHIVE_OK;
- }
+ /* TODO: Handle short write of final block. */
+ if (bytes_written <= 0)
+ ret = ARCHIVE_FATAL;
+ else {
+ a->archive.raw_position += ret;
+ ret = ARCHIVE_OK;
+ }
- /* Cleanup: shut down compressor, release memory, etc. */
+ /* Cleanup: shut down compressor, release memory, etc. */
cleanup:
- switch (BZ2_bzCompressEnd(&(state->stream))) {
- case BZ_OK:
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "Failed to clean up compressor");
- ret = ARCHIVE_FATAL;
- }
+ switch (BZ2_bzCompressEnd(&(state->stream))) {
+ case BZ_OK:
+ break;
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+ "Failed to clean up compressor");
+ ret = ARCHIVE_FATAL;
+ }
- free(state->compressed);
- free(state);
+ free(state->compressed);
+ free(state);
+ }
+ /* Free configuration data even if we were never fully initialized. */
+ free(a->compressor.config);
+ a->compressor.config = NULL;
return (ret);
}
OpenPOWER on IntegriCloud