X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fcompress.c;h=14046b19463f9bb4c28935b41cd21310440bcc90;hb=1558b2a0cc23c40778f42a8d6e8d9bb523b1c593;hp=dfaabe6b1c49d42e42ec035cb9de64e5e0b6250a;hpb=2254a0fc3f1d7af1151ee83f3458f44339b5028b;p=wimlib diff --git a/src/compress.c b/src/compress.c index dfaabe6b..14046b19 100644 --- a/src/compress.c +++ b/src/compress.c @@ -27,73 +27,83 @@ # include "config.h" #endif - #include "wimlib/assert.h" +#include "wimlib/compiler.h" #include "wimlib/compress.h" #include "wimlib/util.h" #include #include -static inline void -flush_bits(struct output_bitstream *ostream) -{ - *(le16*)ostream->bit_output = cpu_to_le16(ostream->bitbuf); - ostream->bit_output = ostream->next_bit_output; - ostream->next_bit_output = ostream->output; - ostream->output += 2; - ostream->num_bytes_remaining -= 2; -} - /* Writes @num_bits bits, given by the @num_bits least significant bits of * @bits, to the output @ostream. */ -int -bitstream_put_bits(struct output_bitstream *ostream, output_bitbuf_t bits, +void +bitstream_put_bits(struct output_bitstream *ostream, u32 bits, unsigned num_bits) { - unsigned rem_bits; + while (num_bits > ostream->free_bits) { + /* Buffer variable does not have space for the new bits. It + * needs to be flushed as a 16-bit integer. Bits in the second + * byte logically precede those in the first byte + * (little-endian), but within each byte the bits are ordered + * from high to low. This is true for both XPRESS and LZX + * compression. */ + + /* There must be at least 2 bytes of space remaining. */ + if (unlikely(ostream->bytes_remaining < 2)) { + ostream->overrun = true; + return; + } - wimlib_assert(num_bits <= 16); - if (num_bits <= ostream->free_bits) { - ostream->bitbuf = (ostream->bitbuf << num_bits) | bits; - ostream->free_bits -= num_bits; - } else { + /* Fill the buffer with as many bits that fit. */ + unsigned fill_bits = ostream->free_bits; + + ostream->bitbuf <<= fill_bits; + ostream->bitbuf |= bits >> (num_bits - fill_bits); - if (ostream->num_bytes_remaining + (ostream->output - - ostream->bit_output) < 2) - return 1; - - /* It is tricky to output the bits correctly. The correct way - * is to output little-endian 2-byte words, such that the bits - * in the SECOND byte logically precede those in the FIRST byte. - * While the byte order is little-endian, the bit order is - * big-endian; the first bit in a byte is the high-order one. - * Any multi-bit numbers are in bit-big-endian form, so the - * low-order bit of a multi-bit number is the LAST bit to be - * output. */ - rem_bits = num_bits - ostream->free_bits; - ostream->bitbuf <<= ostream->free_bits; - ostream->bitbuf |= bits >> rem_bits; - flush_bits(ostream); - ostream->free_bits = 16 - rem_bits; - ostream->bitbuf = bits; + *(le16*)ostream->bit_output = cpu_to_le16(ostream->bitbuf); + ostream->bit_output = ostream->next_bit_output; + ostream->next_bit_output = ostream->output; + ostream->output += 2; + ostream->bytes_remaining -= 2; + ostream->free_bits = 16; + num_bits -= fill_bits; + bits &= (1U << num_bits) - 1; } - return 0; + + /* Buffer variable has space for the new bits. */ + ostream->bitbuf = (ostream->bitbuf << num_bits) | bits; + ostream->free_bits -= num_bits; } -/* Flushes any remaining bits in the output buffer to the output byte stream. */ -int -flush_output_bitstream(struct output_bitstream *ostream) +void +bitstream_put_byte(struct output_bitstream *ostream, u8 n) { - if (ostream->num_bytes_remaining + (ostream->output - - ostream->bit_output) < 2) - return 1; - if (ostream->free_bits != 16) { - ostream->bitbuf <<= ostream->free_bits; - flush_bits(ostream); + if (unlikely(ostream->bytes_remaining < 1)) { + ostream->overrun = true; + return; } - return 0; + *ostream->output++ = n; + ostream->bytes_remaining--; +} + +/* Flushes any remaining bits to the output bitstream. + * + * Returns -1 if the stream has overrun; otherwise returns the total number of + * bytes in the output. */ +input_idx_t +flush_output_bitstream(struct output_bitstream *ostream) +{ + if (unlikely(ostream->overrun)) + return ~(input_idx_t)0; + + *(le16*)ostream->bit_output = + cpu_to_le16((u16)((u32)ostream->bitbuf << ostream->free_bits)); + *(le16*)ostream->next_bit_output = + cpu_to_le16(0); + + return ostream->output - ostream->output_start; } /* Initializes an output bit buffer to write its output to the memory location @@ -106,14 +116,16 @@ init_output_bitstream(struct output_bitstream *ostream, ostream->bitbuf = 0; ostream->free_bits = 16; + ostream->output_start = data; ostream->bit_output = data; ostream->next_bit_output = data + 2; ostream->output = data + 4; - ostream->num_bytes_remaining = num_bytes - 4; + ostream->bytes_remaining = num_bytes; + ostream->overrun = false; } typedef struct { - u32 freq; + freq_t freq; u16 sym; union { u16 path_len; @@ -136,12 +148,12 @@ cmp_nodes_by_freq(const void *_leaf1, const void *_leaf2) const HuffmanNode *leaf1 = _leaf1; const HuffmanNode *leaf2 = _leaf2; - int freq_diff = (int)leaf1->freq - (int)leaf2->freq; - - if (freq_diff == 0) - return (int)leaf1->sym - (int)leaf2->sym; + if (leaf1->freq > leaf2->freq) + return 1; + else if (leaf1->freq < leaf2->freq) + return -1; else - return freq_diff; + return (int)leaf1->sym - (int)leaf2->sym; } /* Comparator function for HuffmanNodes. Sorts primarily by code length and @@ -244,7 +256,7 @@ make_canonical_huffman_code(unsigned num_syms, /* We require at least 2 possible symbols in the alphabet to produce a * valid Huffman decoding table. It is allowed that fewer than 2 symbols * are actually used, though. */ - wimlib_assert(num_syms >= 2); + wimlib_assert(num_syms >= 2 && num_syms < INVALID_SYMBOL); /* Initialize the lengths and codewords to 0 */ memset(lens, 0, num_syms * sizeof(lens[0]));