X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Flzx-decompress.c;h=d25d188b08b1e8fa6320f17b47127fa617d5198c;hp=2b3c0f903149f73965fadfb47dd3457d1d057b70;hb=71abd45bcc85ddb5cf60aba8bbeb53b40780f521;hpb=1530b6dab02a9e1e5faf81529ab502aee68d8cd2 diff --git a/src/lzx-decompress.c b/src/lzx-decompress.c index 2b3c0f90..d25d188b 100644 --- a/src/lzx-decompress.c +++ b/src/lzx-decompress.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. * @@ -106,36 +106,46 @@ * succeed. */ -#include "util.h" -#include "lzx.h" -#include "decompress.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "wimlib.h" +#include "wimlib/decompress.h" +#include "wimlib/lzx.h" +#include "wimlib/util.h" + #include /* Huffman decoding tables and maps from symbols to code lengths. */ struct lzx_tables { u16 maintree_decode_table[(1 << LZX_MAINTREE_TABLEBITS) + - (LZX_MAINTREE_NUM_SYMBOLS * 2)]; + (LZX_MAINTREE_NUM_SYMBOLS * 2)] + _aligned_attribute(DECODE_TABLE_ALIGNMENT); u8 maintree_lens[LZX_MAINTREE_NUM_SYMBOLS]; u16 lentree_decode_table[(1 << LZX_LENTREE_TABLEBITS) + - (LZX_LENTREE_NUM_SYMBOLS * 2)]; + (LZX_LENTREE_NUM_SYMBOLS * 2)] + _aligned_attribute(DECODE_TABLE_ALIGNMENT); u8 lentree_lens[LZX_LENTREE_NUM_SYMBOLS]; u16 alignedtree_decode_table[(1 << LZX_ALIGNEDTREE_TABLEBITS) + - (LZX_ALIGNEDTREE_NUM_SYMBOLS * 2)]; + (LZX_ALIGNEDTREE_NUM_SYMBOLS * 2)] + _aligned_attribute(DECODE_TABLE_ALIGNMENT); u8 alignedtree_lens[LZX_ALIGNEDTREE_NUM_SYMBOLS]; -}; +} _aligned_attribute(DECODE_TABLE_ALIGNMENT); /* * Reads a Huffman-encoded symbol using the pre-tree. */ -static inline int read_huffsym_using_pretree(struct input_bitstream *istream, - const u16 pretree_decode_table[], - const u8 pretree_lens[], unsigned *n) +static inline int +read_huffsym_using_pretree(struct input_bitstream *istream, + const u16 pretree_decode_table[], + const u8 pretree_lens[], unsigned *n) { return read_huffsym(istream, pretree_decode_table, pretree_lens, LZX_PRETREE_NUM_SYMBOLS, LZX_PRETREE_TABLEBITS, n, @@ -143,9 +153,10 @@ static inline int read_huffsym_using_pretree(struct input_bitstream *istream, } /* Reads a Huffman-encoded symbol using the main tree. */ -static inline int read_huffsym_using_maintree(struct input_bitstream *istream, - const struct lzx_tables *tables, - unsigned *n) +static inline int +read_huffsym_using_maintree(struct input_bitstream *istream, + const struct lzx_tables *tables, + unsigned *n) { return read_huffsym(istream, tables->maintree_decode_table, tables->maintree_lens, LZX_MAINTREE_NUM_SYMBOLS, @@ -153,9 +164,10 @@ static inline int read_huffsym_using_maintree(struct input_bitstream *istream, } /* Reads a Huffman-encoded symbol using the length tree. */ -static inline int read_huffsym_using_lentree(struct input_bitstream *istream, - const struct lzx_tables *tables, - unsigned *n) +static inline int +read_huffsym_using_lentree(struct input_bitstream *istream, + const struct lzx_tables *tables, + unsigned *n) { return read_huffsym(istream, tables->lentree_decode_table, tables->lentree_lens, LZX_LENTREE_NUM_SYMBOLS, @@ -163,9 +175,10 @@ static inline int read_huffsym_using_lentree(struct input_bitstream *istream, } /* Reads a Huffman-encoded symbol using the aligned offset tree. */ -static inline int read_huffsym_using_alignedtree(struct input_bitstream *istream, - const struct lzx_tables *tables, - unsigned *n) +static inline int +read_huffsym_using_alignedtree(struct input_bitstream *istream, + const struct lzx_tables *tables, + unsigned *n) { return read_huffsym(istream, tables->alignedtree_decode_table, tables->alignedtree_lens, @@ -185,12 +198,14 @@ static inline int read_huffsym_using_alignedtree(struct input_bitstream *istream * @num_lens: Number of length values to decode and return. * */ -static int lzx_read_code_lens(struct input_bitstream *istream, u8 lens[], - unsigned num_lens) +static int +lzx_read_code_lens(struct input_bitstream *istream, u8 lens[], + unsigned num_lens) { /* Declare the decoding table and length table for the pretree. */ u16 pretree_decode_table[(1 << LZX_PRETREE_TABLEBITS) + - (LZX_PRETREE_NUM_SYMBOLS * 2)]; + (LZX_PRETREE_NUM_SYMBOLS * 2)] + _aligned_attribute(DECODE_TABLE_ALIGNMENT); u8 pretree_lens[LZX_PRETREE_NUM_SYMBOLS]; unsigned i; unsigned len; @@ -230,7 +245,7 @@ static int lzx_read_code_lens(struct input_bitstream *istream, u8 lens[], unsigned num_zeroes; unsigned code; unsigned num_same; - char value; + signed char value; ret = read_huffsym_using_pretree(istream, pretree_decode_table, pretree_lens, &tree_code); @@ -270,7 +285,7 @@ static int lzx_read_code_lens(struct input_bitstream *istream, u8 lens[], &code); if (ret != 0) return ret; - value = (char)*lens - (char)code; + value = (signed char)*lens - (signed char)code; if (value < 0) value += 17; while (num_same--) { @@ -280,7 +295,7 @@ static int lzx_read_code_lens(struct input_bitstream *istream, u8 lens[], } break; default: /* Difference from old length. */ - value = (char)*lens - (char)tree_code; + value = (signed char)*lens - (signed char)tree_code; if (value < 0) value += 17; *lens = value; @@ -306,11 +321,12 @@ static int lzx_read_code_lens(struct input_bitstream *istream, u8 lens[], * R0, R1, and R2 will be written (only for uncompressed * blocks, which contain this information in the header) */ -static int lzx_read_block_header(struct input_bitstream *istream, - unsigned *block_size_ret, - unsigned *block_type_ret, - struct lzx_tables *tables, - struct lru_queue *queue) +static int +lzx_read_block_header(struct input_bitstream *istream, + unsigned *block_size_ret, + unsigned *block_type_ret, + struct lzx_tables *tables, + struct lzx_lru_queue *queue) { int ret; unsigned block_type; @@ -318,17 +334,16 @@ static int lzx_read_block_header(struct input_bitstream *istream, unsigned s; unsigned i; unsigned len; - u32 R[3]; - ret = bitstream_ensure_bits(istream, 4); - if (ret != 0) { - ERROR("LZX input stream overrun"); + ret = bitstream_ensure_bits(istream, LZX_BLOCKTYPE_NBITS + 1); + if (ret) { + LZX_DEBUG("LZX input stream overrun"); return ret; } /* The first three bits tell us what kind of block it is, and are one * of the LZX_BLOCKTYPE_* values. */ - block_type = bitstream_read_bits_nocheck(istream, 3); + block_type = bitstream_read_bits_nocheck(istream, LZX_BLOCKTYPE_NBITS); /* The next bit indicates whether the block size is the default (32768), * indicated by a 1 bit, or whether the block size is given by the next @@ -338,8 +353,8 @@ static int lzx_read_block_header(struct input_bitstream *istream, if (s) { block_size = 32768; } else { - ret = bitstream_read_bits(istream, 16, &block_size); - if (ret != 0) + ret = bitstream_read_bits(istream, LZX_BLOCKSIZE_NBITS, &block_size); + if (ret) return ret; block_size = le16_to_cpu(block_size); } @@ -353,7 +368,7 @@ static int lzx_read_block_header(struct input_bitstream *istream, ret = bitstream_read_bits(istream, LZX_ALIGNEDTREE_ELEMENT_SIZE, &len); - if (ret != 0) + if (ret) return ret; tables->alignedtree_lens[i] = len; } @@ -364,9 +379,9 @@ static int lzx_read_block_header(struct input_bitstream *istream, LZX_ALIGNEDTREE_TABLEBITS, tables->alignedtree_lens, 8); - if (ret != 0) { - ERROR("lzx_decompress(): Failed to make the decode " - "table for the aligned offset tree"); + if (ret) { + LZX_DEBUG("Failed to make the decode table for the " + "aligned offset tree"); return ret; } @@ -382,10 +397,9 @@ static int lzx_read_block_header(struct input_bitstream *istream, * tree. */ ret = lzx_read_code_lens(istream, tables->maintree_lens, LZX_NUM_CHARS); - if (ret != 0) { - ERROR("lzx_decompress(): Failed to read the code " - "lengths for the first 256 elements of the " - "main tree"); + if (ret) { + LZX_DEBUG("Failed to read the code lengths for the " + "first 256 elements of the main tree"); return ret; } @@ -397,10 +411,9 @@ static int lzx_read_block_header(struct input_bitstream *istream, ret = lzx_read_code_lens(istream, tables->maintree_lens + LZX_NUM_CHARS, LZX_MAINTREE_NUM_SYMBOLS - LZX_NUM_CHARS); - if (ret != 0) { - ERROR("lzx_decompress(): Failed to read the path " - "lengths for the remaining elements of the main " - "tree"); + if (ret) { + LZX_DEBUG("Failed to read the path lengths for the " + "remaining elements of the main tree"); return ret; } @@ -412,18 +425,18 @@ static int lzx_read_block_header(struct input_bitstream *istream, LZX_MAINTREE_TABLEBITS, tables->maintree_lens, LZX_MAX_CODEWORD_LEN); - if (ret != 0) { - ERROR("lzx_decompress(): Failed to make the decode " - "table for the main tree"); + if (ret) { + LZX_DEBUG("Failed to make the decode " + "table for the main tree"); return ret; } LZX_DEBUG("Reading path lengths for the length tree."); ret = lzx_read_code_lens(istream, tables->lentree_lens, LZX_LENTREE_NUM_SYMBOLS); - if (ret != 0) { - ERROR("lzx_decompress(): Failed to read the path " - "lengths for the length tree"); + if (ret) { + LZX_DEBUG("Failed to read the path " + "lengths for the length tree"); return ret; } @@ -433,9 +446,8 @@ static int lzx_read_block_header(struct input_bitstream *istream, LZX_LENTREE_TABLEBITS, tables->lentree_lens, LZX_MAX_CODEWORD_LEN); - if (ret != 0) { - ERROR("lzx_decompress(): Failed to build the length " - "Huffman tree"); + if (ret) { + LZX_DEBUG("Failed to build the length Huffman tree"); return ret; } /* The bitstream of compressed literals and matches for this @@ -450,13 +462,19 @@ static int lzx_read_block_header(struct input_bitstream *istream, * *already* aligned, the correct thing to do is to throw away * the next 16 bits. */ if (istream->bitsleft == 0) { - if (istream->data_bytes_left < 14) + if (istream->data_bytes_left < 14) { + LZX_DEBUG("Insufficient length in " + "uncompressed block"); return -1; + } istream->data += 2; istream->data_bytes_left -= 2; } else { - if (istream->data_bytes_left < 12) + if (istream->data_bytes_left < 12) { + LZX_DEBUG("Insufficient length in " + "uncompressed block"); return -1; + } istream->bitsleft = 0; istream->bitbuf = 0; } @@ -469,7 +487,7 @@ static int lzx_read_block_header(struct input_bitstream *istream, * be read in lzx_decompress(). */ break; default: - ERROR("lzx_decompress(): Found invalid block"); + LZX_DEBUG("Found invalid block"); return -1; } *block_type_ret = block_type; @@ -512,12 +530,13 @@ static int lzx_read_block_header(struct input_bitstream *istream, * - Match refers to data before the window. * - The input bitstream ended unexpectedly. */ -static int lzx_decode_match(unsigned main_element, int block_type, - unsigned bytes_remaining, u8 *window, - unsigned window_pos, - const struct lzx_tables *tables, - struct lru_queue *queue, - struct input_bitstream *istream) +static int +lzx_decode_match(unsigned main_element, int block_type, + unsigned bytes_remaining, u8 *window, + unsigned window_pos, + const struct lzx_tables *tables, + struct lzx_lru_queue *queue, + struct input_bitstream *istream) { unsigned length_header; unsigned position_slot; @@ -634,22 +653,24 @@ static int lzx_decode_match(unsigned main_element, int block_type, /* Verify that the match is in the bounds of the part of the window * currently in use, then copy the source of the match to the current * position. */ - match_dest = window + window_pos; - match_src = match_dest - match_offset; if (match_len > bytes_remaining) { - ERROR("lzx_decode_match(): Match of length %u bytes overflows " - "uncompressed block size", match_len); + LZX_DEBUG("Match of length %u bytes overflows " + "uncompressed block size", match_len); return -1; } - if (match_src < window) { - ERROR("lzx_decode_match(): Match of length %u bytes references " - "data before window (match_offset = %u, window_pos = %u)", - match_len, match_offset, window_pos); + if (match_offset > window_pos) { + LZX_DEBUG("Match of length %u bytes references " + "data before window (match_offset = %u, " + "window_pos = %u)", + match_len, match_offset, window_pos); return -1; } + match_dest = window + window_pos; + match_src = match_dest - match_offset; + #if 0 printf("Match: src %u, dst %u, len %u\n", match_src - window, match_dest - window, @@ -669,11 +690,12 @@ static int lzx_decode_match(unsigned main_element, int block_type, return match_len; } -static void undo_call_insn_translation(u32 *call_insn_target, int input_pos, - int32_t file_size) +static void +undo_call_insn_translation(u32 *call_insn_target, int input_pos, + s32 file_size) { - int32_t abs_offset; - int32_t rel_offset; + s32 abs_offset; + s32 rel_offset; abs_offset = le32_to_cpu(*call_insn_target); if (abs_offset >= -input_pos && abs_offset < file_size) { @@ -710,8 +732,8 @@ static void undo_call_insn_translation(u32 *call_insn_target, int input_pos, * Call instruction processing is supposed to take the file size as a parameter, * as it is used in calculating the translated jump targets. But in WIM files, * this file size is always the same (LZX_WIM_MAGIC_FILESIZE == 12000000).*/ -static void undo_call_insn_preprocessing(u8 uncompressed_data[], - int uncompressed_data_len) +static void +undo_call_insn_preprocessing(u8 uncompressed_data[], int uncompressed_data_len) { for (int i = 0; i < uncompressed_data_len - 10; i++) { if (uncompressed_data[i] == 0xe8) { @@ -738,12 +760,13 @@ static void undo_call_insn_preprocessing(u8 uncompressed_data[], * @queue: The least-recently-used queue for match offsets. * @istream: The input bitstream for the compressed literals. */ -static int lzx_decompress_block(int block_type, unsigned block_size, - u8 *window, - unsigned window_pos, - const struct lzx_tables *tables, - struct lru_queue *queue, - struct input_bitstream *istream) +static int +lzx_decompress_block(int block_type, unsigned block_size, + u8 *window, + unsigned window_pos, + const struct lzx_tables *tables, + struct lzx_lru_queue *queue, + struct input_bitstream *istream) { unsigned main_element; unsigned end; @@ -754,7 +777,7 @@ static int lzx_decompress_block(int block_type, unsigned block_size, while (window_pos < end) { ret = read_huffsym_using_maintree(istream, tables, &main_element); - if (ret != 0) + if (ret) return ret; if (main_element < LZX_NUM_CHARS) { @@ -778,30 +801,14 @@ static int lzx_decompress_block(int block_type, unsigned block_size, return 0; } -/* - * Decompresses a block of LZX-compressed data as used in the WIM file format. - * - * Note that this will NOT work unmodified for LZX as used in the cabinet - * format, which is not the same as in the WIM format! - * - * @compressed_data: A pointer to the compressed data. - * - * @compressed_len: The length of the compressed data, in bytes. - * - * @uncompressed_data: A pointer to the buffer into which to write the - * uncompressed data. - * - * @uncompressed_len: The length of the uncompressed data. It must be - * 32768 bytes or less. - * - * Return 0 on success; non-zero on failure. - */ -int lzx_decompress(const void *compressed_data, unsigned compressed_len, - void *uncompressed_data, unsigned uncompressed_len) +/* API function documented in wimlib.h */ +WIMLIBAPI int +wimlib_lzx_decompress(const void *compressed_data, unsigned compressed_len, + void *uncompressed_data, unsigned uncompressed_len) { struct lzx_tables tables; struct input_bitstream istream; - struct lru_queue queue; + struct lzx_lru_queue queue; unsigned window_pos; unsigned block_size; unsigned block_type; @@ -837,16 +844,16 @@ int lzx_decompress(const void *compressed_data, unsigned compressed_len, LZX_DEBUG("Reading block header."); ret = lzx_read_block_header(&istream, &block_size, &block_type, &tables, &queue); - if (ret != 0) + if (ret) return ret; LZX_DEBUG("block_size = %u, window_pos = %u", block_size, window_pos); if (block_size > uncompressed_len - window_pos) { - ERROR("lzx_decompress(): Expected a block size of at " - "most %u bytes (found %u bytes)", - uncompressed_len - window_pos, block_size); + LZX_DEBUG("Expected a block size of at " + "most %u bytes (found %u bytes)", + uncompressed_len - window_pos, block_size); return -1; } @@ -864,7 +871,7 @@ int lzx_decompress(const void *compressed_data, unsigned compressed_len, &tables, &queue, &istream); - if (ret != 0) + if (ret) return ret; if (tables.maintree_lens[0xe8] != 0) e8_preprocessing_done = true; @@ -872,10 +879,10 @@ int lzx_decompress(const void *compressed_data, unsigned compressed_len, case LZX_BLOCKTYPE_UNCOMPRESSED: LZX_DEBUG("LZX_BLOCKTYPE_UNCOMPRESSED"); if (istream.data_bytes_left < block_size) { - ERROR("Unexpected end of input when " - "reading %u bytes from LZX bitstream " - "(only have %u bytes left)", - block_size, istream.data_bytes_left); + LZX_DEBUG("Unexpected end of input when " + "reading %u bytes from LZX bitstream " + "(only have %u bytes left)", + block_size, istream.data_bytes_left); return -1; } memcpy(&((u8*)uncompressed_data)[window_pos], istream.data,