X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fxpress-decompress.c;h=bf42c1f0a69883845dab935c929b4ea7b3a80dfc;hb=f217a34cf5fecfd91b10395f9165a7ae9570c4aa;hp=f08cccbb4b405372b4a4bbb15018973ed7337875;hpb=e176e9731e696562bab8de7b9bd34c019deef3e8;p=wimlib diff --git a/src/xpress-decompress.c b/src/xpress-decompress.c index f08cccbb..bf42c1f0 100644 --- a/src/xpress-decompress.c +++ b/src/xpress-decompress.c @@ -1,7 +1,7 @@ /* * xpress-decompress.c * - * XPRESS decompression routines. + * A very fast decompressor for XPRESS (Huffman version). */ /* @@ -69,139 +69,70 @@ # include "config.h" #endif -#include "wimlib.h" -#include "wimlib/decompress.h" +#include "wimlib/decompressor_ops.h" +#include "wimlib/decompress_common.h" +#include "wimlib/error.h" #include "wimlib/xpress.h" -/* - * Decodes a symbol @sym that begins an XPRESS match. - * - * The low 8 bits of the symbol are divided into: - * - * bits 0-3: length header - * bits 4-7: index of high-order bit of match offset - * - * Returns the match length, or -1 if the data is invalid. - */ +/* This value is chosen for fast decompression. */ +#define XPRESS_TABLEBITS 12 + +/* Decode the matches and literal bytes in a region of XPRESS-encoded data. */ static int -xpress_decode_match(unsigned sym, input_idx_t window_pos, - input_idx_t window_len, u8 window[restrict], - struct input_bitstream * restrict istream) +xpress_decode_window(struct input_bitstream *istream, const u16 *decode_table, + u8 *window, unsigned window_size) { - - u8 len_hdr; - u8 offset_bsr; - int ret; - u8 *match_dest; - u8 *match_src; - unsigned i; + u8 *window_ptr = window; + u8 *window_end = &window[window_size]; + unsigned sym; unsigned match_len; + unsigned offset_bsr; unsigned match_offset; - sym -= XPRESS_NUM_CHARS; - len_hdr = sym & 0xf; - offset_bsr = sym >> 4; + while (window_ptr != window_end) { - if (bitstream_ensure_bits(istream, 16)) - return -1; - - match_offset = (1U << offset_bsr) | bitstream_pop_bits(istream, offset_bsr); - - if (len_hdr == 0xf) { - ret = bitstream_read_byte(istream); - if (ret < 0) - return ret; - match_len = ret; - if (unlikely(match_len == 0xff)) { - ret = bitstream_read_byte(istream); - if (ret < 0) - return ret; - match_len = ret; - - ret = bitstream_read_byte(istream); - if (ret < 0) - return ret; - - match_len |= (ret << 8); - } else { - match_len += 0xf; + sym = read_huffsym(istream, decode_table, + XPRESS_TABLEBITS, XPRESS_MAX_CODEWORD_LEN); + if (sym < XPRESS_NUM_CHARS) { + /* Literal */ + *window_ptr++ = sym; + continue; } - } else { - match_len = len_hdr; - } - match_len += XPRESS_MIN_MATCH_LEN; + /* Match */ + match_len = sym & 0xf; + offset_bsr = (sym >> 4) & 0xf; - /* Verify the match is in bounds, then copy its data to the the current - * position. */ + bitstream_ensure_bits(istream, 16); - if (window_pos + match_len > window_len) - return -1; - - if (match_offset > window_pos) - return -1; - - match_dest = window + window_pos; - match_src = match_dest - match_offset; - - for (i = 0; i < match_len; i++) - match_dest[i] = match_src[i]; - - return match_len; -} + match_offset = (1 << offset_bsr) | + bitstream_pop_bits(istream, offset_bsr); -/* Decodes the Huffman-encoded matches and literal bytes in a region of - * XPRESS-encoded data. */ -static int -xpress_lz_decode(struct input_bitstream * restrict istream, - u8 uncompressed_data[restrict], - unsigned uncompressed_len, - const u8 lens[restrict], - const u16 decode_table[restrict]) -{ - input_idx_t curpos; - unsigned match_len; - - for (curpos = 0; curpos < uncompressed_len; curpos += match_len) { - unsigned sym; - int ret; + if (match_len == 0xf) { + match_len += bitstream_read_byte(istream); + if (match_len == 0xf + 0xff) + match_len = bitstream_read_u16(istream); + } + match_len += XPRESS_MIN_MATCH_LEN; - if (unlikely(bitstream_ensure_bits(istream, 16))) + if (unlikely(match_offset > window_ptr - window)) return -1; - if (unlikely(read_huffsym(istream, decode_table, lens, - XPRESS_NUM_SYMBOLS, XPRESS_TABLEBITS, - &sym, XPRESS_MAX_CODEWORD_LEN))) + if (unlikely(match_len > window_end - window_ptr)) return -1; - if (sym < XPRESS_NUM_CHARS) { - /* Literal */ - uncompressed_data[curpos] = sym; - match_len = 1; - } else { - /* Match */ - ret = xpress_decode_match(sym, - curpos, - uncompressed_len, - uncompressed_data, - istream); - if (unlikely(ret < 0)) - return -1; - match_len = ret; - } + lz_copy(window_ptr, match_len, match_offset, window_end); + + window_ptr += match_len; } return 0; } - -/* API function documented in wimlib.h */ -WIMLIBAPI int -wimlib_xpress_decompress(const void * const restrict _compressed_data, - const unsigned compressed_len, - void * const restrict uncompressed_data, - const unsigned uncompressed_len) +static int +xpress_decompress(const void *compressed_data, size_t compressed_size, + void *uncompressed_data, size_t uncompressed_size, void *_ctx) { - const u8 *compressed_data = _compressed_data; + const u8 *cdata = compressed_data; u8 lens[XPRESS_NUM_SYMBOLS]; u8 *lens_p; u16 decode_table[(1 << XPRESS_TABLEBITS) + 2 * XPRESS_NUM_SYMBOLS] @@ -211,13 +142,13 @@ wimlib_xpress_decompress(const void * const restrict _compressed_data, /* XPRESS uses only one Huffman code. It contains 512 symbols, and the * code lengths of these symbols are given literally as 4-bit integers * in the first 256 bytes of the compressed data. */ - if (compressed_len < XPRESS_NUM_SYMBOLS / 2) + if (compressed_size < XPRESS_NUM_SYMBOLS / 2) return -1; lens_p = lens; for (unsigned i = 0; i < XPRESS_NUM_SYMBOLS / 2; i++) { - *lens_p++ = compressed_data[i] & 0xf; - *lens_p++ = compressed_data[i] >> 4; + *lens_p++ = cdata[i] & 0xf; + *lens_p++ = cdata[i] >> 4; } if (make_huffman_decode_table(decode_table, XPRESS_NUM_SYMBOLS, @@ -225,9 +156,23 @@ wimlib_xpress_decompress(const void * const restrict _compressed_data, XPRESS_MAX_CODEWORD_LEN)) return -1; - init_input_bitstream(&istream, compressed_data + XPRESS_NUM_SYMBOLS / 2, - compressed_len - XPRESS_NUM_SYMBOLS / 2); + init_input_bitstream(&istream, cdata + XPRESS_NUM_SYMBOLS / 2, + compressed_size - XPRESS_NUM_SYMBOLS / 2); - return xpress_lz_decode(&istream, uncompressed_data, - uncompressed_len, lens, decode_table); + return xpress_decode_window(&istream, decode_table, + uncompressed_data, uncompressed_size); } + +static int +xpress_create_decompressor(size_t max_block_size, void **dec_ret) +{ + if (max_block_size > XPRESS_MAX_OFFSET + 1) + return WIMLIB_ERR_INVALID_PARAM; + + return 0; +} + +const struct decompressor_ops xpress_decompressor_ops = { + .create_decompressor = xpress_create_decompressor, + .decompress = xpress_decompress, +};