X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fxpress_decompress.c;h=9fd5ac5eb045512b67c31831ae5499aa7ee3626e;hp=2951be1bc8280db3040a3bf04dc44cb38f8061d8;hb=908381d2809a48acd9490ec080e51087ae1529fd;hpb=40a690416a3951361ec77d33a723dd4497fb7585 diff --git a/src/xpress_decompress.c b/src/xpress_decompress.c index 2951be1b..9fd5ac5e 100644 --- a/src/xpress_decompress.c +++ b/src/xpress_decompress.c @@ -6,7 +6,7 @@ /* * - * Copyright (C) 2012, 2013 Eric Biggers + * Copyright (C) 2012-2016 Eric Biggers * * This file is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free @@ -73,95 +73,86 @@ #include "wimlib/xpress_constants.h" /* This value is chosen for fast decompression. */ -#define XPRESS_TABLEBITS 12 +#define XPRESS_TABLEBITS 11 -/* Decode the matches and literal bytes in a region of XPRESS-encoded data. */ static int -xpress_decode_window(struct input_bitstream *istream, const u16 *decode_table, - u8 *window, unsigned window_size) +xpress_decompress(const void *restrict compressed_data, size_t compressed_size, + void *restrict uncompressed_data, size_t uncompressed_size, + void *restrict _ctx) { - u8 *window_ptr = window; - u8 *window_end = &window[window_size]; - unsigned sym; - unsigned match_len; - unsigned offset_high_bit; - unsigned match_offset; + const u8 * const in_begin = compressed_data; + u8 * const out_begin = uncompressed_data; + u8 *out_next = out_begin; + u8 * const out_end = out_begin + uncompressed_size; + union { + DECODE_TABLE(decode_table, XPRESS_NUM_SYMBOLS, + XPRESS_TABLEBITS, XPRESS_MAX_CODEWORD_LEN); + u8 lens[XPRESS_NUM_SYMBOLS]; + } u; + struct input_bitstream is; + + /* Read the Huffman codeword lengths. */ + if (compressed_size < XPRESS_NUM_SYMBOLS / 2) + return -1; + for (int i = 0; i < XPRESS_NUM_SYMBOLS / 2; i++) { + u.lens[2 * i + 0] = in_begin[i] & 0xf; + u.lens[2 * i + 1] = in_begin[i] >> 4; + } + + /* Build a decoding table for the Huffman code. */ + if (make_huffman_decode_table(u.decode_table, XPRESS_NUM_SYMBOLS, + XPRESS_TABLEBITS, u.lens, + XPRESS_MAX_CODEWORD_LEN)) + return -1; + + /* Decode the matches and literals. */ - while (window_ptr != window_end) { + init_input_bitstream(&is, in_begin + XPRESS_NUM_SYMBOLS / 2, + compressed_size - XPRESS_NUM_SYMBOLS / 2); + + while (out_next != out_end) { + unsigned sym; + unsigned log2_offset; + u32 length; + u32 offset; - sym = read_huffsym(istream, decode_table, + sym = read_huffsym(&is, u.decode_table, XPRESS_TABLEBITS, XPRESS_MAX_CODEWORD_LEN); if (sym < XPRESS_NUM_CHARS) { /* Literal */ - *window_ptr++ = sym; - continue; - } + *out_next++ = sym; + } else { + /* Match */ + length = sym & 0xf; + log2_offset = (sym >> 4) & 0xf; - /* Match */ - match_len = sym & 0xf; - offset_high_bit = (sym >> 4) & 0xf; + bitstream_ensure_bits(&is, 16); - bitstream_ensure_bits(istream, 16); + offset = ((u32)1 << log2_offset) | + bitstream_pop_bits(&is, log2_offset); - match_offset = (1 << offset_high_bit) | - bitstream_pop_bits(istream, offset_high_bit); + if (length == 0xf) { + length += bitstream_read_byte(&is); + if (length == 0xf + 0xff) + length = bitstream_read_u16(&is); + } + length += XPRESS_MIN_MATCH_LEN; - 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(offset > out_next - out_begin)) + return -1; - if (unlikely(match_offset > window_ptr - window)) - return -1; + if (unlikely(length > out_end - out_next)) + return -1; - if (unlikely(match_len > window_end - window_ptr)) - return -1; + lz_copy(out_next, length, offset, out_end, + XPRESS_MIN_MATCH_LEN); - lz_copy(window_ptr, match_len, match_offset, window_end, - XPRESS_MIN_MATCH_LEN); - - window_ptr += match_len; + out_next += length; + } } return 0; } -static int -xpress_decompress(const void *compressed_data, size_t compressed_size, - void *uncompressed_data, size_t uncompressed_size, void *_ctx) -{ - const u8 *cdata = compressed_data; - u8 lens[XPRESS_NUM_SYMBOLS]; - u8 *lens_p; - u16 decode_table[(1 << XPRESS_TABLEBITS) + 2 * XPRESS_NUM_SYMBOLS] - _aligned_attribute(DECODE_TABLE_ALIGNMENT); - struct input_bitstream istream; - - /* 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_size < XPRESS_NUM_SYMBOLS / 2) - return -1; - - lens_p = lens; - for (unsigned i = 0; i < XPRESS_NUM_SYMBOLS / 2; i++) { - *lens_p++ = cdata[i] & 0xf; - *lens_p++ = cdata[i] >> 4; - } - - if (make_huffman_decode_table(decode_table, XPRESS_NUM_SYMBOLS, - XPRESS_TABLEBITS, lens, - XPRESS_MAX_CODEWORD_LEN)) - return -1; - - init_input_bitstream(&istream, cdata + XPRESS_NUM_SYMBOLS / 2, - compressed_size - XPRESS_NUM_SYMBOLS / 2); - - return xpress_decode_window(&istream, decode_table, - uncompressed_data, uncompressed_size); -} - static int xpress_create_decompressor(size_t max_block_size, void **dec_ret) {