[gcab: 3/4] Fixed MSZIP compression when deflate algorithm would expand the input data
- From: Marc-André Lureau <malureau src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcab: 3/4] Fixed MSZIP compression when deflate algorithm would expand the input data
- Date: Tue, 2 Aug 2022 06:39:53 +0000 (UTC)
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]