X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fxpress-compress.c;h=0957e27b960adaf82c45ff8a9156c689a2c29654;hp=77df527994483f7062bfadab49f14405456b74cd;hb=5caa3dfded8e0f590112b59feeb3b55e4fa28420;hpb=40beb80283a2df7af88c8359ca41adb814585e9a diff --git a/src/xpress-compress.c b/src/xpress-compress.c index 77df5279..0957e27b 100644 --- a/src/xpress-compress.c +++ b/src/xpress-compress.c @@ -7,7 +7,7 @@ */ /* - * Copyright (C) 2012 Eric Biggers + * Copyright (C) 2012, 2013 Eric Biggers * * This file is part of wimlib, a library for working with WIM files. * @@ -25,8 +25,17 @@ * along with wimlib; if not, see http://www.gnu.org/licenses/. */ -#include "xpress.h" -#include "compress.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "wimlib.h" +#include "wimlib/assert.h" +#include "wimlib/compress.h" +#include "wimlib/error.h" +#include "wimlib/util.h" +#include "wimlib/xpress.h" + #include #include @@ -36,8 +45,11 @@ * * @codewords and @lens provide the Huffman code that is being used. */ -static int xpress_write_match(struct output_bitstream *ostream, u32 match, - const u16 codewords[], const u8 lens[]) +static int +xpress_write_match(struct output_bitstream *restrict ostream, + u32 match, + const u16 codewords[restrict], + const u8 lens[restrict]) { u32 adjusted_match_len = match & 0xffff; u32 match_offset = match >> 16; @@ -47,17 +59,17 @@ static int xpress_write_match(struct output_bitstream *ostream, u32 match, int ret; ret = bitstream_put_bits(ostream, codewords[sym], lens[sym]); - if (ret != 0) + if (ret) return ret; if (adjusted_match_len >= 0xf) { u8 byte1 = min(adjusted_match_len - 0xf, 0xff); ret = bitstream_put_byte(ostream, byte1); - if (ret != 0) + if (ret) return ret; if (byte1 == 0xff) { ret = bitstream_put_two_bytes(ostream, adjusted_match_len); - if (ret != 0) + if (ret) return ret; } } @@ -65,11 +77,12 @@ static int xpress_write_match(struct output_bitstream *ostream, u32 match, match_offset ^ (1 << offset_bsr), offset_bsr); } -static int xpress_write_compressed_literals(struct output_bitstream *ostream, - const u32 match_tab[], - unsigned num_matches, - const u16 codewords[], - const u8 lens[]) +static int +xpress_write_compressed_literals(struct output_bitstream *ostream, + const u32 match_tab[restrict], + unsigned num_matches, + const u16 codewords[restrict], + const u8 lens[restrict]) { for (unsigned i = 0; i < num_matches; i++) { int ret; @@ -81,22 +94,24 @@ static int xpress_write_compressed_literals(struct output_bitstream *ostream, else /* literal byte */ ret = bitstream_put_bits(ostream, codewords[match], lens[match]); - if (ret != 0) + if (ret) return ret; } return bitstream_put_bits(ostream, codewords[XPRESS_END_OF_DATA], lens[XPRESS_END_OF_DATA]); } -static u32 xpress_record_literal(u8 literal, void *__freq_tab) +static u32 +xpress_record_literal(u8 literal, void *_freq_tab) { - u32 *freq_tab = __freq_tab; + freq_t *freq_tab = _freq_tab; freq_tab[literal]++; return literal; } -static u32 xpress_record_match(unsigned match_offset, unsigned match_len, - void *freq_tab, void *ignore) +static u32 +xpress_record_match(unsigned match_offset, unsigned match_len, + void *freq_tab, void *_ignore) { wimlib_assert(match_len >= XPRESS_MIN_MATCH && match_len <= XPRESS_MAX_MATCH); @@ -121,7 +136,7 @@ static u32 xpress_record_match(unsigned match_offset, unsigned match_len, u32 len_hdr = min(adjusted_match_len, 0xf); u32 offset_bsr = bsr32(match_offset); u32 sym = len_hdr | (offset_bsr << 4) | XPRESS_NUM_CHARS; - ((u32*)freq_tab)[sym]++; + ((freq_t*)freq_tab)[sym]++; return adjusted_match_len | (match_offset << 16); } @@ -135,43 +150,40 @@ static const struct lz_params xpress_lz_params = { .too_far = 4096, }; -/* - * Performs XPRESS compression on a block of data. - * - * @__uncompressed_data: Pointer to the data to be compressed. - * @uncompressed_len: Length, in bytes, of the data to be compressed. - * @__compressed_data: Pointer to a location at least (@uncompressed_len - 1) - * bytes long into which the compressed data may be - * written. - * @compressed_len_ret: A pointer to an unsigned int into which the length of - * the compressed data may be returned. - * - * Returns zero if compression was successfully performed. In that case - * @compressed_data and @compressed_len_ret will contain the compressed data and - * its length. A return value of nonzero means that compressing the data did - * not reduce its size, and @compressed_data will not contain the full - * compressed data. - */ -int xpress_compress(const void *__uncompressed_data, unsigned uncompressed_len, - void *__compressed_data, unsigned *compressed_len_ret) +/* Documented in wimlib.h */ +WIMLIBAPI unsigned +wimlib_xpress_compress(const void * restrict _uncompressed_data, + unsigned uncompressed_len, + void * restrict _compressed_data) { - const u8 *uncompressed_data = __uncompressed_data; - u8 *compressed_data = __compressed_data; + u8 *compressed_data = _compressed_data; struct output_bitstream ostream; u32 match_tab[uncompressed_len]; - u32 freq_tab[XPRESS_NUM_SYMBOLS]; + freq_t freq_tab[XPRESS_NUM_SYMBOLS]; u16 codewords[XPRESS_NUM_SYMBOLS]; u8 lens[XPRESS_NUM_SYMBOLS]; unsigned num_matches; unsigned compressed_len; unsigned i; int ret; + u8 uncompressed_data[uncompressed_len + 8]; + + memcpy(uncompressed_data, _uncompressed_data, uncompressed_len); + memset(uncompressed_data + uncompressed_len, 0, 8); + + wimlib_assert(uncompressed_len <= 32768); /* XPRESS requires 256 bytes of overhead for the Huffman tables, so it's * impossible cannot compress 256 bytes or less of data to less than the - * input size. */ - if (uncompressed_len <= XPRESS_NUM_SYMBOLS / 2) - return 1; + * input size. + * + * +1 to take into account that the buffer for compressed data is 1 byte + * smaller than the buffer for uncompressed data. + * + * +4 to take into account that init_output_bitstream() requires at + * least 4 bytes of data. */ + if (uncompressed_len < XPRESS_NUM_SYMBOLS / 2 + 1 + 4) + return 0; ZERO_ARRAY(freq_tab); num_matches = lz_analyze_block(uncompressed_data, uncompressed_len, @@ -205,13 +217,13 @@ int xpress_compress(const void *__uncompressed_data, unsigned uncompressed_len, ret = xpress_write_compressed_literals(&ostream, match_tab, num_matches, codewords, lens); - if (ret != 0) - return ret; + if (ret) + return 0; /* Flush any bits that are buffered. */ ret = flush_output_bitstream(&ostream); - if (ret != 0) - return ret; + if (ret) + return 0; /* Assert that there are no output bytes between the ostream.output * pointer and the ostream.next_bit_output pointer. This can only @@ -230,33 +242,33 @@ int xpress_compress(const void *__uncompressed_data, unsigned uncompressed_len, * the compressed data, in which case they are actually unnecessary, or * they may precede a number of bytes embedded into the bitstream.) */ if (ostream.bit_output > - (const u8*)__compressed_data + uncompressed_len - 3) - return 1; + (const u8*)_compressed_data + uncompressed_len - 3) + return 0; *(u16*)ostream.bit_output = cpu_to_le16(0); - compressed_len = ostream.next_bit_output - (const u8*)__compressed_data; + compressed_len = ostream.next_bit_output - (const u8*)_compressed_data; wimlib_assert(compressed_len <= uncompressed_len - 1); - *compressed_len_ret = compressed_len; - #ifdef ENABLE_VERIFY_COMPRESSION /* Verify that we really get the same thing back when decompressing. */ - u8 buf[uncompressed_len]; - ret = xpress_decompress(__compressed_data, compressed_len, buf, - uncompressed_len); - if (ret != 0) { - ERROR("xpress_compress(): Failed to decompress data we " - "compressed"); - abort(); - } - for (i = 0; i < uncompressed_len; i++) { - if (buf[i] != uncompressed_data[i]) { - ERROR("xpress_compress(): Data we compressed didn't " - "decompress to the original data (difference at " - "byte %u of %u)", i + 1, uncompressed_len); + { + u8 buf[uncompressed_len]; + ret = wimlib_xpress_decompress(_compressed_data, compressed_len, + buf, uncompressed_len); + if (ret) { + ERROR("xpress_compress(): Failed to decompress data we " + "compressed"); abort(); } + for (i = 0; i < uncompressed_len; i++) { + if (buf[i] != uncompressed_data[i]) { + ERROR("xpress_compress(): Data we compressed didn't " + "decompress to the original data (difference at " + "byte %u of %u)", i + 1, uncompressed_len); + abort(); + } + } } #endif - return 0; + return compressed_len; }