*/
/*
- * Copyright (C) 2012 Eric Biggers
+ * Copyright (C) 2012, 2013 Eric Biggers
*
* This file is part of wimlib, a library for working with WIM files.
*
*
* @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 *ostream, u32 match,
+ const u16 codewords[], const u8 lens[])
{
u32 adjusted_match_len = match & 0xffff;
u32 match_offset = match >> 16;
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[],
+ unsigned num_matches,
+ const u16 codewords[],
+ const u8 lens[])
{
for (unsigned i = 0; i < num_matches; i++) {
int ret;
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);
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);
}
/*
* 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.
+ * Please see the documentation for the 'compress_func_t' type in write.c for
+ * the exact behavior of this function and how to call it.
*/
-int xpress_compress(const void *__uncompressed_data, unsigned uncompressed_len,
- void *__compressed_data, unsigned *compressed_len_ret)
+unsigned
+xpress_compress(const void *__uncompressed_data, unsigned uncompressed_len,
+ void *__compressed_data)
{
const u8 *uncompressed_data = __uncompressed_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 i;
int ret;
+ 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,
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
* they may precede a number of bytes embedded into the bitstream.) */
if (ostream.bit_output >
(const u8*)__compressed_data + uncompressed_len - 3)
- return 1;
+ return 0;
*(u16*)ostream.bit_output = cpu_to_le16(0);
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) {
+ if (ret) {
ERROR("xpress_compress(): Failed to decompress data we "
"compressed");
abort();
}
}
#endif
- return 0;
+ return compressed_len;
}