]> wimlib.net Git - wimlib/blobdiff - src/compress.c
Variable LZX window sizes
[wimlib] / src / compress.c
index e7e199149edc7574bd258e605d2ed27a41b54cb3..86c3c2bcd7bb28cd7e7614b191f112b95b252bc0 100644 (file)
 #  include "config.h"
 #endif
 
-
 #include "wimlib/assert.h"
+#include "wimlib/compiler.h"
 #include "wimlib/compress.h"
 #include "wimlib/util.h"
 
 #include <stdlib.h>
 #include <string.h>
 
-static inline void
-flush_bits(struct output_bitstream *ostream)
-{
-       *(u16*)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,10 +116,12 @@ 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 {
@@ -237,9 +249,9 @@ huffman_tree_compute_path_lengths(HuffmanNode *base_node, u16 cur_len)
 void
 make_canonical_huffman_code(unsigned num_syms,
                            unsigned max_codeword_len,
-                           const freq_t * restrict freq_tab,
-                           u8 * restrict lens,
-                           u16 * restrict codewords)
+                           const freq_t freq_tab[restrict],
+                           u8 lens[restrict],
+                           u16 codewords[restrict])
 {
        /* 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