rbutil: Update embedded 'mspack' library from 0.10.1alpha to 0.11alpha

Change-Id: I37210d1dc2c5cecdf8256f9e0294dcbd8516e8c8
This commit is contained in:
Solomon Peachy 2026-07-04 21:39:31 -04:00
parent adbb185f7b
commit a82396b0be
13 changed files with 281 additions and 327 deletions

View file

@ -1,6 +1,6 @@
This folder contains the mspack project for MS files compression/decompression.
These files are distributed under the LGPL.
The source files have been last synced with libmspack-0.10.1alpha
https://www.cabextract.org.uk/libmspack/ on June 8, 2020
The source files have been last synced with libmspack-0.11alpha
https://www.cabextract.org.uk/libmspack/ released on Feb 5, 2023

View file

@ -1,5 +1,5 @@
/* This file is part of libmspack.
* (C) 2003-2018 Stuart Caie.
* (C) 2003-2023 Stuart Caie.
*
* libmspack is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
@ -76,7 +76,8 @@ static int cabd_read_headers(
struct mspack_system *sys, struct mspack_file *fh,
struct mscabd_cabinet_p *cab, off_t offset, int salvage, int quiet);
static char *cabd_read_string(
struct mspack_system *sys, struct mspack_file *fh, int *error);
struct mspack_system *sys, struct mspack_file *fh, int permit_empty,
int *error);
static struct mscabd_cabinet *cabd_search(
struct mscab_decompressor *base, const char *filename);
@ -394,17 +395,17 @@ static int cabd_read_headers(struct mspack_system *sys,
/* read name and info of preceeding cabinet in set, if present */
if (cab->base.flags & cfheadPREV_CABINET) {
cab->base.prevname = cabd_read_string(sys, fh, &err);
cab->base.prevname = cabd_read_string(sys, fh, 0, &err);
if (err) return err;
cab->base.previnfo = cabd_read_string(sys, fh, &err);
cab->base.previnfo = cabd_read_string(sys, fh, 1, &err);
if (err) return err;
}
/* read name and info of next cabinet in set, if present */
if (cab->base.flags & cfheadNEXT_CABINET) {
cab->base.nextname = cabd_read_string(sys, fh, &err);
cab->base.nextname = cabd_read_string(sys, fh, 0, &err);
if (err) return err;
cab->base.nextinfo = cabd_read_string(sys, fh, &err);
cab->base.nextinfo = cabd_read_string(sys, fh, 1, &err);
if (err) return err;
}
@ -508,7 +509,7 @@ static int cabd_read_headers(struct mspack_system *sys,
file->date_y = (x >> 9) + 1980;
/* get filename */
file->filename = cabd_read_string(sys, fh, &err);
file->filename = cabd_read_string(sys, fh, 0, &err);
/* if folder index or filename are bad, either skip it or fail */
if (err || !file->folder) {
@ -535,7 +536,8 @@ static int cabd_read_headers(struct mspack_system *sys,
}
static char *cabd_read_string(struct mspack_system *sys,
struct mspack_file *fh, int *error)
struct mspack_file *fh, int permit_empty,
int *error)
{
off_t base = sys->tell(fh);
char buf[256], *str;
@ -549,8 +551,8 @@ static char *cabd_read_string(struct mspack_system *sys,
/* search for a null terminator in the buffer */
for (i = 0, ok = 0; i < len; i++) if (!buf[i]) { ok = 1; break; }
/* reject empty strings */
if (i == 0) ok = 0;
/* optionally reject empty strings */
if (i == 0 && !permit_empty) ok = 0;
if (!ok) {
*error = MSPACK_ERR_DATAFORMAT;
@ -651,10 +653,10 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
unsigned int cablen_u32 = 0, foffset_u32 = 0;
int false_cabs = 0;
#if !LARGEFILE_SUPPORT
#if SIZEOF_OFF_T < 8
/* detect 32-bit off_t overflow */
if (flen < 0) {
sys->message(fh, largefile_msg);
sys->message(fh, "library not compiled to support large files.");
return MSPACK_ERR_OK;
}
#endif
@ -753,10 +755,10 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
/* cause the search to restart after this cab's data. */
offset = caboff + (off_t) cablen_u32;
#if !LARGEFILE_SUPPORT
#if SIZEOF_OFF_T < 8
/* detect 32-bit off_t overflow */
if (offset < caboff) {
sys->message(fh, largefile_msg);
sys->message(fh, "library not compiled to support large files.");
return MSPACK_ERR_OK;
}
#endif
@ -1012,7 +1014,7 @@ static int cabd_extract(struct mscab_decompressor *base,
struct mscabd_folder_p *fol;
struct mspack_system *sys;
struct mspack_file *fh;
off_t filelen;
unsigned int filelen;
if (!self) return MSPACK_ERR_ARGS;
if (!file) return self->error = MSPACK_ERR_ARGS;
@ -1029,7 +1031,7 @@ static int cabd_extract(struct mscab_decompressor *base,
* or in salvage mode reduce file length so it fits 2GB limit
*/
filelen = file->length;
if (filelen > CAB_LENGTHMAX || (file->offset + filelen) > CAB_LENGTHMAX) {
if (filelen > (CAB_LENGTHMAX - file->offset)) {
if (self->salvage) {
filelen = CAB_LENGTHMAX - file->offset;
}
@ -1049,8 +1051,8 @@ static int cabd_extract(struct mscab_decompressor *base,
* In salvage mode, don't assume block sizes, just try decoding
*/
if (!self->salvage) {
off_t maxlen = fol->base.num_blocks * CAB_BLOCKMAX;
if ((file->offset + filelen) > maxlen) {
unsigned int maxlen = fol->base.num_blocks * CAB_BLOCKMAX;
if (file->offset > maxlen || filelen > (maxlen - file->offset)) {
sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
"cabinet set is incomplete", file->filename);
return self->error = MSPACK_ERR_DECRUNCH;
@ -1398,7 +1400,7 @@ static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
unsigned int len, ul = 0;
for (len = bytes >> 2; len--; data += 4) {
cksum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24));
cksum ^= EndGetI32(data);
}
switch (bytes & 3) {

View file

@ -1,5 +1,5 @@
/* This file is part of libmspack.
* (C) 2003-2004 Stuart Caie.
* (C) 2003-2023 Stuart Caie.
*
* libmspack is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
@ -104,7 +104,8 @@ struct mschm_compressor_p {
/* CHM decompression definitions */
struct mschmd_decompress_state {
struct mschmd_header *chm; /* CHM file being decompressed */
off_t offset; /* uncompressed offset within folder */
off_t length; /* uncompressed length of LZX stream */
off_t offset; /* uncompressed offset within stream */
off_t inoffset; /* offset in input file */
struct lzxd_stream *state; /* LZX decompressor state */
struct mspack_system sys; /* special I/O code for decompressor */

View file

@ -1,5 +1,5 @@
/* This file is part of libmspack.
* (C) 2003-2018 Stuart Caie.
* (C) 2003-2023 Stuart Caie.
*
* libmspack is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
@ -58,6 +58,8 @@ static int chmd_error(
static int read_off64(
off_t *var, unsigned char *mem, struct mspack_system *sys,
struct mspack_file *fh);
static off_t read_encint(
const unsigned char **p, const unsigned char *end, int *err);
/* filenames of the system files used for decompression.
* Content and ControlData are essential.
@ -249,24 +251,15 @@ static const unsigned char guids[32] = {
0x9E, 0x0C, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEC
};
/* reads an encoded integer into a variable; 7 bits of data per byte,
* the high bit is used to indicate that there is another byte */
#define READ_ENCINT(var) do { \
(var) = 0; \
do { \
if (p >= end) goto chunk_end; \
(var) = ((var) << 7) | (*p & 0x7F); \
} while (*p++ & 0x80); \
} while (0)
static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
struct mschmd_header *chm, int entire)
{
unsigned int section, name_len, x, errors, num_chunks;
unsigned char buf[0x54], *chunk = NULL, *name, *p, *end;
unsigned int errors, num_chunks;
unsigned char buf[0x54], *chunk = NULL;
const unsigned char *name, *p, *end;
struct mschmd_file *fi, *link = NULL;
off_t offset, length;
int num_entries;
off_t offset_hs0, filelen;
int num_entries, err = 0;
/* initialise pointers */
chm->files = NULL;
@ -312,7 +305,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
/* chmhst3_OffsetCS0 does not exist in version 1 or 2 CHM files.
* The offset will be corrected later, once HS1 is read.
*/
if (read_off64(&offset, &buf[chmhst_OffsetHS0], sys, fh) ||
if (read_off64(&offset_hs0, &buf[chmhst_OffsetHS0], sys, fh) ||
read_off64(&chm->dir_offset, &buf[chmhst_OffsetHS1], sys, fh) ||
read_off64(&chm->sec0.offset, &buf[chmhst3_OffsetCS0], sys, fh))
{
@ -320,7 +313,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
}
/* seek to header section 0 */
if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
if (sys->seek(fh, offset_hs0, MSPACK_SYS_SEEK_START)) {
return MSPACK_ERR_SEEK;
}
@ -332,6 +325,18 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
return MSPACK_ERR_DATAFORMAT;
}
/* compare declared CHM file size against actual size */
if (!mspack_sys_filelen(sys, fh, &filelen)) {
if (chm->length > filelen) {
sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes",
chm->length - filelen);
}
else if (chm->length < filelen) {
sys->message(fh, "WARNING; possible %" LD " extra bytes at end of file",
filelen - chm->length);
}
}
/* seek to header section 1 */
if (sys->seek(fh, chm->dir_offset, MSPACK_SYS_SEEK_START)) {
return MSPACK_ERR_SEEK;
@ -412,12 +417,13 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
}
/* seek to the first PMGL chunk, and reduce the number of chunks to read */
if ((x = chm->first_pmgl) != 0) {
if (sys->seek(fh,(off_t) (x * chm->chunk_size), MSPACK_SYS_SEEK_CUR)) {
if (chm->first_pmgl != 0) {
off_t pmgl_offset = (off_t) chm->first_pmgl * (off_t) chm->chunk_size;
if (sys->seek(fh, pmgl_offset, MSPACK_SYS_SEEK_CUR)) {
return MSPACK_ERR_SEEK;
}
}
num_chunks = chm->last_pmgl - x + 1;
num_chunks = chm->last_pmgl - chm->first_pmgl + 1;
if (!(chunk = (unsigned char *) sys->alloc(sys, (size_t)chm->chunk_size))) {
return MSPACK_ERR_NOMEMORY;
@ -449,12 +455,15 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
num_entries = EndGetI16(end);
while (num_entries--) {
READ_ENCINT(name_len);
if (name_len > (unsigned int) (end - p)) goto chunk_end;
unsigned int name_len, section;
off_t offset, length;
name_len = read_encint(&p, end, &err);
if (err || (name_len > (unsigned int) (end - p))) goto encint_err;
name = p; p += name_len;
READ_ENCINT(section);
READ_ENCINT(offset);
READ_ENCINT(length);
section = read_encint(&p, end, &err);
offset = read_encint(&p, end, &err);
length = read_encint(&p, end, &err);
if (err) goto encint_err;
/* ignore blank or one-char (e.g. "/") filenames we'd return as blank */
if (name_len < 2 || !name[0] || !name[1]) continue;
@ -482,7 +491,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
: (struct mschmd_section *) (&chm->sec1));
fi->offset = offset;
fi->length = length;
sys->copy(name, fi->filename, (size_t) name_len);
sys->copy((unsigned char *) name, fi->filename, (size_t) name_len);
fi->filename[name_len] = '\0';
if (name[0] == ':' && name[1] == ':') {
@ -510,10 +519,10 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
}
/* this is reached either when num_entries runs out, or if
* reading data from the chunk reached a premature end of chunk */
chunk_end:
* an ENCINT is badly encoded */
encint_err:
if (num_entries >= 0) {
D(("chunk ended before all entries could be read"))
D(("bad encint before all entries could be read"))
errors++;
}
@ -572,7 +581,10 @@ static int chmd_fast_find(struct mschm_decompressor *base,
}
/* found result. loop around for next chunk if this is PMGI */
if (chunk[3] == 0x4C) break; else READ_ENCINT(n);
if (chunk[3] == 0x4C) break;
n = read_encint(&p, end, &err);
if (err) goto encint_err;
}
}
else {
@ -599,11 +611,12 @@ static int chmd_fast_find(struct mschm_decompressor *base,
/* if we found a file, read it */
if (result > 0) {
READ_ENCINT(sec);
sec = read_encint(&p, end, &err);
f_ptr->section = (sec == 0) ? (struct mschmd_section *) &chm->sec0
: (struct mschmd_section *) &chm->sec1;
READ_ENCINT(f_ptr->offset);
READ_ENCINT(f_ptr->length);
f_ptr->offset = read_encint(&p, end, &err);
f_ptr->length = read_encint(&p, end, &err);
if (err) goto encint_err;
}
else if (result < 0) {
err = MSPACK_ERR_DATAFORMAT;
@ -612,8 +625,8 @@ static int chmd_fast_find(struct mschm_decompressor *base,
sys->close(fh);
return self->error = err;
chunk_end:
D(("read beyond end of chunk entries"))
encint_err:
D(("bad encint in PGMI/PGML chunk"))
sys->close(fh);
return self->error = MSPACK_ERR_DATAFORMAT;
}
@ -697,7 +710,7 @@ static int search_chunk(struct mschmd_header *chm,
const unsigned char *start, *end, *p;
unsigned int qr_size, num_entries, qr_entries, qr_density, name_len;
unsigned int L, R, M, fname_len, entries_off, is_pmgl;
int cmp;
int cmp, err = 0;
fname_len = strlen(filename);
@ -755,8 +768,8 @@ static int search_chunk(struct mschmd_header *chm,
/* compare filename with entry QR points to */
p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
READ_ENCINT(name_len);
if (name_len > (unsigned int) (end - p)) goto chunk_end;
name_len = read_encint(&p, end, &err);
if (err || (name_len > (unsigned int) (end - p))) goto encint_err;
cmp = compare(filename, (char *)p, fname_len, name_len);
if (cmp == 0) break;
@ -792,8 +805,8 @@ static int search_chunk(struct mschmd_header *chm,
*/
*result = NULL;
while (num_entries-- > 0) {
READ_ENCINT(name_len);
if (name_len > (unsigned int) (end - p)) goto chunk_end;
name_len = read_encint(&p, end, &err);
if (err || (name_len > (unsigned int) (end - p))) goto encint_err;
cmp = compare(filename, (char *)p, fname_len, name_len);
p += name_len;
@ -810,21 +823,21 @@ static int search_chunk(struct mschmd_header *chm,
/* read and ignore the rest of this entry */
if (is_pmgl) {
READ_ENCINT(R); /* skip section */
READ_ENCINT(R); /* skip offset */
READ_ENCINT(R); /* skip length */
while (p < end && (*p++ & 0x80)); /* skip section ENCINT */
while (p < end && (*p++ & 0x80)); /* skip offset ENCINT */
while (p < end && (*p++ & 0x80)); /* skip length ENCINT */
}
else {
*result = p; /* store potential final result */
READ_ENCINT(R); /* skip chunk number */
while (p < end && (*p++ & 0x80)); /* skip chunk number ENCINT */
}
}
/* PMGL? not found. PMGI? maybe found */
return (is_pmgl) ? 0 : (*result ? 1 : 0);
chunk_end:
D(("reached end of chunk data while searching"))
encint_err:
D(("bad encint while searching"))
return -1;
}
@ -938,14 +951,19 @@ static int chmd_extract(struct mschm_decompressor *base,
switch (file->section->id) {
case 0: /* Uncompressed section file */
/* simple seek + copy */
if (sys->seek(self->d->infh, file->section->chm->sec0.offset
+ file->offset, MSPACK_SYS_SEEK_START))
if (sys->seek(self->d->infh, chm->sec0.offset + file->offset,
MSPACK_SYS_SEEK_START))
{
self->error = MSPACK_ERR_SEEK;
}
else {
unsigned char buf[512];
off_t length = file->length;
off_t maxlen = chm->length - sys->tell(self->d->infh);
if (length > maxlen) {
sys->message(fh, "WARNING; file is %" LD " bytes longer than CHM file",
length - maxlen);
}
while (length > 0) {
int run = sizeof(buf);
if ((off_t)run > length) run = (int)length;
@ -963,7 +981,7 @@ static int chmd_extract(struct mschm_decompressor *base,
break;
case 1: /* MSCompressed section file */
/* (re)initialise compression state if we it is not yet initialised,
/* (re)initialise compression state if not yet initialised,
* or we have advanced too far and have to backtrack
*/
if (!self->d->state || (file->offset < self->d->offset)) {
@ -974,6 +992,12 @@ static int chmd_extract(struct mschm_decompressor *base,
if (chmd_init_decomp(self, file)) break;
}
/* check file offset is not impossible */
if (file->offset > self->d->length) {
self->error = MSPACK_ERR_DECRUNCH;
break;
}
/* seek to input data */
if (sys->seek(self->d->infh, self->d->inoffset, MSPACK_SYS_SEEK_START)) {
self->error = MSPACK_ERR_SEEK;
@ -988,8 +1012,15 @@ static int chmd_extract(struct mschm_decompressor *base,
/* if getting to the correct offset was error free, unpack file */
if (!self->error) {
off_t length = file->length;
off_t maxlen = self->d->length - file->offset;
if (length > maxlen) {
sys->message(fh, "WARNING; file is %" LD " bytes longer than "
"compressed section", length - maxlen);
length = maxlen + 1; /* should decompress but still error out */
}
self->d->outfh = fh;
self->error = lzxd_decompress(self->d->state, file->length);
self->error = lzxd_decompress(self->d->state, length);
}
/* save offset in input source stream, in case there is a section 0
@ -1052,8 +1083,8 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
if (err) return self->error = err;
/* read ControlData */
if (sec->control->length < lzxcd_SIZEOF) {
D(("ControlData file is too short"))
if (sec->control->length != lzxcd_SIZEOF) {
D(("ControlData file is wrong size"))
return self->error = MSPACK_ERR_DATAFORMAT;
}
if (!(data = read_sys_file(self, sec->control))) {
@ -1125,8 +1156,8 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
entry = 0;
offset = 0;
err = read_spaninfo(self, sec, &length);
}
if (err) return self->error = err;
}
/* get offset of compressed data stream:
* = offset of uncompressed section from start of file
@ -1136,6 +1167,7 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
/* set start offset and overall remaining stream length */
self->d->offset = entry * LZX_FRAME_SIZE;
self->d->length = length;
length -= self->d->offset;
/* initialise LZX stream */
@ -1172,6 +1204,11 @@ static int read_reset_table(struct mschm_decompressor_p *self,
D(("ResetTable file is too short"))
return 0;
}
if (sec->rtable->length > 1000000) { /* arbitrary upper limit */
D(("ResetTable >1MB (%"LD"), report if genuine", sec->rtable->length))
return 0;
}
if (!(data = read_sys_file(self, sec->rtable))) {
D(("can't read reset table"))
return 0;
@ -1246,6 +1283,12 @@ static int read_spaninfo(struct mschm_decompressor_p *self,
return MSPACK_ERR_DATAFORMAT;
}
/* unconditionally set length here, because gcc -Wuninitialized isn't
* clever enough to recognise that read_sys_file() will always set
* self->error to a non-zero value if it returns NULL, and gcc warnings
* spook humans (even false positives) */
*length_ptr = 0;
/* read the SpanInfo file */
if (!(data = read_sys_file(self, sec->spaninfo))) {
D(("can't read SpanInfo file"))
@ -1364,14 +1407,51 @@ static int chmd_error(struct mschm_decompressor *base) {
static int read_off64(off_t *var, unsigned char *mem,
struct mspack_system *sys, struct mspack_file *fh)
{
#if LARGEFILE_SUPPORT
#if SIZEOF_OFF_T >= 8
*var = EndGetI64(mem);
#else
*var = EndGetI32(mem);
if ((*var & 0x80000000) || EndGetI32(mem+4)) {
sys->message(fh, (char *)largefile_msg);
if ((mem[3] & 0x80) | mem[4] | mem[5] | mem[6] | mem[7]) {
sys->message(fh, "library not compiled to support large files.");
return 1;
}
*var = EndGetI32(mem);
#endif
return 0;
}
#if SIZEOF_OFF_T >= 8
/* 63 bits allowed: 9 * 7 bits/byte, last byte must be 0x00-0x7F */
# define ENCINT_MAX_BYTES 9
# define ENCINT_BAD_LAST_BYTE 0x80
#else
/* 31 bits allowed: 5 * 7 bits/byte, last byte must be 0x00-0x07 */
# define ENCINT_MAX_BYTES 5
# define ENCINT_BAD_LAST_BYTE 0xF1
#endif
/***************************************
* READ_ENCINT
***************************************
* Reads an ENCINT from memory. If running on a system with a 32-bit off_t,
* ENCINTs up to 0x7FFFFFFF are accepted, values beyond that are an error.
*/
static off_t read_encint(const unsigned char **p, const unsigned char *end,
int *err)
{
off_t result = 0;
unsigned char c = 0x80;
int i = 0;
while ((c & 0x80) && (i++ < ENCINT_MAX_BYTES)) {
if (*p >= end) {
*err = 1;
return 0;
}
c = *(*p)++;
result = (result << 7) | (c & 0x7F);
}
if (i == ENCINT_MAX_BYTES && (c & ENCINT_BAD_LAST_BYTE)) {
*err = 1;
return 0;
}
return result;
}

View file

@ -1,5 +1,5 @@
/* This file is part of libmspack.
* (C) 2003-2011 Stuart Caie.
* (C) 2003-2023 Stuart Caie.
*
* KWAJ is a format very similar to SZDD. KWAJ method 3 (LZH) was
* written by Jeff Johnson.
@ -97,27 +97,30 @@ static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base,
struct mskwajd_header *hdr;
struct mspack_system *sys;
struct mspack_file *fh;
int err;
if (!self) return NULL;
sys = self->system;
fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
if (!fh) {
self->error = MSPACK_ERR_OPEN;
return NULL;
}
hdr = (struct mskwajd_header *) sys->alloc(sys, sizeof(struct mskwajd_header_p));
if (fh && hdr) {
if (!hdr) {
sys->close(fh);
self->error = MSPACK_ERR_NOMEMORY;
return NULL;
}
((struct mskwajd_header_p *) hdr)->fh = fh;
self->error = kwajd_read_headers(sys, fh, hdr);
if ((err = kwajd_read_headers(sys, fh, hdr))) {
kwajd_close(base, hdr);
self->error = err;
return NULL;
}
else {
if (!fh) self->error = MSPACK_ERR_OPEN;
if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
}
if (self->error) {
if (fh) sys->close(fh);
sys->free(hdr);
hdr = NULL;
}
return hdr;
}
@ -138,6 +141,8 @@ static void kwajd_close(struct mskwaj_decompressor *base,
self->system->close(hdr_p->fh);
/* free the memory associated */
self->system->free(hdr->filename);
self->system->free(hdr->extra);
self->system->free(hdr);
self->error = MSPACK_ERR_OK;
@ -200,7 +205,7 @@ static int kwajd_read_headers(struct mspack_system *sys,
if (hdr->headers & (MSKWAJ_HDR_HASFILENAME | MSKWAJ_HDR_HASFILEEXT)) {
int len;
/* allocate memory for maximum length filename */
char *fn = (char *) sys->alloc(sys, (size_t) 13);
char *fn = (char *) sys->alloc(sys, 13);
if (!(hdr->filename = fn)) return MSPACK_ERR_NOMEMORY;
/* copy filename if present */
@ -236,7 +241,7 @@ static int kwajd_read_headers(struct mspack_system *sys,
if (hdr->headers & MSKWAJ_HDR_HASEXTRATEXT) {
if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
i = EndGetI16(&buf[0]);
hdr->extra = (char *) sys->alloc(sys, (size_t)i+1);
hdr->extra = (char *) sys->alloc(sys, i+1);
if (! hdr->extra) return MSPACK_ERR_NOMEMORY;
if (sys->read(fh, hdr->extra, i) != i) return MSPACK_ERR_READ;
hdr->extra[i] = '\0';
@ -280,7 +285,7 @@ static int kwajd_extract(struct mskwaj_decompressor *base,
hdr->comp_type == MSKWAJ_COMP_XOR)
{
/* NONE is a straight copy. XOR is a copy xored with 0xFF */
unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) KWAJ_INPUT_SIZE);
unsigned char *buf = (unsigned char *) sys->alloc(sys, KWAJ_INPUT_SIZE);
if (buf) {
int read, i;
while ((read = sys->read(fh, buf, KWAJ_INPUT_SIZE)) > 0) {
@ -301,7 +306,7 @@ static int kwajd_extract(struct mskwaj_decompressor *base,
}
else if (hdr->comp_type == MSKWAJ_COMP_SZDD) {
self->error = lzss_decompress(sys, fh, outfh, KWAJ_INPUT_SIZE,
LZSS_MODE_EXPAND);
LZSS_MODE_QBASIC);
}
else if (hdr->comp_type == MSKWAJ_COMP_LZH) {
struct kwajd_stream *lzh = lzh_init(sys, fh, outfh);
@ -435,17 +440,14 @@ static struct kwajd_stream *lzh_init(struct mspack_system *sys,
static int lzh_decompress(struct kwajd_stream *lzh)
{
register unsigned int bit_buffer;
register int bits_left, i;
register unsigned short sym;
unsigned char *i_ptr, *i_end, lit_run = 0;
int j, pos = 0, len, offset, err;
unsigned int types[6];
DECLARE_HUFF_VARS;
unsigned int types[6], i, j, pos = 0, len, offset, lit_run = 0;
int err;
/* reset global state */
INIT_BITS;
RESTORE_BITS;
memset(&lzh->window[0], LZSS_WINDOW_FILL, (size_t) LZSS_WINDOW_SIZE);
memset(&lzh->window[0], LZSS_WINDOW_FILL, LZSS_WINDOW_SIZE);
/* read 6 encoding types (for byte alignment) but only 5 are needed */
for (i = 0; i < 6; i++) READ_BITS_SAFE(types[i], 4);
@ -501,9 +503,7 @@ static int lzh_read_lens(struct kwajd_stream *lzh,
unsigned int type, unsigned int numsyms,
unsigned char *lens)
{
register unsigned int bit_buffer;
register int bits_left;
unsigned char *i_ptr, *i_end;
DECLARE_BIT_VARS;
unsigned int i, c, sel;
int err;

View file

@ -67,7 +67,6 @@ struct lzxd_stream {
unsigned int block_remaining; /* uncompressed bytes still left to decode */
signed int intel_filesize; /* magic header value used for transform */
signed int intel_curpos; /* current offset in transform space */
unsigned char intel_started; /* has intel E8 decoding started? */
unsigned char block_type; /* type of the current block */

View file

@ -1,5 +1,5 @@
/* This file is part of libmspack.
* (C) 2003-2013 Stuart Caie.
* (C) 2003-2023 Stuart Caie.
*
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
* by Microsoft Corporation.
@ -138,12 +138,7 @@
static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens,
unsigned int first, unsigned int last)
{
/* bit buffer and huffman symbol decode variables */
register unsigned int bit_buffer;
register int bits_left, i;
register unsigned short sym;
unsigned char *i_ptr, *i_end;
DECLARE_HUFF_VARS;
unsigned int x, y;
int z;
@ -315,8 +310,8 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system,
}
/* allocate decompression window and input buffer */
lzx->window = (unsigned char *) system->alloc(system, (size_t) window_size);
lzx->inbuf = (unsigned char *) system->alloc(system, (size_t) input_buffer_size);
lzx->window = (unsigned char *) system->alloc(system, window_size);
lzx->inbuf = (unsigned char *) system->alloc(system, input_buffer_size);
if (!lzx->window || !lzx->inbuf) {
system->free(lzx->window);
system->free(lzx->inbuf);
@ -339,7 +334,6 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system,
lzx->frame = 0;
lzx->reset_interval = reset_interval;
lzx->intel_filesize = 0;
lzx->intel_curpos = 0;
lzx->intel_started = 0;
lzx->error = MSPACK_ERR_OK;
lzx->num_offsets = position_slots[window_bits - 15] << 3;
@ -392,17 +386,10 @@ void lzxd_set_output_length(struct lzxd_stream *lzx, off_t out_bytes) {
}
int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* bitstream and huffman reading variables */
register unsigned int bit_buffer;
register int bits_left, i=0;
unsigned char *i_ptr, *i_end;
register unsigned short sym;
int match_length, length_footer, extra, verbatim_bits, bytes_todo;
int this_run, main_element, aligned_bits, j, warned = 0;
unsigned char *window, *runsrc, *rundest, buf[12];
unsigned int frame_size=0, end_frame, match_offset, window_posn;
unsigned int R0, R1, R2;
DECLARE_HUFF_VARS;
unsigned char *window, *runsrc, *rundest, buf[12], warned = 0;
unsigned int frame_size, end_frame, window_posn, R0, R1, R2;
int bytes_todo, this_run, i, j;
/* easy answers */
if (!lzx || (out_bytes < 0)) return MSPACK_ERR_ARGS;
@ -524,9 +511,9 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
READ_IF_NEEDED;
*rundest++ = *i_ptr++;
}
R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
R1 = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24);
R2 = buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24);
R0 = EndGetI32(&buf[0]);
R1 = EndGetI32(&buf[4]);
R2 = EndGetI32(&buf[8]);
break;
default:
@ -546,111 +533,12 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* decode at least this_run bytes */
switch (lzx->block_type) {
case LZX_BLOCKTYPE_ALIGNED:
case LZX_BLOCKTYPE_VERBATIM:
while (this_run > 0) {
READ_HUFFSYM(MAINTREE, main_element);
if (main_element < LZX_NUM_CHARS) {
/* literal: 0 to LZX_NUM_CHARS-1 */
window[window_posn++] = main_element;
this_run--;
}
else {
/* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
main_element -= LZX_NUM_CHARS;
/* get match length */
match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
if (lzx->LENGTH_empty) {
D(("LENGTH symbol needed but tree is empty"))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
READ_HUFFSYM(LENGTH, length_footer);
match_length += length_footer;
}
match_length += LZX_MIN_MATCH;
/* get match offset */
switch ((match_offset = (main_element >> 3))) {
case 0: match_offset = R0; break;
case 1: match_offset = R1; R1=R0; R0 = match_offset; break;
case 2: match_offset = R2; R2=R0; R0 = match_offset; break;
case 3: match_offset = 1; R2=R1; R1=R0; R0 = match_offset; break;
default:
extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
READ_BITS(verbatim_bits, extra);
match_offset = position_base[match_offset] - 2 + verbatim_bits;
R2 = R1; R1 = R0; R0 = match_offset;
}
/* LZX DELTA uses max match length to signal even longer match */
if (match_length == LZX_MAX_MATCH && lzx->is_delta) {
int extra_len = 0;
ENSURE_BITS(3); /* 4 entry huffman tree */
if (PEEK_BITS(1) == 0) {
REMOVE_BITS(1); /* '0' -> 8 extra length bits */
READ_BITS(extra_len, 8);
}
else if (PEEK_BITS(2) == 2) {
REMOVE_BITS(2); /* '10' -> 10 extra length bits + 0x100 */
READ_BITS(extra_len, 10);
extra_len += 0x100;
}
else if (PEEK_BITS(3) == 6) {
REMOVE_BITS(3); /* '110' -> 12 extra length bits + 0x500 */
READ_BITS(extra_len, 12);
extra_len += 0x500;
}
else {
REMOVE_BITS(3); /* '111' -> 15 extra length bits */
READ_BITS(extra_len, 15);
}
match_length += extra_len;
}
if ((window_posn + match_length) > lzx->window_size) {
D(("match ran over window wrap"))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
/* copy match */
rundest = &window[window_posn];
i = match_length;
/* does match offset wrap the window? */
if (match_offset > window_posn) {
if (match_offset > lzx->offset &&
(match_offset - window_posn) > lzx->ref_data_size)
{
D(("match offset beyond LZX stream"))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
/* j = length from match offset to end of window */
j = match_offset - window_posn;
if (j > (int) lzx->window_size) {
D(("match offset beyond window boundaries"))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
runsrc = &window[lzx->window_size - j];
if (j < i) {
/* if match goes over the window edge, do two copy runs */
i -= j; while (j-- > 0) *rundest++ = *runsrc++;
runsrc = window;
}
while (i-- > 0) *rundest++ = *runsrc++;
}
else {
runsrc = rundest - match_offset;
while (i-- > 0) *rundest++ = *runsrc++;
}
this_run -= match_length;
window_posn += match_length;
}
} /* while (this_run > 0) */
break;
case LZX_BLOCKTYPE_ALIGNED:
while (this_run > 0) {
int main_element, length_footer, verbatim_bits, aligned_bits, extra;
int match_length;
unsigned int match_offset;
READ_HUFFSYM(MAINTREE, main_element);
if (main_element < LZX_NUM_CHARS) {
/* literal: 0 to LZX_NUM_CHARS-1 */
@ -681,28 +569,18 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
default:
extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
match_offset = position_base[match_offset] - 2;
if (extra >= 3 && lzx->block_type == LZX_BLOCKTYPE_ALIGNED) {
if (extra > 3) {
/* verbatim and aligned bits */
extra -= 3;
READ_BITS(verbatim_bits, extra);
match_offset += (verbatim_bits << 3);
READ_BITS(verbatim_bits, extra - 3); /* 1-14 bits */
match_offset += verbatim_bits << 3;
}
READ_HUFFSYM(ALIGNED, aligned_bits);
match_offset += aligned_bits;
}
else if (extra == 3) {
/* aligned bits only */
READ_HUFFSYM(ALIGNED, aligned_bits);
match_offset += aligned_bits;
}
else if (extra > 0) { /* extra==1, extra==2 */
/* verbatim bits only */
READ_BITS(verbatim_bits, extra);
else if (extra) {
READ_BITS(verbatim_bits, extra); /* 1-17 bits */
match_offset += verbatim_bits;
}
else /* extra == 0 */ {
/* ??? not defined in LZX specification! */
match_offset = 1;
}
/* update repeated offset LRU queue */
R2 = R1; R1 = R0; R0 = match_offset;
}
@ -742,7 +620,7 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
i = match_length;
/* does match offset wrap the window? */
if (match_offset > window_posn) {
if (match_offset > lzx->offset &&
if ((off_t)match_offset > lzx->offset &&
(match_offset - window_posn) > lzx->ref_data_size)
{
D(("match offset beyond LZX stream"))
@ -784,7 +662,7 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
}
else {
if (i > this_run) i = this_run;
lzx->sys->copy(i_ptr, rundest, (size_t) i);
lzx->sys->copy(i_ptr, rundest, i);
rundest += i;
i_ptr += i;
this_run -= i;
@ -827,11 +705,11 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* does this intel block _really_ need decoding? */
if (lzx->intel_started && lzx->intel_filesize &&
(lzx->frame <= 32768) && (frame_size > 10))
(lzx->frame < 32768) && (frame_size > 10))
{
unsigned char *data = &lzx->e8_buf[0];
unsigned char *dataend = &lzx->e8_buf[frame_size - 10];
signed int curpos = lzx->intel_curpos;
signed int curpos = (int) lzx->offset;
signed int filesize = lzx->intel_filesize;
signed int abs_off, rel_off;
@ -841,7 +719,7 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
while (data < dataend) {
if (*data++ != 0xE8) { curpos++; continue; }
abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
abs_off = EndGetI32(data);
if ((abs_off >= -curpos) && (abs_off < filesize)) {
rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
data[0] = (unsigned char) rel_off;
@ -852,11 +730,9 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
data += 4;
curpos += 5;
}
lzx->intel_curpos += frame_size;
}
else {
lzx->o_ptr = &lzx->window[lzx->frame_posn];
if (lzx->intel_filesize) lzx->intel_curpos += frame_size;
}
lzx->o_end = &lzx->o_ptr[frame_size];

View file

@ -1,5 +1,5 @@
/* This file is part of libmspack.
* (C) 2003-2010 Stuart Caie.
* (C) 2003-2023 Stuart Caie.
*
* The deflate method was created by Phil Katz. MSZIP is equivalent to the
* deflate method.
@ -89,10 +89,7 @@ static const unsigned char bitlen_order[19] = {
#define INF_ERR_HUFFSYM (-14) /* out of bits decoding huffman symbol */
static int zip_read_lens(struct mszipd_stream *zip) {
/* for the bit buffer and huffman decoding */
register unsigned int bit_buffer;
register int bits_left;
unsigned char *i_ptr, *i_end;
DECLARE_BIT_VARS;
/* bitlen Huffman codes -- immediate lookup, 7 bit max code length */
unsigned short bl_table[(1 << 7)];
@ -155,13 +152,9 @@ static int zip_read_lens(struct mszipd_stream *zip) {
/* a clean implementation of RFC 1951 / inflate */
static int inflate(struct mszipd_stream *zip) {
unsigned int last_block, block_type, distance, length, this_run, i;
/* for the bit buffer and huffman decoding */
register unsigned int bit_buffer;
register int bits_left;
register unsigned short sym;
unsigned char *i_ptr, *i_end;
DECLARE_HUFF_VARS;
unsigned int last_block, block_type, distance, length, this_run;
int i;
RESTORE_BITS;
@ -359,7 +352,7 @@ struct mszipd_stream *mszipd_init(struct mspack_system *system,
}
/* allocate input buffer */
zip->inbuf = (unsigned char *) system->alloc(system, (size_t) input_buffer_size);
zip->inbuf = (unsigned char *) system->alloc(system, input_buffer_size);
if (!zip->inbuf) {
system->free(zip);
return NULL;
@ -467,11 +460,7 @@ int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes) {
}
int mszipd_decompress_kwaj(struct mszipd_stream *zip) {
/* for the bit buffer */
register unsigned int bit_buffer;
register int bits_left;
unsigned char *i_ptr, *i_end;
DECLARE_BIT_VARS;
int i, error, block_len;
/* unpack blocks until block_len == 0 */

View file

@ -1,5 +1,5 @@
/* This file is part of libmspack.
* (C) 2003-2004 Stuart Caie.
* (C) 2003-2023 Stuart Caie.
*
* The Quantum method was created by David Stafford, adapted by Microsoft
* Corporation.
@ -254,14 +254,12 @@ struct qtmd_stream *qtmd_init(struct mspack_system *system,
}
int qtmd_decompress(struct qtmd_stream *qtm, off_t out_bytes) {
DECLARE_BIT_VARS;
unsigned int frame_todo, frame_end, window_posn, match_offset, range;
unsigned char *window, *i_ptr, *i_end, *runsrc, *rundest;
unsigned char *window, *runsrc, *rundest;
int i, j, selector, extra, sym, match_length;
unsigned short H, L, C, symf;
register unsigned int bit_buffer;
register unsigned char bits_left;
/* easy answers */
if (!qtm || (out_bytes < 0)) return MSPACK_ERR_ARGS;
if (qtm->error) return qtm->error;

View file

@ -13,6 +13,7 @@
/* this header defines macros that read data streams by
* the individual bits
*
* DECLARE_BIT_VARS declares local variables
* INIT_BITS initialises bitstream state in state structure
* STORE_BITS stores bitstream state in state structure
* RESTORE_BITS restores bitstream state from state structure
@ -92,13 +93,20 @@
# endif
#endif
typedef unsigned int bitbuf_type;
#if HAVE_LIMITS_H
# include <limits.h>
#endif
#ifndef CHAR_BIT
# define CHAR_BIT (8)
#endif
#define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT)
#define BITBUF_WIDTH (sizeof(bitbuf_type) * CHAR_BIT)
#define DECLARE_BIT_VARS \
unsigned char *i_ptr, *i_end; \
register bitbuf_type bit_buffer; \
register int bits_left
#define INIT_BITS do { \
BITS_VAR->i_ptr = &BITS_VAR->inbuf[0]; \
@ -136,7 +144,7 @@
unsigned char needed = (bits), bitrun; \
(val) = 0; \
while (needed > 0) { \
if (bits_left <= (BITBUF_WIDTH - 16)) READ_BYTES; \
if (bits_left <= (int)(BITBUF_WIDTH - 16)) READ_BYTES; \
bitrun = (bits_left < needed) ? bits_left : needed; \
(val) = ((val) << bitrun) | PEEK_BITS(bitrun); \
REMOVE_BITS(bitrun); \
@ -148,12 +156,13 @@
# define PEEK_BITS(nbits) (bit_buffer >> (BITBUF_WIDTH - (nbits)))
# define REMOVE_BITS(nbits) ((bit_buffer <<= (nbits)), (bits_left -= (nbits)))
# define INJECT_BITS(bitdata,nbits) ((bit_buffer |= \
(bitdata) << (BITBUF_WIDTH - (nbits) - bits_left)), (bits_left += (nbits)))
(bitbuf_type)(bitdata) << (BITBUF_WIDTH - (nbits) - bits_left)), \
(bits_left += (nbits)))
#else /* BITS_ORDER_LSB */
# define PEEK_BITS(nbits) (bit_buffer & ((1 << (nbits))-1))
# define PEEK_BITS(nbits) (bit_buffer & ((bitbuf_type)(1 << (nbits))-1))
# define REMOVE_BITS(nbits) ((bit_buffer >>= (nbits)), (bits_left -= (nbits)))
# define INJECT_BITS(bitdata,nbits) ((bit_buffer |= \
(bitdata) << bits_left), (bits_left += (nbits)))
(bitbuf_type)(bitdata) << bits_left), (bits_left += (nbits)))
#endif
#ifdef BITS_LSB_TABLE

View file

@ -28,35 +28,40 @@
# define HUFF_MAXBITS 16
#endif
#define DECLARE_HUFF_VARS \
DECLARE_BIT_VARS; \
register int huff_idx; \
register unsigned short huff_sym
/* Decodes the next huffman symbol from the input bitstream into var.
* Do not use this macro on a table unless build_decode_table() succeeded.
*/
#define READ_HUFFSYM(tbl, var) do { \
ENSURE_BITS(HUFF_MAXBITS); \
sym = HUFF_TABLE(tbl, PEEK_BITS(TABLEBITS(tbl))); \
if (sym >= MAXSYMBOLS(tbl)) HUFF_TRAVERSE(tbl); \
(var) = sym; \
i = HUFF_LEN(tbl, sym); \
REMOVE_BITS(i); \
huff_sym = HUFF_TABLE(tbl, PEEK_BITS(TABLEBITS(tbl))); \
if (huff_sym >= MAXSYMBOLS(tbl)) HUFF_TRAVERSE(tbl); \
(var) = huff_sym; \
huff_idx = HUFF_LEN(tbl, huff_sym); \
REMOVE_BITS(huff_idx); \
} while (0)
#ifdef BITS_ORDER_LSB
# define HUFF_TRAVERSE(tbl) do { \
i = TABLEBITS(tbl) - 1; \
huff_idx = TABLEBITS(tbl) - 1; \
do { \
if (i++ > HUFF_MAXBITS) HUFF_ERROR; \
sym = HUFF_TABLE(tbl, \
(sym << 1) | ((bit_buffer >> i) & 1)); \
} while (sym >= MAXSYMBOLS(tbl)); \
if (huff_idx++ > HUFF_MAXBITS) HUFF_ERROR; \
huff_sym = HUFF_TABLE(tbl, \
(huff_sym << 1) | ((bit_buffer >> huff_idx) & 1)); \
} while (huff_sym >= MAXSYMBOLS(tbl)); \
} while (0)
#else
#define HUFF_TRAVERSE(tbl) do { \
i = 1 << (BITBUF_WIDTH - TABLEBITS(tbl)); \
huff_idx = 1 << (BITBUF_WIDTH - TABLEBITS(tbl)); \
do { \
if ((i >>= 1) == 0) HUFF_ERROR; \
sym = HUFF_TABLE(tbl, \
(sym << 1) | ((bit_buffer & i) ? 1 : 0)); \
} while (sym >= MAXSYMBOLS(tbl)); \
if ((huff_idx >>= 1) == 0) HUFF_ERROR; \
huff_sym = HUFF_TABLE(tbl, \
(huff_sym << 1) | ((bit_buffer & huff_idx) ? 1 : 0)); \
} while (huff_sym >= MAXSYMBOLS(tbl)); \
} while (0)
#endif

View file

@ -13,11 +13,6 @@
#include "system-mspack.h"
#ifndef LARGEFILE_SUPPORT
const char *largefile_msg = "library not compiled to support large files.";
#endif
int mspack_version(int entity) {
switch (entity) {
/* CHM decoder version 1 -> 2 changes: