[gcab: 3/4] Fixed MSZIP compression when deflate algorithm would expand the input data




commit 6b90d6204bd7a0d213833dc38eb4c5bcdb945466
Author: Joel Holdsworth <jholdsworth nvidia com>
Date:   Thu Jul 21 22:48:35 2022 +0100

    Fixed MSZIP compression when deflate algorithm would expand the input data

 libgcab/cabinet.c      | 74 +++++++++++++++++++++++++++++++-------------------
 libgcab/cabinet.h      |  9 ++++--
 libgcab/decomp.h       |  8 ------
 libgcab/gcab-cabinet.c | 10 ++++---
 4 files changed, 58 insertions(+), 43 deletions(-)
---
diff --git a/libgcab/cabinet.c b/libgcab/cabinet.c
index 072ef7a..6241904 100644
--- a/libgcab/cabinet.c
+++ b/libgcab/cabinet.c
@@ -426,6 +426,43 @@ compute_checksum (guint8 *in, guint16 ncbytes, guint32 seed)
     return csum;
 }
 
+static gboolean
+cdata_deflate_block (cdata_t *cd, guint8 *data, size_t size, int level,
+                     GError **error)
+{
+    z_stream deflate_stream = { 0, };
+    int zret;
+
+    deflate_stream.zalloc = zalloc;
+    deflate_stream.zfree = zfree;
+    zret = deflateInit2 (&deflate_stream, level, Z_DEFLATED, -15, 8,
+                         Z_DEFAULT_STRATEGY);
+    if (zret != Z_OK) {
+        g_set_error (error, GCAB_ERROR, GCAB_ERROR_FAILED,
+                     "zlib deflateInit2 failed: %s", zError (zret));
+        return FALSE;
+    }
+    deflate_stream.next_in = data;
+    deflate_stream.avail_in = size;
+    deflate_stream.next_out = cd->in + 2;
+    deflate_stream.avail_out = sizeof (cd->in) - 2;
+    /* insert the signature */
+    cd->in[0] = 'C';
+    cd->in[1] = 'K';
+    zret = deflate (&deflate_stream, Z_FINISH);
+    if (zret != Z_OK && zret != Z_STREAM_END) {
+        g_set_error (error, GCAB_ERROR, GCAB_ERROR_FAILED,
+                     "zlib deflate failed: %s", zError (zret));
+        return FALSE;
+    }
+    deflateEnd (&deflate_stream);
+
+    cd->ncbytes = deflate_stream.total_out + 2;
+    cd->nubytes = size;
+
+    return TRUE;
+}
+
 G_GNUC_INTERNAL gboolean
 cdata_write (cdata_t *cd, GDataOutputStream *out, int type,
              guint8 *data, size_t size, gsize *bytes_written,
@@ -439,34 +476,15 @@ cdata_write (cdata_t *cd, GDataOutputStream *out, int type,
         break;
 
     case GCAB_COMPRESSION_MSZIP:
-        z_stream deflate_stream = { 0, };
-        int zret;
-
-        deflate_stream.zalloc = zalloc;
-        deflate_stream.zfree = zfree;
-        zret = deflateInit2 (&deflate_stream, Z_DEFAULT_COMPRESSION,
-                             Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
-        if (zret != Z_OK) {
-            g_set_error (error, GCAB_ERROR, GCAB_ERROR_FAILED,
-                         "zlib deflateInit2 failed: %s", zError (zret));
-            return FALSE;
-        }
-        deflate_stream.next_in = data;
-        deflate_stream.avail_in = size;
-        deflate_stream.next_out = cd->in + 2;
-        deflate_stream.avail_out = sizeof (cd->in) - 2;
-        /* insert the signature */
-        cd->in[0] = 'C';
-        cd->in[1] = 'K';
-        zret = deflate (&deflate_stream, Z_FINISH);
-        if (zret != Z_OK && zret != Z_STREAM_END) {
-            g_set_error (error, GCAB_ERROR, GCAB_ERROR_FAILED,
-                         "zlib deflate failed: %s", zError (zret));
+        if (!cdata_deflate_block (cd, data, size, Z_DEFAULT_COMPRESSION, error))
             return FALSE;
+
+        if (cd->ncbytes >= CAB_MAX_MSZIP_BLOCK_SIZE) {
+            /* if the compressor inflated the data, store it uncompressed */
+            if (!cdata_deflate_block (cd, data, size, Z_NO_COMPRESSION, error))
+                return FALSE;
         }
-        deflateEnd (&deflate_stream);
-        cd->ncbytes = deflate_stream.total_out + 2;
-        cd->nubytes = size;
+
         break;
 
     default:
@@ -570,11 +588,11 @@ cdata_read (cdata_t *cd, guint8 res_data, gint comptype,
         return FALSE;
     }
     R2 (cd->nubytes);
-    if (cd->nubytes > CAB_BLOCKMAX) {
+    if (cd->nubytes > CAB_MAX_BLOCK_SIZE) {
         g_set_error (error, GCAB_ERROR, GCAB_ERROR_INVALID_DATA,
                      "CDATA block of %" G_GUINT16_FORMAT " bytes "
                      "was bigger than maximum size %i",
-                     cd->nubytes, CAB_BLOCKMAX);
+                     cd->nubytes, CAB_MAX_BLOCK_SIZE);
         return FALSE;
     }
     RN (cd->reserved, res_data);
diff --git a/libgcab/cabinet.h b/libgcab/cabinet.h
index 850ac65..5470b22 100644
--- a/libgcab/cabinet.h
+++ b/libgcab/cabinet.h
@@ -40,7 +40,10 @@
 /* based on the spec
    http://msdn.microsoft.com/en-us/library/bb417343.aspx */
 
-#define DATABLOCKSIZE           32768
+#define CAB_MAX_BLOCK_SIZE                (32768)
+#define CAB_MAX_MSZIP_BLOCK_SIZE          (32768 + 12)
+#define CAB_MAX_LZX_BLOCK_SIZE            (32768 + 6144)
+#define CAB_MAX_COMPRESSED_BLOCK_SIZE     (CAB_MAX_LZX_BLOCK_SIZE)
 
 #define CFO_START               0x24    /* folder offset */
 #define CFI_START               0x2C    /* file offset */
@@ -100,8 +103,8 @@ typedef struct
     guint16 ncbytes;
     guint16 nubytes;
     guint8 *reserved;
-    guint8 in[CAB_INPUTMAX+2];
-    guint8 out[CAB_BLOCKMAX];
+    guint8 in[CAB_MAX_COMPRESSED_BLOCK_SIZE];
+    guint8 out[CAB_MAX_BLOCK_SIZE];
     /* using zlib */
     z_stream z;
     /* using wine decomp.h */
diff --git a/libgcab/decomp.h b/libgcab/decomp.h
index 041d60e..36f28d9 100644
--- a/libgcab/decomp.h
+++ b/libgcab/decomp.h
@@ -117,14 +117,6 @@
   bitbuf = lb.bb; bitsleft = lb.bl; inpos = lb.ip; \
 } while (0)
 
-/* CAB data blocks are <= 32768 bytes in uncompressed form. Uncompressed
- * blocks have zero growth. MSZIP guarantees that it won't grow above
- * uncompressed size by more than 12 bytes. LZX guarantees it won't grow
- * more than 6144 bytes.
- */
-#define CAB_BLOCKMAX (32768)
-#define CAB_INPUTMAX (CAB_BLOCKMAX+6144)
-
 typedef guint8        cab_UBYTE; /* 8 bits  */
 typedef guint16       cab_UWORD; /* 16 bits */
 typedef guint32       cab_ULONG; /* 32 bits */
diff --git a/libgcab/gcab-cabinet.c b/libgcab/gcab-cabinet.c
index 57c5962..10087e9 100644
--- a/libgcab/gcab-cabinet.c
+++ b/libgcab/gcab-cabinet.c
@@ -274,7 +274,7 @@ gcab_cabinet_write (GCabCabinet *self,
     g_autoptr(GDataOutputStream) dstream = NULL;
     gssize len, offset = 0;
     cdata_t block = { 0, };
-    guint8 data[DATABLOCKSIZE];
+    guint8 data[CAB_MAX_BLOCK_SIZE];
     gsize written;
     size_t sumstr = 0;
     g_autoptr(GSList) files = NULL;
@@ -319,9 +319,11 @@ gcab_cabinet_write (GCabCabinet *self,
             return FALSE;
 
         while ((len = g_input_stream_read (in,
-                                           &data[offset], DATABLOCKSIZE - offset,
-                                           cancellable, error)) == (DATABLOCKSIZE - offset)) {
-            if (!cdata_write (&block, dstream, folder.typecomp, data, DATABLOCKSIZE, &written, cancellable, 
error))
+                                           &data[offset], CAB_MAX_BLOCK_SIZE - offset,
+                                           cancellable, error)) ==
+                (CAB_MAX_BLOCK_SIZE - offset)) {
+            if (!cdata_write (&block, dstream, folder.typecomp, data,
+                              CAB_MAX_BLOCK_SIZE, &written, cancellable, error))
                 return FALSE;
             folder.ndatab++;
             cheader->size += written;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]