Merge pull request #3256 from stoeckmann/cab_integers

cab: Refactor data types + extend huffman tables to 16 bit if needed
This commit is contained in:
Dustin L. Howett authored and GitHub committed 2026-07-09 10:03:45 -05:00
commit cb2c1207f0
5 files changed
+274 -204

No files matched your search

+2
View File
@@ -490,6 +490,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_read_format_ar.c \
libarchive/test/test_read_format_cab.c \
libarchive/test/test_read_format_cab_filename.c \
libarchive/test/test_read_format_cab_lzx_16bit.c \
libarchive/test/test_read_format_cab_lzx_e8.c \
libarchive/test/test_read_format_cab_lzx_oob.c \
libarchive/test/test_read_format_cab_mszip_oob.c \
@@ -918,6 +919,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_read_format_cab_2.cab.uu \
libarchive/test/test_read_format_cab_3.cab.uu \
libarchive/test/test_read_format_cab_filename_cp932.cab.uu \
libarchive/test/test_read_format_cab_lzx_16bit.cab.uu \
libarchive/test/test_read_format_cab_lzx_e8.cab.uu \
libarchive/test/test_read_format_cab_lzx_oob.cab.uu \
libarchive/test/test_read_format_cab_multi.p1.cab.uu \
+213 -204
View File
@@ -56,12 +56,12 @@
* Lookups are performed through a direct, expanded lookup table.
*
* An expanded table has as many elements as needed to cover all possible
* indices formable with bit patterns of given max_bits length.
* indices formable with bit patterns of given lookup_bits length.
*
* If less codes exist, these span multiple entries for all possible
* combinations of following bits.
*
* Example of a Huffman tree with len_size = 3, max_bits = 2:
* Example of a Huffman tree with len_size = 3, lookup_bits = 2:
*
* Symbol | Code
* -------+-----
@@ -80,7 +80,7 @@
* 0b10 | B
* 0b11 | C
*
* By using max_bits bits as a lookup, it becomes apparent that 0b00 and
* By using lookup_bits bits as a lookup, it becomes apparent that 0b00 and
* 0b01 point to a symbol which actually has the code 0b0. A user of this
* data structure must check the code bit length of a retrieved symbol after
* the lookup to properly advance the bit stream:
@@ -93,7 +93,7 @@
*
* Thus, a proper code sequence would be:
*
* symbol = tbl[read_bits(max_bits)]
* symbol = tbl[read_bits(lookup_bits)]
* consume_bits(bitlen[symbol])
*/
struct huffman {
@@ -101,14 +101,14 @@ struct huffman {
* Amount of symbols.
*
* This implementation keeps track of unused symbols as well,
* thus symbols start with 0x0000 up to given maximum amount
* of symbols: [0..len_size]
* thus symbols start with 0x0000 up to given symbol amount:
* [0..symbol_count)
*
* Used to construct tbl.
*/
int len_size;
uint16_t symbol_count;
/*
* Frequency (aka weight) of code bit lengths.
* Frequency of code bit lengths.
*
* Represents the amount of occurrences of given bit lengths.
* Index 0 is used for "empty" codes (aka unused symbols),
@@ -117,17 +117,17 @@ struct huffman {
*
* Used to construct tbl.
*/
int freq[17];
uint16_t freq[17];
/* Map of symbols to their code bit lengths. */
unsigned char *bitlen;
/* Longest used code bit length (<= tbl_bits). */
int max_bits;
uint8_t *bitlen;
/* Amount of bits to use for lookup (<= tbl_bits). */
uint8_t lookup_bits;
/*
* Maximum allowed code bit length (<= 16).
* Code bit length used for allocation (<= 16).
*
* Used to construct tbl.
*/
int tbl_bits;
uint8_t tbl_bits;
/* Direct, expanded lookup table. */
uint16_t *tbl;
};
@@ -141,14 +141,14 @@ struct lzx_br {
/* Cache buffer. */
CACHE_TYPE cache_buffer;
/* Indicates how many bits avail in cache_buffer. */
int cache_avail;
unsigned char odd;
char have_odd;
size_t cache_avail;
uint8_t odd;
int have_odd;
};
struct lzx_pos_tbl {
int base;
int footer_bits;
uint32_t base;
uint8_t footer_bits;
};
struct lzx_dec {
@@ -181,34 +181,34 @@ struct lzx_dec {
/*
* Window to see last decoded data, from 32KBi to 2MBi.
*/
int w_size;
int w_mask;
size_t w_size;
size_t w_mask;
/* Window buffer, which is a loop buffer. */
unsigned char *w_buff;
uint8_t *w_buff;
/* The insert position to the window. */
int w_pos;
size_t w_pos;
/* The position where we can copy decoded code from the window. */
int copy_pos;
size_t copy_pos;
/* The length how many bytes we can copy decoded code from
* the window. */
int copy_len;
size_t copy_len;
/* Translation reversal for x86 processor CALL byte sequence(E8).
* This is used for LZX only. */
int32_t translation_size;
char translation;
char block_type;
int translation;
uint8_t block_type;
#define VERBATIM_BLOCK 1
#define ALIGNED_OFFSET_BLOCK 2
#define UNCOMPRESSED_BLOCK 3
size_t block_size;
size_t block_bytes_avail;
/* Repeated offset. */
int r0, r1, r2;
unsigned char rbytes[4];
int rbytes_avail;
int length_header;
int position_slot;
int offset_bits;
size_t r0, r1, r2;
uint8_t rbytes[4];
size_t rbytes_avail;
uint8_t length_header;
uint16_t position_slot;
uint8_t offset_bits;
struct lzx_pos_tbl *pos_tbl;
/*
@@ -224,11 +224,11 @@ struct lzx_dec {
struct huffman mt;
struct huffman pt;
int loop;
uint16_t loop;
int error;
};
static const int slots[] = {
static const size_t slots[] = {
30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
};
#define SLOT_BASE 15
@@ -236,11 +236,11 @@ static const int slots[] = {
struct lzx_stream {
const unsigned char *next_in;
int64_t avail_in;
int64_t total_in;
size_t avail_in;
size_t total_in;
unsigned char *next_out;
int64_t avail_out;
int64_t total_out;
size_t avail_out;
size_t total_out;
struct lzx_dec *ds;
};
@@ -440,11 +440,11 @@ static void lzx_translation(struct lzx_stream *, unsigned char *, size_t, int32_
static void lzx_cleanup_bitstream(struct lzx_stream *);
static int lzx_decode(struct lzx_stream *, int);
static int lzx_read_pre_tree(struct lzx_stream *);
static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, int);
static int lzx_huffman_init(struct huffman *, size_t, int);
static int lzx_read_bitlen(struct lzx_stream *, struct huffman *, uint16_t);
static int lzx_huffman_init(struct huffman *, uint16_t, uint8_t);
static void lzx_huffman_free(struct huffman *);
static int lzx_make_huffman_table(struct huffman *);
static inline int lzx_decode_huffman(struct huffman *, unsigned);
static uint16_t lzx_decode_huffman(struct huffman *, uint16_t);
int
@@ -2121,7 +2121,7 @@ archive_read_format_cab_cleanup(struct archive_read *a)
{
struct cab *cab = (struct cab *)(a->format->data);
struct cfheader *hd = &cab->cfheader;
int i;
uint16_t i;
if (hd->folder_array != NULL) {
for (i = 0; i < hd->folder_count; i++)
@@ -2183,10 +2183,11 @@ cab_dos_time(const unsigned char *p)
static int
lzx_decode_init(struct lzx_stream *strm, int w_bits)
{
struct lzx_dec *ds;
int slot, w_size, w_slot;
int base, footer;
int base_inc[18];
struct lzx_dec *ds;
uint32_t base;
uint16_t slot, w_size, w_slot;
uint8_t footer;
if (strm->ds == NULL) {
strm->ds = calloc(1, sizeof(*strm->ds));
@@ -2208,7 +2209,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
w_size = ds->w_size;
w_slot = slots[w_bits - SLOT_BASE];
ds->w_size = 1U << w_bits;
ds->w_mask = ds->w_size -1;
ds->w_mask = ds->w_size - 1;
if (ds->w_buff == NULL || w_size != ds->w_size) {
free(ds->w_buff);
ds->w_buff = malloc(ds->w_size);
@@ -2230,11 +2231,13 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
else
base += base_inc[footer];
if (footer < 17) {
footer = -2;
footer = 0;
for (n = base; n; n >>= 1)
footer++;
if (footer <= 0)
if (footer <= 2)
footer = 0;
else
footer -= 2;
}
ds->pos_tbl[slot].base = base;
ds->pos_tbl[slot].footer_bits = footer;
@@ -2255,7 +2258,7 @@ lzx_decode_init(struct lzx_stream *strm, int w_bits)
return (ARCHIVE_FATAL);
/* Initialize Main tree. */
if (lzx_huffman_init(&(ds->mt), 256+(w_slot<<3), 16)
if (lzx_huffman_init(&(ds->mt), 256 + (w_slot << 3), 16)
!= ARCHIVE_OK)
return (ARCHIVE_FATAL);
@@ -2342,7 +2345,7 @@ lzx_translation(struct lzx_stream *strm, unsigned char *buffer, size_t size,
* False : we met that strm->next_in is empty, we have to get following
* bytes. */
#define lzx_br_read_ahead_0(strm, br, n) \
(lzx_br_has((br), (n)) || lzx_br_fillup(strm, br))
(lzx_br_has((br), (n)) || lzx_br_fillup(strm, br) == ARCHIVE_OK)
/* True : the cache buffer has some bits as much as we need.
* False : there are no enough bits in the cache buffer to be used,
* we have to get following bytes if we could. */
@@ -2371,8 +2374,8 @@ static const uint32_t cache_masks[] = {
* Shift away used bits in the cache data and fill it up with following bits.
* Call this when cache buffer does not have enough bits you need.
*
* Returns 1 if the cache buffer is full.
* Returns 0 if the cache buffer is not full; input buffer is empty.
* Returns ARCHIVE_OK if the cache buffer is full.
* Returns ARCHIVE_EOF if the cache buffer is not full; input buffer is empty.
*/
static int
lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
@@ -2380,7 +2383,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
/*
* x86 processor family can read misaligned data without an access error.
*/
int n = CACHE_BITS - br->cache_avail;
ssize_t n = CACHE_BITS - br->cache_avail;
for (;;) {
switch (n >> 4) {
@@ -2398,7 +2401,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
strm->next_in += 8;
strm->avail_in -= 8;
br->cache_avail += 8 * 8;
return (1);
return (ARCHIVE_OK);
}
break;
case 3:
@@ -2414,13 +2417,13 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
strm->next_in += 6;
strm->avail_in -= 6;
br->cache_avail += 6 * 8;
return (1);
return (ARCHIVE_OK);
}
break;
case 0:
/* We have enough compressed data in
* the cache buffer.*/
return (1);
return (ARCHIVE_EOF);
default:
break;
}
@@ -2432,7 +2435,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
strm->avail_in--;
br->have_odd = 1;
}
return (0);
return (ARCHIVE_EOF);
}
br->cache_buffer =
(br->cache_buffer << 16) |
@@ -2447,7 +2450,7 @@ lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
static void
lzx_br_fixup(struct lzx_stream *strm, struct lzx_br *br)
{
int n = CACHE_BITS - br->cache_avail;
ssize_t n = CACHE_BITS - br->cache_avail;
if (br->have_odd && n >= 16 && strm->avail_in > 0) {
br->cache_buffer =
@@ -2480,7 +2483,7 @@ static int
lzx_decode(struct lzx_stream *strm, int last)
{
struct lzx_dec *ds = strm->ds;
int64_t avail_in;
size_t avail_in;
int r;
if (ds->error)
@@ -2492,7 +2495,8 @@ lzx_decode(struct lzx_stream *strm, int last)
if (ds->state < ST_MAIN)
r = lzx_read_blocks(strm, last);
else {
int64_t bytes_written = strm->avail_out;
size_t bytes_written = strm->avail_out;
r = lzx_decode_blocks(strm, last);
bytes_written -= strm->avail_out;
strm->next_out += bytes_written;
@@ -2508,7 +2512,8 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
{
struct lzx_dec *ds = strm->ds;
struct lzx_br *br = &(ds->br);
int i, r;
int r;
uint16_t i;
for (;;) {
switch (ds->state) {
@@ -2645,17 +2650,17 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
ds->rbytes_avail = 0;
if (ds->state == ST_RD_R0) {
ds->r0 = archive_le32dec(ds->rbytes);
if (ds->r0 < 0)
if (ds->r0 > (size_t)INT32_MAX)
goto failed;
ds->state = ST_RD_R1;
} else if (ds->state == ST_RD_R1) {
ds->r1 = archive_le32dec(ds->rbytes);
if (ds->r1 < 0)
if (ds->r1 > (size_t)INT32_MAX)
goto failed;
ds->state = ST_RD_R2;
} else if (ds->state == ST_RD_R2) {
ds->r2 = archive_le32dec(ds->rbytes);
if (ds->r2 < 0)
if (ds->r2 > (size_t)INT32_MAX)
goto failed;
/* We've gotten all repeated offsets. */
ds->state = ST_COPY_UNCOMP1;
@@ -2667,7 +2672,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
* Copy bytes form next_in to next_out directly.
*/
while (ds->block_bytes_avail) {
int l;
size_t l;
if (strm->avail_out <= 0)
/* Output buffer is empty. */
@@ -2678,13 +2683,13 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
goto failed;
return (ARCHIVE_OK);
}
l = (int)ds->block_bytes_avail;
l = ds->block_bytes_avail;
if (l > ds->w_size - ds->w_pos)
l = ds->w_size - ds->w_pos;
if (l > strm->avail_out)
l = (int)strm->avail_out;
l = strm->avail_out;
if (l > strm->avail_in)
l = (int)strm->avail_in;
l = strm->avail_in;
memcpy(strm->next_out, strm->next_in, l);
memcpy(&(ds->w_buff[ds->w_pos]),
strm->next_in, l);
@@ -2718,19 +2723,19 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Read Aligned offset tree.
*/
if (!lzx_br_read_ahead(strm, br, 3 * ds->at.len_size)) {
if (!lzx_br_read_ahead(strm, br, 3 * ds->at.symbol_count)) {
ds->state = ST_RD_ALIGNED_OFFSET;
if (last)
goto failed;
return (ARCHIVE_OK);
}
memset(ds->at.freq, 0, sizeof(ds->at.freq));
for (i = 0; i < ds->at.len_size; i++) {
for (i = 0; i < ds->at.symbol_count; i++) {
ds->at.bitlen[i] = lzx_br_bits(br, 3);
ds->at.freq[ds->at.bitlen[i]]++;
lzx_br_consume(br, 3);
}
if (!lzx_make_huffman_table(&ds->at))
if (lzx_make_huffman_table(&ds->at) < 0)
goto failed;
/* FALL THROUGH */
case ST_RD_VERBATIM:
@@ -2740,13 +2745,13 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Read Pre-tree for first 256 elements of main tree.
*/
if (!lzx_read_pre_tree(strm)) {
if (lzx_read_pre_tree(strm) < 0) {
ds->state = ST_RD_PRE_MAIN_TREE_256;
if (last)
goto failed;
return (ARCHIVE_OK);
}
if (!lzx_make_huffman_table(&ds->pt))
if (lzx_make_huffman_table(&ds->pt) < 0)
goto failed;
ds->loop = 0;
/* FALL THROUGH */
@@ -2755,27 +2760,26 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
* Get path lengths of first 256 elements of main tree.
*/
r = lzx_read_bitlen(strm, &ds->mt, 256);
if (r < 0)
goto failed;
else if (!r) {
if (r == ARCHIVE_EOF) {
ds->state = ST_MAIN_TREE_256;
if (last)
goto failed;
return (ARCHIVE_OK);
}
} else if (r < 0)
goto failed;
ds->loop = 0;
/* FALL THROUGH */
case ST_RD_PRE_MAIN_TREE_REM:
/*
* Read Pre-tree for remaining elements of main tree.
*/
if (!lzx_read_pre_tree(strm)) {
if (lzx_read_pre_tree(strm) < 0) {
ds->state = ST_RD_PRE_MAIN_TREE_REM;
if (last)
goto failed;
return (ARCHIVE_OK);
}
if (!lzx_make_huffman_table(&ds->pt))
if (lzx_make_huffman_table(&ds->pt) < 0)
goto failed;
ds->loop = 256;
/* FALL THROUGH */
@@ -2783,16 +2787,15 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Get path lengths of remaining elements of main tree.
*/
r = lzx_read_bitlen(strm, &ds->mt, -1);
if (r < 0)
goto failed;
else if (!r) {
r = lzx_read_bitlen(strm, &ds->mt, 0);
if (r == ARCHIVE_EOF) {
ds->state = ST_MAIN_TREE_REM;
if (last)
goto failed;
return (ARCHIVE_OK);
}
if (!lzx_make_huffman_table(&ds->mt))
} else if (r < 0)
goto failed;
if (lzx_make_huffman_table(&ds->mt) < 0)
goto failed;
ds->loop = 0;
/* FALL THROUGH */
@@ -2800,13 +2803,13 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Read Pre-tree for remaining elements of main tree.
*/
if (!lzx_read_pre_tree(strm)) {
if (lzx_read_pre_tree(strm) < 0) {
ds->state = ST_RD_PRE_LENGTH_TREE;
if (last)
goto failed;
return (ARCHIVE_OK);
}
if (!lzx_make_huffman_table(&ds->pt))
if (lzx_make_huffman_table(&ds->pt) < 0)
goto failed;
ds->loop = 0;
/* FALL THROUGH */
@@ -2814,16 +2817,15 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
/*
* Get path lengths of remaining elements of main tree.
*/
r = lzx_read_bitlen(strm, &ds->lt, -1);
if (r < 0)
goto failed;
else if (!r) {
r = lzx_read_bitlen(strm, &ds->lt, 0);
if (r == ARCHIVE_EOF) {
ds->state = ST_LENGTH_TREE;
if (last)
goto failed;
return (ARCHIVE_OK);
}
if (!lzx_make_huffman_table(&ds->lt))
} else if (r < 0)
goto failed;
if (lzx_make_huffman_table(&ds->lt) < 0)
goto failed;
ds->state = ST_MAIN;
return (100);
@@ -2842,22 +2844,23 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;
unsigned char *noutp = strm->next_out;
unsigned char *endp = noutp + strm->avail_out;
unsigned char *w_buff = ds->w_buff;
unsigned char *at_bitlen = at->bitlen;
unsigned char *lt_bitlen = lt->bitlen;
unsigned char *mt_bitlen = mt->bitlen;
uint8_t *w_buff = ds->w_buff;
uint8_t *at_bitlen = at->bitlen;
uint8_t *lt_bitlen = lt->bitlen;
uint8_t *mt_bitlen = mt->bitlen;
size_t block_bytes_avail = ds->block_bytes_avail;
int at_max_bits = at->max_bits;
int lt_max_bits = lt->max_bits;
int mt_max_bits = mt->max_bits;
int c, copy_len = ds->copy_len, copy_pos = ds->copy_pos;
int w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
int length_header = ds->length_header;
int offset_bits = ds->offset_bits;
int position_slot = ds->position_slot;
int r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;
uint8_t at_lookup_bits = at->lookup_bits;
uint8_t lt_lookup_bits = lt->lookup_bits;
uint8_t mt_lookup_bits = mt->lookup_bits;
size_t copy_len = ds->copy_len, copy_pos = ds->copy_pos;
size_t w_pos = ds->w_pos, w_mask = ds->w_mask, w_size = ds->w_size;
uint8_t length_header = ds->length_header;
uint8_t offset_bits = ds->offset_bits;
uint16_t position_slot = ds->position_slot;
size_t r0 = ds->r0, r1 = ds->r1, r2 = ds->r2;
int state = ds->state;
char block_type = ds->block_type;
uint16_t c;
uint8_t block_type = ds->block_type;
for (;;) {
switch (state) {
@@ -2883,26 +2886,26 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
goto next_data;
if (!lzx_br_read_ahead(strm, &bre,
mt_max_bits)) {
mt_lookup_bits)) {
if (!last)
goto next_data;
/* Remaining bits are less than
* maximum bits(mt.max_bits) but maybe
* it still remains as much as we need,
* so we should try to use it with
* dummy bits. */
* maximum bits (mt.lookup_bits) but
* maybe it still remains as much as we
* need, so we should try to use it
* with dummy bits. */
c = lzx_decode_huffman(mt,
lzx_br_bits_forced(
&bre, mt_max_bits));
lzx_br_consume(&bre, mt_bitlen[c]);
if (!lzx_br_has(&bre, 0))
&bre, mt_lookup_bits));
if (!lzx_br_has(&bre, mt_bitlen[c]))
goto failed;/* Over read. */
lzx_br_consume(&bre, mt_bitlen[c]);
} else {
c = lzx_decode_huffman(mt,
lzx_br_bits(&bre, mt_max_bits));
lzx_br_bits(&bre, mt_lookup_bits));
lzx_br_consume(&bre, mt_bitlen[c]);
}
if ((unsigned int)c > UCHAR_MAX)
if (c > UCHAR_MAX)
break;
/*
* 'c' is exactly literal code.
@@ -2928,26 +2931,26 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
*/
if (length_header == 7) {
if (!lzx_br_read_ahead(strm, &bre,
lt_max_bits)) {
lt_lookup_bits)) {
if (!last) {
state = ST_LENGTH;
goto next_data;
}
c = lzx_decode_huffman(lt,
lzx_br_bits_forced(
&bre, lt_max_bits));
lzx_br_consume(&bre, lt_bitlen[c]);
if (!lzx_br_has(&bre, 0))
&bre, lt_lookup_bits));
if (!lzx_br_has(&bre, lt_bitlen[c]))
goto failed;/* Over read. */
lzx_br_consume(&bre, lt_bitlen[c]);
} else {
c = lzx_decode_huffman(lt,
lzx_br_bits(&bre, lt_max_bits));
lzx_br_bits(&bre, lt_lookup_bits));
lzx_br_consume(&bre, lt_bitlen[c]);
}
copy_len = c + 7 + 2;
} else
copy_len = length_header + 2;
if ((size_t)copy_len > block_bytes_avail)
if (copy_len > block_bytes_avail)
goto failed;
/*
* Get an offset.
@@ -2984,7 +2987,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
*/
if (block_type == ALIGNED_OFFSET_BLOCK &&
offset_bits >= 3) {
int offbits = offset_bits - 3;
unsigned offbits = offset_bits - 3;
if (!lzx_br_read_ahead(strm, &bre, offbits)) {
state = ST_OFFSET;
@@ -2996,7 +2999,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
/* Get an aligned number. */
if (!lzx_br_read_ahead(strm, &bre,
offbits + at_max_bits)) {
offbits + at_lookup_bits)) {
if (!last) {
state = ST_OFFSET;
goto next_data;
@@ -3004,14 +3007,14 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
lzx_br_consume(&bre, offbits);
c = lzx_decode_huffman(at,
lzx_br_bits_forced(&bre,
at_max_bits));
lzx_br_consume(&bre, at_bitlen[c]);
if (!lzx_br_has(&bre, 0))
at_lookup_bits));
if (!lzx_br_has(&bre, at_bitlen[c]))
goto failed;/* Over read. */
lzx_br_consume(&bre, at_bitlen[c]);
} else {
lzx_br_consume(&bre, offbits);
c = lzx_decode_huffman(at,
lzx_br_bits(&bre, at_max_bits));
lzx_br_bits(&bre, at_lookup_bits));
lzx_br_consume(&bre, at_bitlen[c]);
}
/* Add an aligned number. */
@@ -3027,7 +3030,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
copy_pos = lzx_br_bits(&bre, offset_bits);
lzx_br_consume(&bre, offset_bits);
}
copy_pos += pos_tbl[position_slot].base -2;
copy_pos += pos_tbl[position_slot].base - 2;
/* Update repeated offset LRU queue. */
r2 = r1;
@@ -3046,8 +3049,8 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
* into the output buffer.
*/
for (;;) {
const unsigned char *s;
int l;
const uint8_t *s;
size_t l;
l = copy_len;
if (copy_pos > w_pos) {
@@ -3058,15 +3061,15 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
l = w_size - w_pos;
}
if (noutp + l >= endp)
l = (int)(endp - noutp);
l = endp - noutp;
s = w_buff + copy_pos;
if (l >= 8 && ((copy_pos + l < w_pos)
|| (w_pos + l < copy_pos))) {
memcpy(w_buff + w_pos, s, l);
memcpy(noutp, s, l);
} else {
unsigned char *d;
int li;
uint8_t *d;
size_t li;
d = w_buff + w_pos;
for (li = 0; li < l; li++)
@@ -3112,122 +3115,124 @@ lzx_read_pre_tree(struct lzx_stream *strm)
{
struct lzx_dec *ds = strm->ds;
struct lzx_br *br = &(ds->br);
int i;
uint16_t i;
if (ds->loop == 0)
memset(ds->pt.freq, 0, sizeof(ds->pt.freq));
for (i = ds->loop; i < ds->pt.len_size; i++) {
for (i = ds->loop; i < ds->pt.symbol_count; i++) {
if (!lzx_br_read_ahead(strm, br, 4)) {
ds->loop = i;
return (0);
return (ARCHIVE_EOF);
}
ds->pt.bitlen[i] = lzx_br_bits(br, 4);
ds->pt.freq[ds->pt.bitlen[i]]++;
lzx_br_consume(br, 4);
}
ds->loop = i;
return (1);
return (ARCHIVE_OK);
}
/*
* Read a bunch of bit-lengths from pre-tree.
*/
static int
lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, int end)
lzx_read_bitlen(struct lzx_stream *strm, struct huffman *d, uint16_t end)
{
struct lzx_dec *ds = strm->ds;
struct lzx_br *br = &(ds->br);
int c, i, j, ret, same;
unsigned rbits;
int ret;
uint16_t c, i, j, rbits, same;
i = ds->loop;
if (i == 0)
memset(d->freq, 0, sizeof(d->freq));
ret = 0;
if (end < 0)
end = d->len_size;
ret = ARCHIVE_EOF;
if (end == 0)
end = d->symbol_count;
while (i < end) {
ds->loop = i;
if (!lzx_br_read_ahead(strm, br, ds->pt.max_bits))
if (!lzx_br_read_ahead(strm, br, (unsigned)ds->pt.lookup_bits))
goto getdata;
rbits = lzx_br_bits(br, ds->pt.max_bits);
rbits = lzx_br_bits(br, ds->pt.lookup_bits);
c = lzx_decode_huffman(&(ds->pt), rbits);
switch (c) {
case 17:/* several zero lengths, from 4 to 19. */
if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+4))
if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c] + 4U))
goto getdata;
lzx_br_consume(br, ds->pt.bitlen[c]);
same = lzx_br_bits(br, 4) + 4;
if (i + same > end)
return (-1);/* Invalid */
if (same > end - i)
return (ARCHIVE_FATAL);
lzx_br_consume(br, 4);
for (j = 0; j < same; j++)
d->bitlen[i++] = 0;
break;
case 18:/* many zero lengths, from 20 to 51. */
if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c]+5))
if (!lzx_br_read_ahead(strm, br, ds->pt.bitlen[c] + 5U))
goto getdata;
lzx_br_consume(br, ds->pt.bitlen[c]);
same = lzx_br_bits(br, 5) + 20;
if (i + same > end)
return (-1);/* Invalid */
if (same > end - i)
return (ARCHIVE_FATAL);
lzx_br_consume(br, 5);
memset(d->bitlen + i, 0, same);
i += same;
break;
case 19:/* a few same lengths. */
if (!lzx_br_read_ahead(strm, br,
ds->pt.bitlen[c]+1+ds->pt.max_bits))
ds->pt.bitlen[c] + 1U + ds->pt.lookup_bits))
goto getdata;
lzx_br_consume(br, ds->pt.bitlen[c]);
same = lzx_br_bits(br, 1) + 4;
if (i + same > end)
return (-1);
if (same > end - i)
return (ARCHIVE_FATAL);
lzx_br_consume(br, 1);
rbits = lzx_br_bits(br, ds->pt.max_bits);
rbits = lzx_br_bits(br, ds->pt.lookup_bits);
c = lzx_decode_huffman(&(ds->pt), rbits);
lzx_br_consume(br, ds->pt.bitlen[c]);
c = (d->bitlen[i] - c + 17) % 17;
if (c < 0)
return (-1);/* Invalid */
if (c > d->bitlen[i] + 17)
return (ARCHIVE_FATAL);
c = (d->bitlen[i] + 17 - c) % 17;
for (j = 0; j < same; j++)
d->bitlen[i++] = c;
d->freq[c] += same;
break;
default:
lzx_br_consume(br, ds->pt.bitlen[c]);
c = (d->bitlen[i] - c + 17) % 17;
if (c < 0)
return (-1);/* Invalid */
if (c > d->bitlen[i] + 17)
return (ARCHIVE_FATAL);
c = (d->bitlen[i] + 17 - c) % 17;
d->freq[c]++;
d->bitlen[i++] = c;
break;
}
}
ret = 1;
ret = ARCHIVE_OK;
getdata:
ds->loop = i;
return (ret);
}
static int
lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
lzx_huffman_init(struct huffman *hf, uint16_t symbol_count, uint8_t tbl_bits)
{
size_t tbl_size = (size_t)1 << tbl_bits;
if (hf->bitlen == NULL || hf->len_size != (int)len_size) {
if (hf->bitlen == NULL || hf->symbol_count != symbol_count) {
free(hf->bitlen);
hf->bitlen = calloc(len_size, sizeof(hf->bitlen[0]));
hf->bitlen = calloc(symbol_count, sizeof(hf->bitlen[0]));
if (hf->bitlen == NULL)
return (ARCHIVE_FATAL);
hf->len_size = (int)len_size;
hf->symbol_count = symbol_count;
} else
memset(hf->bitlen, 0, len_size * sizeof(hf->bitlen[0]));
memset(hf->bitlen, 0, symbol_count * sizeof(hf->bitlen[0]));
if (hf->tbl == NULL) {
hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0]));
hf->tbl = calloc(tbl_size, sizeof(hf->tbl[0]));
if (hf->tbl == NULL)
return (ARCHIVE_FATAL);
hf->tbl_bits = tbl_bits;
}
} else
memset(hf->tbl, 0, tbl_size * sizeof(hf->bitlen[0]));
return (ARCHIVE_OK);
}
@@ -3245,11 +3250,12 @@ lzx_huffman_free(struct huffman *hf)
static int
lzx_make_huffman_table(struct huffman *hf)
{
uint16_t bitptn[17], weight[17];
uint16_t *tbl;
const unsigned char *bitlen;
int bitptn[17], weight[17];
int i, maxbits = 0, ptn, tbl_size, w;
int len_avail;
const uint8_t *bitlen;
uint8_t maxbits = 0;
uint32_t ptn;
uint16_t i, symbol_count, w;
/*
* Initialize bit patterns.
@@ -3290,10 +3296,8 @@ lzx_make_huffman_table(struct huffman *hf)
}
}
/* Verify Kraft's inequality. */
if ((ptn & 0xffff) != 0 || maxbits > hf->tbl_bits)
return (0);/* Invalid */
hf->max_bits = maxbits;
if (ptn != 0 && ptn != 0x10000)
return (ARCHIVE_FATAL);
/*
* Shrink codes to smallest size by removing extra bits after
@@ -3318,13 +3322,27 @@ lzx_make_huffman_table(struct huffman *hf)
* Thus, the direct, expanded lookup table only needs 4 entries.
*/
if (maxbits < 16) {
int ebits = 16 - maxbits;
uint8_t ebits = 16 - maxbits;
for (i = 1; i <= maxbits; i++) {
bitptn[i] >>= ebits;
weight[i] >>= ebits;
}
}
/* Grow table if necessary. */
if (maxbits > hf->tbl_bits) {
size_t tbl_size;
hf->tbl_bits = 16;
tbl_size = (size_t)1 << hf->tbl_bits;
free(hf->tbl);
hf->tbl = calloc(tbl_size, sizeof(hf->tbl[0]));
if (hf->tbl == NULL)
return (ARCHIVE_FATAL);
}
hf->lookup_bits = maxbits;
/*
* Construct the direct, expanded lookup table.
*
@@ -3351,43 +3369,34 @@ lzx_make_huffman_table(struct huffman *hf)
* 2 (0b10) | 3
* 3 (0b11) | 4
*/
tbl_size = 1 << hf->tbl_bits;
tbl = hf->tbl;
bitlen = hf->bitlen;
len_avail = hf->len_size;
/* Initialize table to invalid values */
for (i = 0; i < tbl_size; i++) {
tbl[i] = (uint16_t)hf->len_size;
}
for (i = 0; i < len_avail; i++) {
symbol_count = hf->symbol_count;
for (i = 0; i < symbol_count; i++) {
uint16_t *p;
int len, cnt;
uint16_t cnt;
uint8_t len;
if (bitlen[i] == 0)
continue;
/* Get a bit pattern */
len = bitlen[i];
if (len > tbl_size)
return (0);
if (len > maxbits)
return (ARCHIVE_FATAL);
ptn = bitptn[len];
cnt = weight[len];
/* Calculate next bit pattern */
if ((bitptn[len] = ptn + cnt) > tbl_size)
return (0);/* Invalid */
bitptn[len] = ptn + cnt;
/* Update the table */
p = &(tbl[ptn]);
while (--cnt >= 0)
p[cnt] = (uint16_t)i;
p = tbl + ptn;
while (cnt-- > 0)
*p++ = i;
}
return (1);
return (ARCHIVE_OK);
}
static inline int
lzx_decode_huffman(struct huffman *hf, unsigned rbits)
static uint16_t
lzx_decode_huffman(struct huffman *hf, uint16_t rbits)
{
int c;
c = hf->tbl[rbits];
if (c < hf->len_size)
return (c);
return (0);
return hf->tbl[rbits];
}
+1
View File
@@ -119,6 +119,7 @@ IF(ENABLE_TEST)
test_read_format_ar.c
test_read_format_cab.c
test_read_format_cab_filename.c
test_read_format_cab_lzx_16bit.c
test_read_format_cab_lzx_e8.c
test_read_format_cab_lzx_oob.c
test_read_format_cab_mszip_oob.c
@@ -0,0 +1,52 @@
/*-
* Copyright (c) 2026 Tobias Stoeckmann
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
DEFINE_TEST(test_read_format_cab_lzx_16bit)
{
const char *refname = "test_read_format_cab_lzx_16bit.cab";
struct archive *a;
struct archive_entry *ae;
char buff[16];
extract_reference_file(refname);
assert((a = archive_read_new()) != NULL);
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_cab(a));
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
assertEqualIntA(a, ARCHIVE_OK,
archive_read_open_filename(a, refname, 10240));
/* Read entry. */
assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
assertEqualString(archive_entry_pathname(ae), "lzx16.bin");
assertEqualInt(archive_entry_size(ae), 16);
assertEqualIntA(a, sizeof(buff),
archive_read_data(a, buff, sizeof(buff)));
assertEqualMem(buff, "ABABABABABABABAB", 16);
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
@@ -0,0 +1,6 @@
begin 644 test_read_format_cab_lzx_16bit.cab
M35-#1@````""`````````"P``````````P$!``$`````````1@````$``P\0
M````````````(0```"``;'IX,38N8FEN```````T`!```!`#`6=%JXGOS0+P
H"R(%[??[`.@``````````'^(__\`X`````````(`_R'__ZK*`*@`````
`
end