]> wimlib.net Git - wimlib/blobdiff - src/xpress-compress.c
--disable-verify-compression by default
[wimlib] / src / xpress-compress.c
index 2b3a6a6e9d980a14ce7ca2e6f062b5505c53656a..ec63eb18a8206b06d39dbdf032a1080809f962bb 100644 (file)
@@ -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.
  *
@@ -26,7 +26,9 @@
  */
 
 #include "xpress.h"
+#include "wimlib.h"
 #include "compress.h"
+
 #include <stdlib.h>
 #include <string.h>
 
@@ -36,8 +38,9 @@
  *
  * @codewords and @lens provide the Huffman code that is being used.
  */
-static int xpress_write_match(struct output_bitstream *ostream, u32 match,
-                             const u16 codewords[], const u8 lens[])
+static int
+xpress_write_match(struct output_bitstream *ostream, u32 match,
+                  const u16 codewords[], const u8 lens[])
 {
        u32 adjusted_match_len = match & 0xffff;
        u32 match_offset = match >> 16;
@@ -65,11 +68,12 @@ static int xpress_write_match(struct output_bitstream *ostream, u32 match,
                                  match_offset ^ (1 << offset_bsr), offset_bsr);
 }
 
-static int xpress_write_compressed_literals(struct output_bitstream *ostream,
-                                           const u32 match_tab[],
-                                           unsigned num_matches,
-                                           const u16 codewords[],
-                                           const u8 lens[])
+static int
+xpress_write_compressed_literals(struct output_bitstream *ostream,
+                                const u32 match_tab[],
+                                unsigned num_matches,
+                                const u16 codewords[],
+                                const u8 lens[])
 {
        for (unsigned i = 0; i < num_matches; i++) {
                int ret;
@@ -88,15 +92,17 @@ static int xpress_write_compressed_literals(struct output_bitstream *ostream,
                                  lens[XPRESS_END_OF_DATA]);
 }
 
-static u32 xpress_record_literal(u8 literal, void *__freq_tab)
+static u32
+xpress_record_literal(u8 literal, void *__freq_tab)
 {
-       u32 *freq_tab = __freq_tab;
+       freq_t *freq_tab = __freq_tab;
        freq_tab[literal]++;
        return literal;
 }
 
-static u32 xpress_record_match(unsigned match_offset, unsigned match_len,
-                              void *freq_tab, void *ignore)
+static u32
+xpress_record_match(unsigned match_offset, unsigned match_len,
+                   void *freq_tab, void *ignore)
 {
        wimlib_assert(match_len >= XPRESS_MIN_MATCH &&
                      match_len <= XPRESS_MAX_MATCH);
@@ -121,7 +127,7 @@ static u32 xpress_record_match(unsigned match_offset, unsigned match_len,
        u32 len_hdr = min(adjusted_match_len, 0xf);
        u32 offset_bsr = bsr32(match_offset);
        u32 sym = len_hdr | (offset_bsr << 4) | XPRESS_NUM_CHARS;
-       ((u32*)freq_tab)[sym]++;
+       ((freq_t*)freq_tab)[sym]++;
        return adjusted_match_len | (match_offset << 16);
 }
 
@@ -135,37 +141,27 @@ static const struct lz_params xpress_lz_params = {
        .too_far        = 4096,
 };
 
-/*
- * Performs XPRESS compression on a block of data.
- *
- * @__uncompressed_data:  Pointer to the data to be compressed.
- * @uncompressed_len:  Length, in bytes, of the data to be compressed.
- * @__compressed_data: Pointer to a location at least (@uncompressed_len - 1)
- *                             bytes long into which the compressed data may be
- *                             written.
- * @compressed_len_ret:        A pointer to an unsigned int into which the length of
- *                             the compressed data may be returned.
- *
- * Returns zero if compression was successfully performed.  In that case
- * @compressed_data and @compressed_len_ret will contain the compressed data and
- * its length.  A return value of nonzero means that compressing the data did
- * not reduce its size, and @compressed_data will not contain the full
- * compressed data.
- */
-int xpress_compress(const void *__uncompressed_data, unsigned uncompressed_len,
-                   void *__compressed_data, unsigned *compressed_len_ret)
+/* Documented in wimlib.h */
+WIMLIBAPI unsigned
+wimlib_xpress_compress(const void *__uncompressed_data,
+                      unsigned uncompressed_len, void *__compressed_data)
 {
-       const u8 *uncompressed_data = __uncompressed_data;
        u8 *compressed_data = __compressed_data;
        struct output_bitstream ostream;
        u32 match_tab[uncompressed_len];
-       u32 freq_tab[XPRESS_NUM_SYMBOLS];
+       freq_t freq_tab[XPRESS_NUM_SYMBOLS];
        u16 codewords[XPRESS_NUM_SYMBOLS];
        u8 lens[XPRESS_NUM_SYMBOLS];
        unsigned num_matches;
        unsigned compressed_len;
        unsigned i;
        int ret;
+       u8 uncompressed_data[uncompressed_len + 8];
+
+       memcpy(uncompressed_data, __uncompressed_data, uncompressed_len);
+       memset(uncompressed_data + uncompressed_len, 0, 8);
+
+       wimlib_assert(uncompressed_len <= 32768);
 
        /* XPRESS requires 256 bytes of overhead for the Huffman tables, so it's
         * impossible cannot compress 256 bytes or less of data to less than the
@@ -177,7 +173,7 @@ int xpress_compress(const void *__uncompressed_data, unsigned uncompressed_len,
         * +4 to take into account that init_output_bitstream() requires at
         * least 4 bytes of data. */
        if (uncompressed_len < XPRESS_NUM_SYMBOLS / 2 + 1 + 4)
-               return 1;
+               return 0;
 
        ZERO_ARRAY(freq_tab);
        num_matches = lz_analyze_block(uncompressed_data, uncompressed_len,
@@ -211,13 +207,13 @@ int xpress_compress(const void *__uncompressed_data, unsigned uncompressed_len,
 
        ret = xpress_write_compressed_literals(&ostream, match_tab,
                                               num_matches, codewords, lens);
-       if (ret != 0)
-               return ret;
+       if (ret)
+               return 0;
 
        /* Flush any bits that are buffered. */
        ret = flush_output_bitstream(&ostream);
-       if (ret != 0)
-               return ret;
+       if (ret)
+               return 0;
 
        /* Assert that there are no output bytes between the ostream.output
         * pointer and the ostream.next_bit_output pointer.  This can only
@@ -237,32 +233,32 @@ int xpress_compress(const void *__uncompressed_data, unsigned uncompressed_len,
         * they may precede a number of bytes embedded into the bitstream.) */
        if (ostream.bit_output >
            (const u8*)__compressed_data + uncompressed_len - 3)
-               return 1;
+               return 0;
        *(u16*)ostream.bit_output = cpu_to_le16(0);
        compressed_len = ostream.next_bit_output - (const u8*)__compressed_data;
 
        wimlib_assert(compressed_len <= uncompressed_len - 1);
 
-       *compressed_len_ret = compressed_len;
-
-#ifdef ENABLE_VERIFY_COMPRESSION
+#if defined(ENABLE_VERIFY_COMPRESSION)
        /* Verify that we really get the same thing back when decompressing. */
-       u8 buf[uncompressed_len];
-       ret = xpress_decompress(__compressed_data, compressed_len, buf,
-                               uncompressed_len);
-       if (ret != 0) {
-               ERROR("xpress_compress(): Failed to decompress data we "
-                     "compressed");
-               abort();
-       }
-       for (i = 0; i < uncompressed_len; i++) {
-               if (buf[i] != uncompressed_data[i]) {
-                       ERROR("xpress_compress(): Data we compressed didn't "
-                             "decompress to the original data (difference at "
-                             "byte %u of %u)", i + 1, uncompressed_len);
+       {
+               u8 buf[uncompressed_len];
+               ret = wimlib_xpress_decompress(__compressed_data, compressed_len,
+                                              buf, uncompressed_len);
+               if (ret) {
+                       ERROR("xpress_compress(): Failed to decompress data we "
+                             "compressed");
                        abort();
                }
+               for (i = 0; i < uncompressed_len; i++) {
+                       if (buf[i] != uncompressed_data[i]) {
+                               ERROR("xpress_compress(): Data we compressed didn't "
+                                     "decompress to the original data (difference at "
+                                     "byte %u of %u)", i + 1, uncompressed_len);
+                               abort();
+                       }
+               }
        }
 #endif
-       return 0;
+       return compressed_len;
 }