]> wimlib.net Git - wimlib/blobdiff - src/decompress.h
Re-organize code
[wimlib] / src / decompress.h
diff --git a/src/decompress.h b/src/decompress.h
new file mode 100644 (file)
index 0000000..b4c4579
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * decompress.h
+ *
+ * Functions useful for decompression, mainly bitstreams.
+ */
+
+#ifndef _WIMLIB_DECOMP_H
+#define _WIMLIB_DECOMP_H
+
+#include "util.h"
+#include "endianness.h"
+
+/* Must be at least 32 bits. */
+typedef unsigned long input_bitbuf_t;
+
+/* Structure to provide a bitstream. */
+struct input_bitstream {
+
+       /* A variable of length at least 32 bits that is used to hold bits that
+        * have been read from the stream.  The bits are ordered from high-order
+        * to low-order; the next bit is always the high-order bit. */
+       input_bitbuf_t  bitbuf;
+
+       /* Pointer to the next byte to be retrieved from the input. */
+       const u8 *data;
+
+       /* Number of bits in @bitbuf that are valid. */
+       unsigned bitsleft;
+
+       /* Number of words of data that are left. */
+       unsigned data_bytes_left;
+};
+
+/* Initializes a bitstream to receive its input from @data. */
+static inline void init_input_bitstream(struct input_bitstream *istream,
+                                       const void *data, unsigned num_data_bytes)
+{
+       istream->bitbuf          = 0;
+       istream->bitsleft        = 0;
+       istream->data            = data;
+       istream->data_bytes_left = num_data_bytes;
+}
+
+/* Ensures that the bit buffer contains @num_bits bits. */
+static inline int bitstream_ensure_bits(struct input_bitstream *istream,
+                                       unsigned num_bits)
+{
+       wimlib_assert(num_bits <= 16);
+
+       /* Unfortunately this needs to be different for the different
+        * compression types.  LZX requires reading no more than the number of
+        * bits needed, otherwise the end of the compressed data may be overrun.
+        * XPRESS, on the other hand, requires that we always return with at
+        * least 16 bits in the buffer, even if fewer are requested.  This is
+        * important because this may change the location of a literal byte
+        * read with bitstream_read_byte(). */
+#ifdef XPRESS_DECOMP
+       while (istream->bitsleft < 16) {
+#else
+       while (istream->bitsleft < num_bits) {
+#endif
+               if (istream->data_bytes_left < 2)
+                       return 1;
+
+               unsigned shift = sizeof(input_bitbuf_t) * 8 - 16 -
+                                istream->bitsleft;
+               istream->bitbuf |= (input_bitbuf_t)le16_to_cpu(
+                                       *(u16*)istream->data) << shift;
+               istream->data += 2;
+               istream->bitsleft += 16;
+               istream->data_bytes_left -= 2;
+       }
+       return 0;
+}
+
+/* Returns the next @num_bits bits in the bit buffer.  It must contain at least
+ * @num_bits bits to call this function. */
+static inline unsigned
+bitstream_peek_bits(const struct input_bitstream *istream, unsigned num_bits)
+{
+       if (num_bits == 0)
+               return 0;
+       return istream->bitbuf >> (sizeof(input_bitbuf_t) * 8 - num_bits);
+}
+
+/* Removes @num_bits bits from the bit buffer.  It must contain at least
+ * @num_bits bits to call this function. */
+static inline void bitstream_remove_bits(struct input_bitstream *istream,
+                                        unsigned num_bits)
+{
+       istream->bitbuf <<= num_bits;
+       istream->bitsleft -= num_bits;
+}
+
+/* Reads and returns @num_bits bits from the input bitstream. */
+static inline int bitstream_read_bits(struct input_bitstream *istream,
+                                     unsigned num_bits, unsigned *n)
+{
+       int ret;
+       ret = bitstream_ensure_bits(istream, num_bits);
+       if (ret != 0) {
+               ERROR("bitstream_read_bits(): Input buffer exhausted");
+               return ret;
+       }
+       *n = bitstream_peek_bits(istream, num_bits);
+       bitstream_remove_bits(istream, num_bits);
+       return 0;
+}
+
+/* In the XPRESS format there can be literal length bytes embedded in the
+ * compressed bitstream.  These bytes are basically separate from the bitstream,
+ * as they come AFTER the bits that are currently in the buffer variable (based
+ * on reading 16 bits at a time), even though the buffer variable may not be
+ * empty.
+ *
+ * This function returns the next such literal length byte in the input
+ * bitstream.  Returns -1 if we are at the end of the bitstream. */
+static inline int bitstream_read_byte(struct input_bitstream *istream)
+{
+       wimlib_assert(istream->bitsleft < 32);
+
+       if (istream->data_bytes_left == 0) {
+               ERROR("bitstream_read_byte(): Input buffer exhausted");
+               return -1;
+       }
+       istream->data_bytes_left--;
+       return *istream->data++;
+}
+
+/* Reads @num_bits bits from the bit buffer without checking to see if that many
+ * bits are in the buffer or not. */
+static inline unsigned
+bitstream_read_bits_nocheck(struct input_bitstream *istream, unsigned num_bits)
+{
+       unsigned n = bitstream_peek_bits(istream, num_bits);
+       bitstream_remove_bits(istream, num_bits);
+       return n;
+}
+
+/* Removes the bits that have been read into the bit buffer variable. */
+static inline void flush_input_bitstream(struct input_bitstream *istream)
+{
+       bitstream_remove_bits(istream, istream->bitsleft);
+       istream->bitsleft = 0;
+       istream->bitbuf = 0;
+}
+
+extern int bitstream_read_bytes(struct input_bitstream *istream, size_t n,
+                               void *dest);
+
+extern int align_input_bitstream(struct input_bitstream *istream,
+                                bool skip_word_if_aligned);
+
+extern int read_huffsym(struct input_bitstream *stream,
+                       const u16 decode_table[],
+                       const u8 lengths[],
+                       unsigned num_symbols,
+                       unsigned table_bits,
+                       unsigned *n,
+                       unsigned max_codeword_len);
+
+extern int make_huffman_decode_table(u16 decode_table[], unsigned num_syms,
+                                    unsigned num_bits, const u8 lengths[],
+                                    unsigned max_codeword_len);
+
+#endif /* _WIMLIB_DECOMP_H */