]> wimlib.net Git - wimlib/blobdiff - src/lzx-decompress.c
lzx-decompress.c: Don't allow using offsets of 0
[wimlib] / src / lzx-decompress.c
index 0c95ac03ecefa1489ee9e69a76a5d9197245e7ad..513944ee18525ab69715bb0341188b2044ad2322 100644 (file)
@@ -94,12 +94,11 @@ struct lzx_tables {
 /* The main LZX decompressor structure.
  *
  * Note: we keep track of most of the decompression state outside this
- * structure.  This structure only exists so that (1) we can store
- * @max_window_size and @num_main_syms for multiple calls to lzx_decompress();
- * and (2) so that we don't have to allocate the large 'struct lzx_tables' on
- * the stack.  */
+ * structure.  This structure only exists so that (1) we can store @window_order
+ * and @num_main_syms for multiple calls to lzx_decompress(); and (2) so that we
+ * don't have to allocate the large 'struct lzx_tables' on the stack.  */
 struct lzx_decompressor {
-       u32 max_window_size;
+       unsigned window_order;
        unsigned num_main_syms;
        struct lzx_tables tables;
 };
@@ -265,7 +264,7 @@ lzx_read_codeword_lens(struct input_bitstream *istream, u8 lens[], unsigned num_
 static int
 lzx_read_block_header(struct input_bitstream *istream,
                      unsigned num_main_syms,
-                     u32 max_window_size,
+                     unsigned window_order,
                      int *block_type_ret,
                      u32 *block_size_ret,
                      struct lzx_tables *tables,
@@ -296,7 +295,7 @@ lzx_read_block_header(struct input_bitstream *istream,
                block_size <<= 8;
                block_size |= tmp;
 
-               if (max_window_size >= 65536) {
+               if (window_order >= 16) {
                        tmp = bitstream_read_bits(istream, 8);
                        block_size <<= 8;
                        block_size |= tmp;
@@ -379,22 +378,15 @@ 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)
-                               return -1;
-                       istream->data += 2;
-                       istream->data_bytes_left -= 2;
-               } else {
-                       if (istream->data_bytes_left < 12)
-                               return -1;
-                       istream->bitsleft = 0;
-                       istream->bitbuf = 0;
-               }
-               queue->R[0] = le32_to_cpu(*(le32*)(istream->data + 0));
-               queue->R[1] = le32_to_cpu(*(le32*)(istream->data + 4));
-               queue->R[2] = le32_to_cpu(*(le32*)(istream->data + 8));
-               istream->data += 12;
-               istream->data_bytes_left -= 12;
+               bitstream_ensure_bits(istream, 1);
+               bitstream_align(istream);
+               queue->R[0] = bitstream_read_u32(istream);
+               queue->R[1] = bitstream_read_u32(istream);
+               queue->R[2] = bitstream_read_u32(istream);
+
+               /* Offsets of 0 are invalid.  */
+               if (queue->R[0] == 0 || queue->R[1] == 0 || queue->R[2] == 0)
+                       return -1;
                break;
 
        default:
@@ -593,9 +585,6 @@ lzx_decompress(const void *compressed_data, size_t compressed_size,
        bool may_have_e8_byte;
        int ret;
 
-       if (uncompressed_size > dec->max_window_size)
-               return -1;
-
        init_input_bitstream(&istream, compressed_data, compressed_size);
 
        /* Initialize the recent offsets queue.  */
@@ -619,7 +608,7 @@ lzx_decompress(const void *compressed_data, size_t compressed_size,
             window_pos += block_size)
        {
                ret = lzx_read_block_header(&istream, dec->num_main_syms,
-                                           dec->max_window_size, &block_type,
+                                           dec->window_order, &block_type,
                                            &block_size, &dec->tables, &queue);
                if (ret)
                        return ret;
@@ -648,21 +637,19 @@ lzx_decompress(const void *compressed_data, size_t compressed_size,
                } else {
 
                        /* Uncompressed block.  */
+                       const u8 *p;
 
-                       if (istream.data_bytes_left < block_size)
+                       p = bitstream_read_bytes(&istream, block_size);
+                       if (!p)
                                return -1;
 
-                       memcpy(&((u8*)uncompressed_data)[window_pos], istream.data,
-                              block_size);
-                       istream.data += block_size;
-                       istream.data_bytes_left -= block_size;
+                       memcpy(&((u8*)uncompressed_data)[window_pos], p, block_size);
 
                        /* Re-align the bitstream if an odd number of bytes was
                         * read.  */
-                       if (istream.data_bytes_left && (block_size & 1)) {
-                               istream.data_bytes_left--;
-                               istream.data++;
-                       }
+                       if (block_size & 1)
+                               bitstream_read_byte(&istream);
+
                        may_have_e8_byte = true;
                }
        }
@@ -683,11 +670,13 @@ lzx_free_decompressor(void *_dec)
 }
 
 static int
-lzx_create_decompressor(size_t max_window_size, void **dec_ret)
+lzx_create_decompressor(size_t max_block_size, void **dec_ret)
 {
        struct lzx_decompressor *dec;
+       unsigned window_order;
 
-       if (!lzx_window_size_valid(max_window_size))
+       window_order = lzx_get_window_order(max_block_size);
+       if (window_order == 0)
                return WIMLIB_ERR_INVALID_PARAM;
 
        /* The aligned allocation is needed to ensure that the lzx_tables are
@@ -697,8 +686,8 @@ lzx_create_decompressor(size_t max_window_size, void **dec_ret)
        if (!dec)
                return WIMLIB_ERR_NOMEM;
 
-       dec->max_window_size = max_window_size;
-       dec->num_main_syms = lzx_get_num_main_syms(max_window_size);
+       dec->window_order = window_order;
+       dec->num_main_syms = lzx_get_num_main_syms(window_order);
 
        *dec_ret = dec;
        return 0;