/*
* Performs LZX 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
+unsigned
lzx_compress(const void *__uncompressed_data, unsigned uncompressed_len,
- void *compressed_data, unsigned *compressed_len_ret)
+ void *compressed_data)
{
struct output_bitstream ostream;
u8 uncompressed_data[uncompressed_len + 8];
int ret;
int block_type = LZX_BLOCKTYPE_ALIGNED;
+ wimlib_assert(uncompressed_len <= 32768);
+
if (uncompressed_len < 100)
- return 1;
+ return 0;
memset(&freq_tabs, 0, sizeof(freq_tabs));
queue.R0 = 1;
* main tree. */
ret = lzx_write_compressed_tree(&ostream, codes.main_lens,
LZX_NUM_CHARS);
- if (ret != 0)
- return ret;
+ if (ret)
+ return 0;
/* Write the pre-tree and symbols for the rest of the main tree. */
ret = lzx_write_compressed_tree(&ostream, codes.main_lens +
LZX_NUM_CHARS,
LZX_MAINTREE_NUM_SYMBOLS -
LZX_NUM_CHARS);
- if (ret != 0)
- return ret;
+ if (ret)
+ return 0;
/* Write the pre-tree and symbols for the length tree. */
ret = lzx_write_compressed_tree(&ostream, codes.len_lens,
LZX_LENTREE_NUM_SYMBOLS);
- if (ret != 0)
- return ret;
+ if (ret)
+ return 0;
/* Write the compressed literals. */
ret = lzx_write_compressed_literals(&ostream, block_type,
match_tab, num_matches, &codes);
- if (ret != 0)
- return ret;
+ if (ret)
+ return 0;
ret = flush_output_bitstream(&ostream);
- if (ret != 0)
- return ret;
+ if (ret)
+ return 0;
compressed_len = ostream.bit_output - (u8*)compressed_data;
- *compressed_len_ret = compressed_len;
-
#ifdef ENABLE_VERIFY_COMPRESSION
/* Verify that we really get the same thing back when decompressing. */
u8 buf[uncompressed_len];
}
}
#endif
- return 0;
+ return compressed_len;
}
/* Given the number of a LZX position slot, return the number of extra bits that
* are needed to encode the match offset. */
-static inline unsigned lzx_get_num_extra_bits(unsigned position_slot)
+static inline unsigned
+lzx_get_num_extra_bits(unsigned position_slot)
{
#ifdef USE_LZX_EXTRA_BITS_ARRAY
/* Use a table */
u32 R2;
};
-extern int lzx_decompress(const void *compressed_data, unsigned compressed_len,
- void *uncompressed_data, unsigned uncompressed_len);
+extern int
+lzx_decompress(const void *compressed_data, unsigned compressed_len,
+ void *uncompressed_data, unsigned uncompressed_len);
-extern int lzx_compress(const void *uncompressed_data, unsigned uncompressed_len,
- void *compressed_data, unsigned *compressed_len_ret);
+extern unsigned
+lzx_compress(const void *uncompressed_data, unsigned uncompressed_len,
+ void *compressed_data);
#endif /* _WIMLIB_LZX_H */
}
/*
- * Pointer to function to compresses a chunk of a WIM resource.
+ * compress_func_t- Pointer to a function to compresses a chunk
+ * of a WIM resource. This may be either xpress_compress()
+ * (xpress-compress.c) or lzx_compress() (lzx-compress.c).
*
- * @chunk: Uncompressed data of the chunk.
- * @chunk_size: Size of the uncompressed chunk in bytes.
- * @compressed_chunk: Pointer to output buffer of size at least
- * (@chunk_size - 1) bytes.
- * @compressed_chunk_len_ret: Pointer to an unsigned int into which the size
- * of the compressed chunk will be
- * returned.
+ * @chunk: Uncompressed data of the chunk.
+ * @chunk_size: Size of the uncompressed chunk, in bytes.
+ * @out: Pointer to output buffer of size at least (@chunk_size - 1) bytes.
+ *
+ * Returns the size of the compressed data written to @out in bytes, or 0 if the
+ * data could not be compressed to (@chunk_size - 1) bytes or fewer.
+ *
+ * As a special requirement, the compression code is optimized for the WIM
+ * format and therefore requires (@chunk_size <= 32768).
*
- * Returns zero if compressed succeeded, and nonzero if the chunk could not be
- * compressed to any smaller than @chunk_size. This function cannot fail for
- * any other reasons.
+ * As another special requirement, the compression code will read up to 8 bytes
+ * off the end of the @chunk array for performance reasons. The values of these
+ * bytes will not affect the output of the compression, but the calling code
+ * must make sure that the buffer holding the uncompressed chunk is actually at
+ * least (@chunk_size + 8) bytes, or at least that these extra bytes are in
+ * mapped memory that will not cause a memory access violation if accessed.
*/
-typedef int (*compress_func_t)(const void *, unsigned, void *, unsigned *);
+typedef unsigned (*compress_func_t)(const void *chunk, unsigned chunk_size,
+ void *out);
compress_func_t
get_compress_func(int out_ctype)
unsigned out_chunk_size;
if (chunk_tab) {
u8 *compressed_chunk = alloca(chunk_size);
- int ret;
- ret = compress(chunk, chunk_size, compressed_chunk,
- &out_chunk_size);
- if (ret == 0) {
+ out_chunk_size = compress(chunk, chunk_size, compressed_chunk);
+ if (out_chunk_size) {
+ /* Write compressed */
out_chunk = compressed_chunk;
} else {
+ /* Write uncompressed */
out_chunk = chunk;
out_chunk_size = chunk_size;
}
*chunk_tab->cur_offset_p++ = chunk_tab->cur_offset;
chunk_tab->cur_offset += out_chunk_size;
} else {
+ /* Write uncompressed */
out_chunk = chunk;
out_chunk_size = chunk_size;
}
{
for (unsigned i = 0; i < msg->num_chunks; i++) {
DEBUG2("compress chunk %u of %u", i, msg->num_chunks);
- int ret = compress(msg->uncompressed_chunks[i],
- msg->uncompressed_chunk_sizes[i],
- msg->compressed_chunks[i],
- &msg->compressed_chunk_sizes[i]);
- if (ret == 0) {
+ unsigned len = compress(msg->uncompressed_chunks[i],
+ msg->uncompressed_chunk_sizes[i],
+ msg->compressed_chunks[i]);
+ if (len) {
+ /* To be written compressed */
msg->out_compressed_chunks[i] = msg->compressed_chunks[i];
+ msg->compressed_chunk_sizes[i] = len;
} else {
+ /* To be written uncompressed */
msg->out_compressed_chunks[i] = msg->uncompressed_chunks[i];
msg->compressed_chunk_sizes[i] = msg->uncompressed_chunk_sizes[i];
+
}
}
}
/*
* 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
+unsigned
xpress_compress(const void *__uncompressed_data, unsigned uncompressed_len,
- void *__compressed_data, unsigned *compressed_len_ret)
+ void *__compressed_data)
{
const u8 *uncompressed_data = __uncompressed_data;
u8 *compressed_data = __compressed_data;
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.
* +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 1;
+ 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;
}
#define XPRESS_MIN_MATCH 3
#define XPRESS_MAX_MATCH 65538
-extern int xpress_decompress(const void *__compressed_data, unsigned compressed_len,
- void *__uncompressed_data, unsigned uncompressed_len);
+extern int
+xpress_decompress(const void *compressed_data, unsigned compressed_len,
+ void *uncompressed_data, unsigned uncompressed_len);
-extern int xpress_compress(const void *uncompressed_data, unsigned uncompressed_len,
- void *compressed_data, unsigned *compressed_len_ret);
+extern unsigned
+xpress_compress(const void *uncompressed_data, unsigned uncompressed_len,
+ void *compressed_data);
#endif /* _WIMLIB_XPRESS_H */