summaryrefslogtreecommitdiffstats
path: root/rbutil/rbutilqt
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/rbutilqt')
-rw-r--r--rbutil/rbutilqt/mspack/README.ROCKBOX4
-rw-r--r--rbutil/rbutilqt/mspack/cab.h27
-rw-r--r--rbutil/rbutilqt/mspack/cabd.c541
-rw-r--r--rbutil/rbutilqt/mspack/chmd.c667
-rw-r--r--rbutil/rbutilqt/mspack/kwajd.c365
-rw-r--r--rbutil/rbutilqt/mspack/lzss.h8
-rw-r--r--rbutil/rbutilqt/mspack/lzssd.c84
-rw-r--r--rbutil/rbutilqt/mspack/lzx.h61
-rw-r--r--rbutil/rbutilqt/mspack/lzxd.c793
-rw-r--r--rbutil/rbutilqt/mspack/mspack.h316
-rw-r--r--rbutil/rbutilqt/mspack/mszip.h17
-rw-r--r--rbutil/rbutilqt/mspack/mszipd.c268
-rw-r--r--rbutil/rbutilqt/mspack/qtm.h8
-rw-r--r--rbutil/rbutilqt/mspack/qtmd.c235
-rw-r--r--rbutil/rbutilqt/mspack/readbits.h104
-rw-r--r--rbutil/rbutilqt/mspack/readhuff.h129
-rw-r--r--rbutil/rbutilqt/mspack/system-mspack.c2
-rw-r--r--rbutil/rbutilqt/mspack/system-mspack.h4
-rw-r--r--rbutil/rbutilqt/mspack/szddd.c70
19 files changed, 2121 insertions, 1582 deletions
diff --git a/rbutil/rbutilqt/mspack/README.ROCKBOX b/rbutil/rbutilqt/mspack/README.ROCKBOX
index db5ba7f482..220691af2c 100644
--- a/rbutil/rbutilqt/mspack/README.ROCKBOX
+++ b/rbutil/rbutilqt/mspack/README.ROCKBOX
@@ -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.3alpha
-http://sourceforge.net/projects/libmspack/on January 28, 2013
+The source files have been last synced with libmspack-0.10.1alpha
+https://www.cabextract.org.uk/libmspack/ on June 8, 2020
diff --git a/rbutil/rbutilqt/mspack/cab.h b/rbutil/rbutilqt/mspack/cab.h
index 78ec8e60db..79d9951252 100644
--- a/rbutil/rbutilqt/mspack/cab.h
+++ b/rbutil/rbutilqt/mspack/cab.h
@@ -1,5 +1,5 @@
/* This file is part of libmspack.
- * (C) 2003-2004 Stuart Caie.
+ * (C) 2003-2018 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
@@ -10,10 +10,6 @@
#ifndef MSPACK_CAB_H
#define MSPACK_CAB_H 1
-#include "mszip.h"
-#include "qtm.h"
-#include "lzx.h"
-
/* generic CAB definitions */
/* structure offsets */
@@ -70,6 +66,22 @@
#define CAB_BLOCKMAX (32768)
#define CAB_INPUTMAX (CAB_BLOCKMAX+6144)
+/* input buffer needs to be CAB_INPUTMAX + 1 byte to allow for max-sized block
+ * plus 1 trailer byte added by cabd_sys_read_block() for Quantum alignment.
+ *
+ * When MSCABD_PARAM_SALVAGE is set, block size is not checked so can be
+ * up to 65535 bytes, so max input buffer size needed is 65535 + 1
+ */
+#define CAB_INPUTMAX_SALVAGE (65535)
+#define CAB_INPUTBUF (CAB_INPUTMAX_SALVAGE + 1)
+
+/* There are no more than 65535 data blocks per folder, so a folder cannot
+ * be more than 32768*65535 bytes in length. As files cannot span more than
+ * one folder, this is also their max offset, length and offset+length limit.
+ */
+#define CAB_FOLDERMAX (65535)
+#define CAB_LENGTHMAX (CAB_BLOCKMAX * CAB_FOLDERMAX)
+
/* CAB compression definitions */
struct mscab_compressor_p {
@@ -85,6 +97,7 @@ struct mscabd_decompress_state {
struct mscabd_folder_data *data; /* current folder split we're in */
unsigned int offset; /* uncompressed offset within folder */
unsigned int block; /* which block are we decompressing? */
+ off_t outlen; /* cumulative sum of block output sizes */
struct mspack_system sys; /* special I/O code for decompressor */
int comp_type; /* type of compression used by folder */
int (*decompress)(void *, off_t); /* decompressor code */
@@ -93,14 +106,14 @@ struct mscabd_decompress_state {
struct mspack_file *infh; /* input file handle */
struct mspack_file *outfh; /* output file handle */
unsigned char *i_ptr, *i_end; /* input data consumed, end */
- unsigned char input[CAB_INPUTMAX]; /* one input block of data */
+ unsigned char input[CAB_INPUTBUF]; /* one input block of data */
};
struct mscab_decompressor_p {
struct mscab_decompressor base;
struct mscabd_decompress_state *d;
struct mspack_system *system;
- int param[3]; /* !!! MATCH THIS TO NUM OF PARAMS IN MSPACK.H !!! */
+ int buf_size, searchbuf_size, fix_mszip, salvage; /* params */
int error, read_error;
};
diff --git a/rbutil/rbutilqt/mspack/cabd.c b/rbutil/rbutilqt/mspack/cabd.c
index 6549d7b8cf..ae66769b24 100644
--- a/rbutil/rbutilqt/mspack/cabd.c
+++ b/rbutil/rbutilqt/mspack/cabd.c
@@ -1,5 +1,5 @@
/* This file is part of libmspack.
- * (C) 2003-2011 Stuart Caie.
+ * (C) 2003-2018 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
@@ -23,7 +23,9 @@
#include "system-mspack.h"
#include "cab.h"
-#include <assert.h>
+#include "mszip.h"
+#include "lzx.h"
+#include "qtm.h"
/* Notes on compliance with cabinet specification:
*
@@ -72,10 +74,9 @@ static void cabd_close(
struct mscab_decompressor *base, struct mscabd_cabinet *origcab);
static int cabd_read_headers(
struct mspack_system *sys, struct mspack_file *fh,
- struct mscabd_cabinet_p *cab, off_t offset, int quiet);
+ 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,
- struct mscabd_cabinet_p *cab, int *error);
+ struct mspack_system *sys, struct mspack_file *fh, int *error);
static struct mscabd_cabinet *cabd_search(
struct mscab_decompressor *base, const char *filename);
@@ -110,7 +111,7 @@ static int cabd_sys_write(
struct mspack_file *file, void *buffer, int bytes);
static int cabd_sys_read_block(
struct mspack_system *sys, struct mscabd_decompress_state *d, int *out,
- int ignore_cksum);
+ int ignore_cksum, int ignore_blocksize);
static unsigned int cabd_checksum(
unsigned char *data, unsigned int bytes, unsigned int cksum);
static struct noned_state *noned_init(
@@ -155,9 +156,10 @@ struct mscab_decompressor *
self->d = NULL;
self->error = MSPACK_ERR_OK;
- self->param[MSCABD_PARAM_SEARCHBUF] = 32768;
- self->param[MSCABD_PARAM_FIXMSZIP] = 0;
- self->param[MSCABD_PARAM_DECOMPBUF] = 4096;
+ self->searchbuf_size = 32768;
+ self->fix_mszip = 0;
+ self->buf_size = 4096;
+ self->salvage = 0;
}
return (struct mscab_decompressor *) self;
}
@@ -171,9 +173,9 @@ void mspack_destroy_cab_decompressor(struct mscab_decompressor *base) {
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
if (self) {
struct mspack_system *sys = self->system;
- cabd_free_decomp(self);
if (self->d) {
if (self->d->infh) sys->close(self->d->infh);
+ cabd_free_decomp(self);
sys->free(self->d);
}
sys->free(self);
@@ -187,7 +189,7 @@ void mspack_destroy_cab_decompressor(struct mscab_decompressor *base) {
* opens a file and tries to read it as a cabinet file
*/
static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
- const char *filename)
+ const char *filename)
{
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
struct mscabd_cabinet_p *cab = NULL;
@@ -201,10 +203,10 @@ static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
if ((cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
cab->base.filename = filename;
- error = cabd_read_headers(sys, fh, cab, (off_t) 0, 0);
+ error = cabd_read_headers(sys, fh, cab, (off_t) 0, self->salvage, 0);
if (error) {
- cabd_close(base, (struct mscabd_cabinet *) cab);
- cab = NULL;
+ cabd_close(base, (struct mscabd_cabinet *) cab);
+ cab = NULL;
}
self->error = error;
}
@@ -225,7 +227,7 @@ static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
* frees all memory associated with a given mscabd_cabinet.
*/
static void cabd_close(struct mscab_decompressor *base,
- struct mscabd_cabinet *origcab)
+ struct mscabd_cabinet *origcab)
{
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
struct mscabd_folder_data *dat, *ndat;
@@ -253,16 +255,16 @@ static void cabd_close(struct mscab_decompressor *base,
/* free folder decompression state if it has been decompressed */
if (self->d && (self->d->folder == (struct mscabd_folder_p *) fol)) {
- if (self->d->infh) sys->close(self->d->infh);
- cabd_free_decomp(self);
- sys->free(self->d);
- self->d = NULL;
+ if (self->d->infh) sys->close(self->d->infh);
+ cabd_free_decomp(self);
+ sys->free(self->d);
+ self->d = NULL;
}
/* free folder data segments */
for (dat = ((struct mscabd_folder_p *)fol)->data.next; dat; dat = ndat) {
- ndat = dat->next;
- sys->free(dat);
+ ndat = dat->next;
+ sys->free(dat);
}
sys->free(fol);
}
@@ -304,11 +306,11 @@ static void cabd_close(struct mscab_decompressor *base,
* for folders and files as necessary
*/
static int cabd_read_headers(struct mspack_system *sys,
- struct mspack_file *fh,
- struct mscabd_cabinet_p *cab,
- off_t offset, int quiet)
+ struct mspack_file *fh,
+ struct mscabd_cabinet_p *cab,
+ off_t offset, int salvage, int quiet)
{
- int num_folders, num_files, folder_resv, i, x;
+ int num_folders, num_files, folder_resv, i, x, err, fidx;
struct mscabd_folder_p *fol, *linkfol = NULL;
struct mscabd_file *file, *linkfile = NULL;
unsigned char buf[64];
@@ -364,6 +366,7 @@ static int cabd_read_headers(struct mspack_system *sys,
/* read the reserved-sizes part of header, if present */
cab->base.flags = EndGetI16(&buf[cfhead_Flags]);
+
if (cab->base.flags & cfheadRESERVE_PRESENT) {
if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) {
return MSPACK_ERR_READ;
@@ -379,7 +382,7 @@ static int cabd_read_headers(struct mspack_system *sys,
/* skip the reserved header */
if (cab->base.header_resv) {
if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) {
- return MSPACK_ERR_SEEK;
+ return MSPACK_ERR_SEEK;
}
}
}
@@ -391,14 +394,18 @@ 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, cab, &x); if (x) return x;
- cab->base.previnfo = cabd_read_string(sys, fh, cab, &x); if (x) return x;
+ cab->base.prevname = cabd_read_string(sys, fh, &err);
+ if (err) return err;
+ cab->base.previnfo = cabd_read_string(sys, fh, &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, cab, &x); if (x) return x;
- cab->base.nextinfo = cabd_read_string(sys, fh, cab, &x); if (x) return x;
+ cab->base.nextname = cabd_read_string(sys, fh, &err);
+ if (err) return err;
+ cab->base.nextinfo = cabd_read_string(sys, fh, &err);
+ if (err) return err;
}
/* read folders */
@@ -408,7 +415,7 @@ static int cabd_read_headers(struct mspack_system *sys,
}
if (folder_resv) {
if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) {
- return MSPACK_ERR_SEEK;
+ return MSPACK_ERR_SEEK;
}
}
@@ -447,45 +454,44 @@ static int cabd_read_headers(struct mspack_system *sys,
file->offset = EndGetI32(&buf[cffile_FolderOffset]);
/* set folder pointer */
- x = EndGetI16(&buf[cffile_FolderIndex]);
- if (x < cffileCONTINUED_FROM_PREV) {
- /* normal folder index; count up to the correct folder. the folder
- * pointer will be NULL if folder index is invalid */
- struct mscabd_folder *ifol = cab->base.folders;
- while (x--) if (ifol) ifol = ifol->next;
- file->folder = ifol;
-
- if (!ifol) {
- sys->free(file);
- D(("invalid folder index"))
- return MSPACK_ERR_DATAFORMAT;
+ fidx = EndGetI16(&buf[cffile_FolderIndex]);
+ if (fidx < cffileCONTINUED_FROM_PREV) {
+ /* normal folder index; count up to the correct folder */
+ if (fidx < num_folders) {
+ struct mscabd_folder *ifol = cab->base.folders;
+ while (fidx--) if (ifol) ifol = ifol->next;
+ file->folder = ifol;
+ }
+ else {
+ D(("invalid folder index"))
+ file->folder = NULL;
}
}
else {
/* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or
* CONTINUED_PREV_AND_NEXT */
- if ((x == cffileCONTINUED_TO_NEXT) ||
- (x == cffileCONTINUED_PREV_AND_NEXT))
+ if ((fidx == cffileCONTINUED_TO_NEXT) ||
+ (fidx == cffileCONTINUED_PREV_AND_NEXT))
{
- /* get last folder */
- struct mscabd_folder *ifol = cab->base.folders;
- while (ifol->next) ifol = ifol->next;
- file->folder = ifol;
-
- /* set "merge next" pointer */
- fol = (struct mscabd_folder_p *) ifol;
- if (!fol->merge_next) fol->merge_next = file;
+ /* get last folder */
+ struct mscabd_folder *ifol = cab->base.folders;
+ while (ifol->next) ifol = ifol->next;
+ file->folder = ifol;
+
+ /* set "merge next" pointer */
+ fol = (struct mscabd_folder_p *) ifol;
+ if (!fol->merge_next) fol->merge_next = file;
}
- if ((x == cffileCONTINUED_FROM_PREV) ||
- (x == cffileCONTINUED_PREV_AND_NEXT))
+ if ((fidx == cffileCONTINUED_FROM_PREV) ||
+ (fidx == cffileCONTINUED_PREV_AND_NEXT))
{
- /* get first folder */
- file->folder = cab->base.folders;
+ /* get first folder */
+ file->folder = cab->base.folders;
- /* set "merge prev" pointer */
- fol = (struct mscabd_folder_p *) file->folder;
- if (!fol->merge_prev) fol->merge_prev = file;
+ /* set "merge prev" pointer */
+ fol = (struct mscabd_folder_p *) file->folder;
+ if (!fol->merge_prev) fol->merge_prev = file;
}
}
@@ -502,10 +508,14 @@ static int cabd_read_headers(struct mspack_system *sys,
file->date_y = (x >> 9) + 1980;
/* get filename */
- file->filename = cabd_read_string(sys, fh, cab, &x);
- if (x) {
+ file->filename = cabd_read_string(sys, fh, &err);
+
+ /* if folder index or filename are bad, either skip it or fail */
+ if (err || !file->folder) {
+ sys->free(file->filename);
sys->free(file);
- return x;
+ if (salvage) continue;
+ return err ? err : MSPACK_ERR_DATAFORMAT;
}
/* link file entry into file list */
@@ -514,23 +524,34 @@ static int cabd_read_headers(struct mspack_system *sys,
linkfile = file;
}
+ if (cab->base.files == NULL) {
+ /* We never actually added any files to the file list. Something went wrong.
+ * The file header may have been invalid */
+ D(("No files found, even though header claimed to have %d files", num_files))
+ return MSPACK_ERR_DATAFORMAT;
+ }
+
return MSPACK_ERR_OK;
}
static char *cabd_read_string(struct mspack_system *sys,
- struct mspack_file *fh,
- struct mscabd_cabinet_p *cab, int *error)
+ struct mspack_file *fh, int *error)
{
off_t base = sys->tell(fh);
char buf[256], *str;
- unsigned int len, i, ok;
- (void)cab;
+ int len, i, ok;
/* read up to 256 bytes */
- len = sys->read(fh, &buf[0], 256);
+ if ((len = sys->read(fh, &buf[0], 256)) <= 0) {
+ *error = MSPACK_ERR_READ;
+ return NULL;
+ }
/* 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;
+
if (!ok) {
*error = MSPACK_ERR_DATAFORMAT;
return NULL;
@@ -566,7 +587,7 @@ static char *cabd_read_string(struct mspack_system *sys,
* break out of the loop and be sure that all resources are freed
*/
static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
- const char *filename)
+ const char *filename)
{
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
struct mscabd_cabinet_p *cab = NULL;
@@ -579,7 +600,7 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
sys = self->system;
/* allocate a search buffer */
- search_buf = (unsigned char *) sys->alloc(sys, (size_t) self->param[MSCABD_PARAM_SEARCHBUF]);
+ search_buf = (unsigned char *) sys->alloc(sys, (size_t) self->searchbuf_size);
if (!search_buf) {
self->error = MSPACK_ERR_NOMEMORY;
return NULL;
@@ -589,21 +610,21 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
if (!(self->error = mspack_sys_filelen(sys, fh, &filelen))) {
self->error = cabd_find(self, search_buf, fh, filename,
- filelen, &firstlen, &cab);
+ filelen, &firstlen, &cab);
}
/* truncated / extraneous data warning: */
if (firstlen && (firstlen != filelen) &&
- (!cab || (cab->base.base_offset == 0)))
+ (!cab || (cab->base.base_offset == 0)))
{
if (firstlen < filelen) {
- sys->message(fh, "WARNING; possible %" LD
- " extra bytes at end of file.",
- filelen - firstlen);
+ sys->message(fh, "WARNING; possible %" LD
+ " extra bytes at end of file.",
+ filelen - firstlen);
}
else {
- sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.",
- firstlen - filelen);
+ sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.",
+ firstlen - filelen);
}
}
@@ -620,8 +641,8 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
}
static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
- struct mspack_file *fh, const char *filename, off_t flen,
- off_t *firstlen, struct mscabd_cabinet_p **firstcab)
+ struct mspack_file *fh, const char *filename, off_t flen,
+ off_t *firstlen, struct mscabd_cabinet_p **firstcab)
{
struct mscabd_cabinet_p *cab, *link = NULL;
off_t caboff, offset, length;
@@ -630,7 +651,7 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
unsigned int cablen_u32 = 0, foffset_u32 = 0;
int false_cabs = 0;
-#ifndef LARGEFILE_SUPPORT
+#if !LARGEFILE_SUPPORT
/* detect 32-bit off_t overflow */
if (flen < 0) {
sys->message(fh, largefile_msg);
@@ -643,8 +664,8 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
/* search length is either the full length of the search buffer, or the
* amount of data remaining to the end of the file, whichever is less. */
length = flen - offset;
- if (length > self->param[MSCABD_PARAM_SEARCHBUF]) {
- length = self->param[MSCABD_PARAM_SEARCHBUF];
+ if (length > self->searchbuf_size) {
+ length = self->searchbuf_size;
}
/* fill the search buffer with data from disk */
@@ -654,22 +675,21 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
/* FAQ avoidance strategy */
if ((offset == 0) && (EndGetI32(&buf[0]) == 0x28635349)) {
- sys->message(fh, "WARNING; found InstallShield header. "
- "This is probably an InstallShield file. "
- "Use UNSHIELD from www.synce.org to unpack it.");
+ sys->message(fh, "WARNING; found InstallShield header. Use unshield "
+ "(https://github.com/twogood/unshield) to unpack this file");
}
/* read through the entire buffer. */
for (p = &buf[0], pend = &buf[length]; p < pend; ) {
switch (state) {
- /* starting state */
+ /* starting state */
case 0:
- /* we spend most of our time in this while loop, looking for
- * a leading 'M' of the 'MSCF' signature */
- while (p < pend && *p != 0x4D) p++;
- /* if we found tht 'M', advance state */
- if (p++ < pend) state = 1;
- break;
+ /* we spend most of our time in this while loop, looking for
+ * a leading 'M' of the 'MSCF' signature */
+ while (p < pend && *p != 0x4D) p++;
+ /* if we found tht 'M', advance state */
+ if (p++ < pend) state = 1;
+ break;
/* verify that the next 3 bytes are 'S', 'C' and 'F' */
case 1: state = (*p++ == 0x53) ? 2 : 0; break;
@@ -691,70 +711,71 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
case 17: foffset_u32 |= *p++ << 8; state++; break;
case 18: foffset_u32 |= *p++ << 16; state++; break;
case 19: foffset_u32 |= *p++ << 24;
- /* now we have recieved 20 bytes of potential cab header. work out
- * the offset in the file of this potential cabinet */
- caboff = offset + (p - &buf[0]) - 20;
-
- /* should reading cabinet fail, restart search just after 'MSCF' */
- offset = caboff + 4;
-
- /* capture the "length of cabinet" field if there is a cabinet at
- * offset 0 in the file, regardless of whether the cabinet can be
- * read correctly or not */
- if (caboff == 0) *firstlen = (off_t) cablen_u32;
-
- /* check that the files offset is less than the alleged length of
- * the cabinet, and that the offset + the alleged length are
- * 'roughly' within the end of overall file length */
- if ((foffset_u32 < cablen_u32) &&
- ((caboff + (off_t) foffset_u32) < (flen + 32)) &&
- ((caboff + (off_t) cablen_u32) < (flen + 32)) )
- {
- /* likely cabinet found -- try reading it */
- if (!(cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
- return MSPACK_ERR_NOMEMORY;
- }
- cab->base.filename = filename;
- if (cabd_read_headers(sys, fh, cab, caboff, 1)) {
- /* destroy the failed cabinet */
- cabd_close((struct mscab_decompressor *) self,
- (struct mscabd_cabinet *) cab);
- false_cabs++;
- }
- else {
- /* cabinet read correctly! */
-
- /* link the cab into the list */
- if (!link) *firstcab = cab;
- else link->base.next = (struct mscabd_cabinet *) cab;
- link = cab;
-
- /* cause the search to restart after this cab's data. */
- offset = caboff + (off_t) cablen_u32;
-
-#ifndef LARGEFILE_SUPPORT
- /* detect 32-bit off_t overflow */
- if (offset < caboff) {
- sys->message(fh, largefile_msg);
- return MSPACK_ERR_OK;
- }
-#endif
- }
- }
-
- /* restart search */
- if (offset >= flen) return MSPACK_ERR_OK;
- if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
- return MSPACK_ERR_SEEK;
- }
- length = 0;
- p = pend;
- state = 0;
- break;
+ /* now we have recieved 20 bytes of potential cab header. work out
+ * the offset in the file of this potential cabinet */
+ caboff = offset + (p - &buf[0]) - 20;
+
+ /* should reading cabinet fail, restart search just after 'MSCF' */
+ offset = caboff + 4;
+
+ /* capture the "length of cabinet" field if there is a cabinet at
+ * offset 0 in the file, regardless of whether the cabinet can be
+ * read correctly or not */
+ if (caboff == 0) *firstlen = (off_t) cablen_u32;
+
+ /* check that the files offset is less than the alleged length of
+ * the cabinet, and that the offset + the alleged length are
+ * 'roughly' within the end of overall file length. In salvage
+ * mode, don't check the alleged length, allow it to be garbage */
+ if ((foffset_u32 < cablen_u32) &&
+ ((caboff + (off_t) foffset_u32) < (flen + 32)) &&
+ (((caboff + (off_t) cablen_u32) < (flen + 32)) || self->salvage))
+ {
+ /* likely cabinet found -- try reading it */
+ if (!(cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
+ return MSPACK_ERR_NOMEMORY;
+ }
+ cab->base.filename = filename;
+ if (cabd_read_headers(sys, fh, cab, caboff, self->salvage, 1)) {
+ /* destroy the failed cabinet */
+ cabd_close((struct mscab_decompressor *) self,
+ (struct mscabd_cabinet *) cab);
+ false_cabs++;
+ }
+ else {
+ /* cabinet read correctly! */
+
+ /* link the cab into the list */
+ if (!link) *firstcab = cab;
+ else link->base.next = (struct mscabd_cabinet *) cab;
+ link = cab;
+
+ /* cause the search to restart after this cab's data. */
+ offset = caboff + (off_t) cablen_u32;
+
+#if !LARGEFILE_SUPPORT
+ /* detect 32-bit off_t overflow */
+ if (offset < caboff) {
+ sys->message(fh, largefile_msg);
+ return MSPACK_ERR_OK;
+ }
+#endif
+ }
+ }
+
+ /* restart search */
+ if (offset >= flen) return MSPACK_ERR_OK;
+ if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
+ return MSPACK_ERR_SEEK;
+ }
+ length = 0;
+ p = pend;
+ state = 0;
+ break;
/* for bytes 4-7 and 12-15, just advance state/pointer */
default:
- p++, state++;
+ p++, state++;
} /* switch(state) */
} /* for (... p < pend ...) */
} /* for (... offset < length ...) */
@@ -765,7 +786,7 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
return MSPACK_ERR_OK;
}
-
+
/***************************************
* CABD_MERGE, CABD_PREPEND, CABD_APPEND
***************************************
@@ -775,22 +796,22 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
* merged folder's data parts list.
*/
static int cabd_prepend(struct mscab_decompressor *base,
- struct mscabd_cabinet *cab,
- struct mscabd_cabinet *prevcab)
+ struct mscabd_cabinet *cab,
+ struct mscabd_cabinet *prevcab)
{
return cabd_merge(base, prevcab, cab);
}
static int cabd_append(struct mscab_decompressor *base,
- struct mscabd_cabinet *cab,
- struct mscabd_cabinet *nextcab)
+ struct mscabd_cabinet *cab,
+ struct mscabd_cabinet *nextcab)
{
return cabd_merge(base, cab, nextcab);
}
static int cabd_merge(struct mscab_decompressor *base,
- struct mscabd_cabinet *lcab,
- struct mscabd_cabinet *rcab)
+ struct mscabd_cabinet *lcab,
+ struct mscabd_cabinet *rcab)
{
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
struct mscabd_folder_data *data, *ndata;
@@ -880,7 +901,7 @@ static int cabd_merge(struct mscab_decompressor *base,
* instead */
lfol->base.num_blocks += rfol->base.num_blocks - 1;
if ((rfol->merge_next == NULL) ||
- (rfol->merge_next->folder != (struct mscabd_folder *) rfol))
+ (rfol->merge_next->folder != (struct mscabd_folder *) rfol))
{
lfol->merge_next = rfol->merge_next;
}
@@ -903,9 +924,9 @@ static int cabd_merge(struct mscab_decompressor *base,
rfi = fi->next;
/* if file's folder matches the merge folder, unlink and free it */
if (fi->folder == (struct mscabd_folder *) rfol) {
- if (lfi) lfi->next = rfi; else lcab->files = rfi;
- sys->free(fi->filename);
- sys->free(fi);
+ if (lfi) lfi->next = rfi; else lcab->files = rfi;
+ sys->free(fi->filename);
+ sys->free(fi);
}
else lfi = fi;
}
@@ -940,6 +961,12 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
return 0;
}
+ /* check there are not too many data blocks after merging */
+ if ((lfol->base.num_blocks + rfol->base.num_blocks) > CAB_FOLDERMAX) {
+ D(("folder merge: too many data blocks in merged folders"))
+ return 0;
+ }
+
if (!(lfi = lfol->merge_next) || !(rfi = rfol->merge_prev)) {
D(("folder merge: one cabinet has no files to merge"))
return 0;
@@ -950,10 +977,10 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
* should be identical in number and order. to verify this, check the
* offset and length of each file. */
for (l=lfi, r=rfi; l; l=l->next, r=r->next) {
- if (!r || (l->offset != r->offset) || (l->length != r->length)) {
- matching = 0;
- break;
- }
+ if (!r || (l->offset != r->offset) || (l->length != r->length)) {
+ matching = 0;
+ break;
+ }
}
if (matching) return 1;
@@ -963,9 +990,9 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
* the merge with a warning about missing files. */
matching = 0;
for (l = lfi; l; l = l->next) {
- for (r = rfi; r; r = r->next) {
- if (l->offset == r->offset && l->length == r->length) break;
- }
+ for (r = rfi; r; r = r->next) {
+ if (l->offset == r->offset && l->length == r->length) break;
+ }
if (r) matching = 1; else sys->message(NULL,
"WARNING; merged file %s not listed in both cabinets", l->filename);
}
@@ -985,6 +1012,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;
if (!self) return MSPACK_ERR_ARGS;
if (!file) return self->error = MSPACK_ERR_ARGS;
@@ -992,15 +1020,43 @@ static int cabd_extract(struct mscab_decompressor *base,
sys = self->system;
fol = (struct mscabd_folder_p *) file->folder;
- /* check if file can be extracted */
- if ((!fol) || (fol->merge_prev) ||
- (((file->offset + file->length) / CAB_BLOCKMAX) > fol->base.num_blocks))
- {
- sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
- "cabinet set is incomplete.", file->filename);
+ /* if offset is beyond 2GB, nothing can be extracted */
+ if (file->offset > CAB_LENGTHMAX) {
return self->error = MSPACK_ERR_DATAFORMAT;
}
+ /* if file claims to go beyond 2GB either error out,
+ * 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 (self->salvage) {
+ filelen = CAB_LENGTHMAX - file->offset;
+ }
+ else {
+ return self->error = MSPACK_ERR_DATAFORMAT;
+ }
+ }
+
+ /* extraction impossible if no folder, or folder needs predecessor */
+ if (!fol || fol->merge_prev) {
+ sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
+ "cabinet set is incomplete", file->filename);
+ return self->error = MSPACK_ERR_DECRUNCH;
+ }
+
+ /* if file goes beyond what can be decoded, given an error.
+ * 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) {
+ sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
+ "cabinet set is incomplete", file->filename);
+ return self->error = MSPACK_ERR_DECRUNCH;
+ }
+ }
+
/* allocate generic decompression state */
if (!self->d) {
self->d = (struct mscabd_decompress_state *) sys->alloc(sys, sizeof(struct mscabd_decompress_state));
@@ -1016,14 +1072,19 @@ static int cabd_extract(struct mscab_decompressor *base,
}
/* do we need to change folder or reset the current folder? */
- if ((self->d->folder != fol) || (self->d->offset > file->offset)) {
+ if ((self->d->folder != fol) || (self->d->offset > file->offset) ||
+ !self->d->state)
+ {
+ /* free any existing decompressor */
+ cabd_free_decomp(self);
+
/* do we need to open a new cab file? */
if (!self->d->infh || (fol->data.cab != self->d->incab)) {
/* close previous file handle if from a different cab */
if (self->d->infh) sys->close(self->d->infh);
self->d->incab = fol->data.cab;
self->d->infh = sys->open(sys, fol->data.cab->base.filename,
- MSPACK_SYS_OPEN_READ);
+ MSPACK_SYS_OPEN_READ);
if (!self->d->infh) return self->error = MSPACK_ERR_OPEN;
}
/* seek to start of data blocks */
@@ -1041,6 +1102,7 @@ static int cabd_extract(struct mscab_decompressor *base,
self->d->data = &fol->data;
self->d->offset = 0;
self->d->block = 0;
+ self->d->outlen = 0;
self->d->i_ptr = self->d->i_end = &self->d->input[0];
/* read_error lasts for the lifetime of a decompressor */
@@ -1055,7 +1117,7 @@ static int cabd_extract(struct mscab_decompressor *base,
self->error = MSPACK_ERR_OK;
/* if file has more than 0 bytes */
- if (file->length) {
+ if (filelen) {
off_t bytes;
int error;
/* get to correct offset.
@@ -1065,14 +1127,14 @@ static int cabd_extract(struct mscab_decompressor *base,
*/
self->d->outfh = NULL;
if ((bytes = file->offset - self->d->offset)) {
- error = self->d->decompress(self->d->state, bytes);
- self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
+ error = self->d->decompress(self->d->state, bytes);
+ self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
}
/* if getting to the correct offset was error free, unpack file */
if (!self->error) {
self->d->outfh = fh;
- error = self->d->decompress(self->d->state, (off_t) file->length);
+ error = self->d->decompress(self->d->state, filelen);
self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
}
}
@@ -1098,34 +1160,27 @@ static int cabd_init_decomp(struct mscab_decompressor_p *self, unsigned int ct)
{
struct mspack_file *fh = (struct mspack_file *) self;
- assert(self && self->d);
-
- /* free any existing decompressor */
- cabd_free_decomp(self);
-
self->d->comp_type = ct;
switch (ct & cffoldCOMPTYPE_MASK) {
case cffoldCOMPTYPE_NONE:
self->d->decompress = (int (*)(void *, off_t)) &noned_decompress;
- self->d->state = noned_init(&self->d->sys, fh, fh,
- self->param[MSCABD_PARAM_DECOMPBUF]);
+ self->d->state = noned_init(&self->d->sys, fh, fh, self->buf_size);
break;
case cffoldCOMPTYPE_MSZIP:
self->d->decompress = (int (*)(void *, off_t)) &mszipd_decompress;
- self->d->state = mszipd_init(&self->d->sys, fh, fh,
- self->param[MSCABD_PARAM_DECOMPBUF],
- self->param[MSCABD_PARAM_FIXMSZIP]);
+ self->d->state = mszipd_init(&self->d->sys, fh, fh, self->buf_size,
+ self->fix_mszip);
break;
case cffoldCOMPTYPE_QUANTUM:
self->d->decompress = (int (*)(void *, off_t)) &qtmd_decompress;
self->d->state = qtmd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f,
- self->param[MSCABD_PARAM_DECOMPBUF]);
+ self->buf_size);
break;
case cffoldCOMPTYPE_LZX:
self->d->decompress = (int (*)(void *, off_t)) &lzxd_decompress;
self->d->state = lzxd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f, 0,
- self->param[MSCABD_PARAM_DECOMPBUF], (off_t) 0);
+ self->buf_size, (off_t)0,0);
break;
default:
return self->error = MSPACK_ERR_DATAFORMAT;
@@ -1134,7 +1189,7 @@ static int cabd_init_decomp(struct mscab_decompressor_p *self, unsigned int ct)
}
static void cabd_free_decomp(struct mscab_decompressor_p *self) {
- if (!self || !self->d || !self->d->folder || !self->d->state) return;
+ if (!self || !self->d || !self->d->state) return;
switch (self->d->comp_type & cffoldCOMPTYPE_MASK) {
case cffoldCOMPTYPE_NONE: noned_free((struct noned_state *) self->d->state); break;
@@ -1162,10 +1217,12 @@ static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) {
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file;
unsigned char *buf = (unsigned char *) buffer;
struct mspack_system *sys = self->system;
- int avail, todo, outlen, ignore_cksum;
+ int avail, todo, outlen, ignore_cksum, ignore_blocksize;
- ignore_cksum = self->param[MSCABD_PARAM_FIXMSZIP] &&
- ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP);
+ ignore_cksum = self->salvage ||
+ (self->fix_mszip &&
+ ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP));
+ ignore_blocksize = self->salvage;
todo = bytes;
while (todo > 0) {
@@ -1185,37 +1242,35 @@ static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) {
/* check if we're out of input blocks, advance block counter */
if (self->d->block++ >= self->d->folder->base.num_blocks) {
- self->read_error = MSPACK_ERR_DATAFORMAT;
- break;
+ if (!self->salvage) {
+ self->read_error = MSPACK_ERR_DATAFORMAT;
+ }
+ else {
+ D(("Ran out of CAB input blocks prematurely"))
+ }
+ break;
}
/* read a block */
- self->read_error = cabd_sys_read_block(sys, self->d, &outlen, ignore_cksum);
+ self->read_error = cabd_sys_read_block(sys, self->d, &outlen,
+ ignore_cksum, ignore_blocksize);
if (self->read_error) return -1;
+ self->d->outlen += outlen;
/* special Quantum hack -- trailer byte to allow the decompressor
* to realign itself. CAB Quantum blocks, unlike LZX blocks, can have
* anything from 0 to 4 trailing null bytes. */
if ((self->d->comp_type & cffoldCOMPTYPE_MASK)==cffoldCOMPTYPE_QUANTUM) {
- *self->d->i_end++ = 0xFF;
+ *self->d->i_end++ = 0xFF;
}
/* is this the last block? */
if (self->d->block >= self->d->folder->base.num_blocks) {
- /* last block */
- if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) {
- /* special LZX hack -- on the last block, inform LZX of the
- * size of the output data stream. */
- lzxd_set_output_length((struct lzxd_stream *) self->d->state, (off_t)
- ((self->d->block-1) * CAB_BLOCKMAX + outlen));
- }
- }
- else {
- /* not the last block */
- if (outlen != CAB_BLOCKMAX) {
- self->system->message(self->d->infh,
- "WARNING; non-maximal data block");
- }
+ if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) {
+ /* special LZX hack -- on the last block, inform LZX of the
+ * size of the output data stream. */
+ lzxd_set_output_length((struct lzxd_stream *) self->d->state, self->d->outlen);
+ }
}
} /* if (avail) */
} /* while (todo > 0) */
@@ -1238,12 +1293,13 @@ static int cabd_sys_write(struct mspack_file *file, void *buffer, int bytes) {
* one cab file, if it does then the fragments will be reassembled
*/
static int cabd_sys_read_block(struct mspack_system *sys,
- struct mscabd_decompress_state *d,
- int *out, int ignore_cksum)
+ struct mscabd_decompress_state *d,
+ int *out, int ignore_cksum,
+ int ignore_blocksize)
{
unsigned char hdr[cfdata_SIZEOF];
unsigned int cksum;
- int len;
+ int len, full_len;
/* reset the input block pointer and end of block pointer */
d->i_ptr = d->i_end = &d->input[0];
@@ -1256,23 +1312,27 @@ static int cabd_sys_read_block(struct mspack_system *sys,
/* skip any reserved block headers */
if (d->data->cab->block_resv &&
- sys->seek(d->infh, (off_t) d->data->cab->block_resv,
- MSPACK_SYS_SEEK_CUR))
+ sys->seek(d->infh, (off_t) d->data->cab->block_resv,
+ MSPACK_SYS_SEEK_CUR))
{
return MSPACK_ERR_SEEK;
}
/* blocks must not be over CAB_INPUTMAX in size */
len = EndGetI16(&hdr[cfdata_CompressedSize]);
- if (((d->i_end - d->i_ptr) + len) > CAB_INPUTMAX) {
- D(("block size > CAB_INPUTMAX (%ld + %d)", d->i_end - d->i_ptr, len))
- return MSPACK_ERR_DATAFORMAT;
+ full_len = (d->i_end - d->i_ptr) + len; /* include cab-spanning blocks */
+ if (full_len > CAB_INPUTMAX) {
+ D(("block size %d > CAB_INPUTMAX", full_len));
+ /* in salvage mode, blocks can be 65535 bytes but no more than that */
+ if (!ignore_blocksize || full_len > CAB_INPUTMAX_SALVAGE) {
+ return MSPACK_ERR_DATAFORMAT;
+ }
}
/* blocks must not expand to more than CAB_BLOCKMAX */
if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) {
D(("block size > CAB_BLOCKMAX"))
- return MSPACK_ERR_DATAFORMAT;
+ if (!ignore_blocksize) return MSPACK_ERR_DATAFORMAT;
}
/* read the block data */
@@ -1284,8 +1344,8 @@ static int cabd_sys_read_block(struct mspack_system *sys,
if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) {
unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0);
if (cabd_checksum(&hdr[4], 4, sum2) != cksum) {
- if (!ignore_cksum) return MSPACK_ERR_CHECKSUM;
- sys->message(d->infh, "WARNING; bad block checksum found");
+ if (!ignore_cksum) return MSPACK_ERR_CHECKSUM;
+ sys->message(d->infh, "WARNING; bad block checksum found");
}
}
@@ -1310,14 +1370,14 @@ static int cabd_sys_read_block(struct mspack_system *sys,
/* advance to next member in the cabinet set */
if (!(d->data = d->data->next)) {
- D(("ran out of splits in cabinet set"))
+ sys->message(d->infh, "WARNING; ran out of cabinets in set. Are any missing?");
return MSPACK_ERR_DATAFORMAT;
}
/* open next cab file */
d->incab = d->data->cab;
if (!(d->infh = sys->open(sys, d->incab->base.filename,
- MSPACK_SYS_OPEN_READ)))
+ MSPACK_SYS_OPEN_READ)))
{
return MSPACK_ERR_OPEN;
}
@@ -1333,7 +1393,7 @@ static int cabd_sys_read_block(struct mspack_system *sys,
}
static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
- unsigned int cksum)
+ unsigned int cksum)
{
unsigned int len, ul = 0;
@@ -1342,8 +1402,8 @@ static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
}
switch (bytes & 3) {
- case 3: ul |= *data++ << 16;
- case 2: ul |= *data++ << 8;
+ case 3: ul |= *data++ << 16; /*@fallthrough@*/
+ case 2: ul |= *data++ << 8; /*@fallthrough@*/
case 1: ul |= *data;
}
cksum ^= ul;
@@ -1365,9 +1425,9 @@ struct noned_state {
};
static struct noned_state *noned_init(struct mspack_system *sys,
- struct mspack_file *in,
- struct mspack_file *out,
- int bufsize)
+ struct mspack_file *in,
+ struct mspack_file *out,
+ int bufsize)
{
struct noned_state *state = (struct noned_state *) sys->alloc(sys, sizeof(struct noned_state));
unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) bufsize);
@@ -1419,14 +1479,17 @@ static int cabd_param(struct mscab_decompressor *base, int param, int value) {
switch (param) {
case MSCABD_PARAM_SEARCHBUF:
if (value < 4) return MSPACK_ERR_ARGS;
- self->param[MSCABD_PARAM_SEARCHBUF] = value;
+ self->searchbuf_size = value;
break;
case MSCABD_PARAM_FIXMSZIP:
- self->param[MSCABD_PARAM_FIXMSZIP] = value;
+ self->fix_mszip = value;
break;
case MSCABD_PARAM_DECOMPBUF:
if (value < 4) return MSPACK_ERR_ARGS;
- self->param[MSCABD_PARAM_DECOMPBUF] = value;
+ self->buf_size = value;
+ break;
+ case MSCABD_PARAM_SALVAGE:
+ self->salvage = value;
break;
default:
return MSPACK_ERR_ARGS;
diff --git a/rbutil/rbutilqt/mspack/chmd.c b/rbutil/rbutilqt/mspack/chmd.c
index 416156e742..6c8481db14 100644
--- a/rbutil/rbutilqt/mspack/chmd.c
+++ b/rbutil/rbutilqt/mspack/chmd.c
@@ -1,5 +1,5 @@
/* This file is part of libmspack.
- * (C) 2003-2011 Stuart Caie.
+ * (C) 2003-2018 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
@@ -44,7 +44,7 @@ static int chmd_init_decomp(
struct mschm_decompressor_p *self, struct mschmd_file *file);
static int read_reset_table(
struct mschm_decompressor_p *self, struct mschmd_sec_mscompressed *sec,
- int entry, off_t *length_ptr, off_t *offset_ptr);
+ unsigned int entry, off_t *length_ptr, off_t *offset_ptr);
static int read_spaninfo(
struct mschm_decompressor_p *self, struct mschmd_sec_mscompressed *sec,
off_t *length_ptr);
@@ -121,7 +121,7 @@ void mspack_destroy_chm_decompressor(struct mschm_decompressor *base) {
* Calls chmd_real_open() with entire=1.
*/
static struct mschmd_header *chmd_open(struct mschm_decompressor *base,
- const char *filename)
+ const char *filename)
{
return chmd_real_open(base, filename, 1);
}
@@ -133,7 +133,7 @@ static struct mschmd_header *chmd_open(struct mschm_decompressor *base,
* the file headers. Calls chmd_real_open() with entire=0
*/
static struct mschmd_header *chmd_fast_open(struct mschm_decompressor *base,
- const char *filename)
+ const char *filename)
{
return chmd_real_open(base, filename, 0);
}
@@ -146,7 +146,7 @@ static struct mschmd_header *chmd_fast_open(struct mschm_decompressor *base,
* either read all headers, or a bare mininum.
*/
static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base,
- const char *filename, int entire)
+ const char *filename, int entire)
{
struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
struct mschmd_header *chm = NULL;
@@ -162,16 +162,16 @@ static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base,
chm->filename = filename;
error = chmd_read_headers(sys, fh, chm, entire);
if (error) {
- /* if the error is DATAFORMAT, and there are some results, return
- * partial results with a warning, rather than nothing */
- if (error == MSPACK_ERR_DATAFORMAT && (chm->files || chm->sysfiles)) {
- sys->message(fh, "WARNING; contents are corrupt");
- error = MSPACK_ERR_OK;
- }
- else {
- chmd_close(base, chm);
- chm = NULL;
- }
+ /* if the error is DATAFORMAT, and there are some results, return
+ * partial results with a warning, rather than nothing */
+ if (error == MSPACK_ERR_DATAFORMAT && (chm->files || chm->sysfiles)) {
+ sys->message(fh, "WARNING; contents are corrupt");
+ error = MSPACK_ERR_OK;
+ }
+ else {
+ chmd_close(base, chm);
+ chm = NULL;
+ }
}
self->error = error;
}
@@ -192,7 +192,7 @@ static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base,
* frees all memory associated with a given mschmd_header
*/
static void chmd_close(struct mschm_decompressor *base,
- struct mschmd_header *chm)
+ struct mschmd_header *chm)
{
struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
struct mschmd_file *fi, *nfi;
@@ -251,16 +251,16 @@ static const unsigned char guids[32] = {
/* 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); \
+#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)
+ struct mschmd_header *chm, int entire)
{
unsigned int section, name_len, x, errors, num_chunks;
unsigned char buf[0x54], *chunk = NULL, *name, *p, *end;
@@ -292,7 +292,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
}
/* check both header GUIDs */
- if (mspack_memcmp(&buf[chmhead_GUID1], &guids[0], 32L) != 0) {
+ if (memcmp(&buf[chmhead_GUID1], &guids[0], 32L) != 0) {
D(("incorrect GUIDs"))
return MSPACK_ERR_SIGNATURE;
}
@@ -356,8 +356,53 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
chm->sec0.offset = chm->dir_offset + (chm->chunk_size * chm->num_chunks);
}
- /* ensure chunk size is large enough for signature and num_entries */
+ /* check if content offset or file size is wrong */
+ if (chm->sec0.offset > chm->length) {
+ D(("content section begins after file has ended"))
+ return MSPACK_ERR_DATAFORMAT;
+ }
+
+ /* ensure there are chunks and that chunk size is
+ * large enough for signature and num_entries */
if (chm->chunk_size < (pmgl_Entries + 2)) {
+ D(("chunk size not large enough"))
+ return MSPACK_ERR_DATAFORMAT;
+ }
+ if (chm->num_chunks == 0) {
+ D(("no chunks"))
+ return MSPACK_ERR_DATAFORMAT;
+ }
+
+ /* The chunk_cache data structure is not great; large values for num_chunks
+ * or num_chunks*chunk_size can exhaust all memory. Until a better chunk
+ * cache is implemented, put arbitrary limits on num_chunks and chunk size.
+ */
+ if (chm->num_chunks > 100000) {
+ D(("more than 100,000 chunks"))
+ return MSPACK_ERR_DATAFORMAT;
+ }
+ if (chm->chunk_size > 8192) {
+ D(("chunk size over 8192 (get in touch if this is valid)"))
+ return MSPACK_ERR_DATAFORMAT;
+ }
+ if ((off_t)chm->chunk_size * (off_t)chm->num_chunks > chm->length) {
+ D(("chunks larger than entire file"))
+ return MSPACK_ERR_DATAFORMAT;
+ }
+
+ /* common sense checks on header section 1 fields */
+ if (chm->chunk_size != 4096) {
+ sys->message(fh, "WARNING; chunk size is not 4096");
+ }
+ if (chm->first_pmgl != 0) {
+ sys->message(fh, "WARNING; first PMGL chunk is not zero");
+ }
+ if (chm->first_pmgl > chm->last_pmgl) {
+ D(("first pmgl chunk is after last pmgl chunk"))
+ return MSPACK_ERR_DATAFORMAT;
+ }
+ if (chm->index_root != 0xFFFFFFFF && chm->index_root >= chm->num_chunks) {
+ D(("index_root outside valid range"))
return MSPACK_ERR_DATAFORMAT;
}
@@ -394,7 +439,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
sys->message(fh, "WARNING; PMGL quickref area is too small");
}
if (EndGetI32(&chunk[pmgl_QuickRefSize]) >
- ((int)chm->chunk_size - pmgl_Entries))
+ (chm->chunk_size - pmgl_Entries))
{
sys->message(fh, "WARNING; PMGL quickref area is too large");
}
@@ -404,60 +449,63 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
num_entries = EndGetI16(end);
while (num_entries--) {
- READ_ENCINT(name_len); name = p; p += name_len;
+ READ_ENCINT(name_len);
+ if (name_len > (unsigned int) (end - p)) goto chunk_end;
+ name = p; p += name_len;
READ_ENCINT(section);
READ_ENCINT(offset);
READ_ENCINT(length);
+ /* ignore blank or one-char (e.g. "/") filenames we'd return as blank */
+ if (name_len < 2 || !name[0] || !name[1]) continue;
+
/* empty files and directory names are stored as a file entry at
* offset 0 with length 0. We want to keep empty files, but not
* directory names, which end with a "/" */
if ((offset == 0) && (length == 0)) {
- if ((name_len > 0) && (name[name_len-1] == '/')) continue;
+ if ((name_len > 0) && (name[name_len-1] == '/')) continue;
}
if (section > 1) {
- sys->message(fh, "invalid section number '%u'.", section);
- continue;
+ sys->message(fh, "invalid section number '%u'.", section);
+ continue;
}
if (!(fi = (struct mschmd_file *) sys->alloc(sys, sizeof(struct mschmd_file) + name_len + 1))) {
- sys->free(chunk);
- return MSPACK_ERR_NOMEMORY;
+ sys->free(chunk);
+ return MSPACK_ERR_NOMEMORY;
}
fi->next = NULL;
fi->filename = (char *) &fi[1];
fi->section = ((section == 0) ? (struct mschmd_section *) (&chm->sec0)
- : (struct mschmd_section *) (&chm->sec1));
+ : (struct mschmd_section *) (&chm->sec1));
fi->offset = offset;
fi->length = length;
sys->copy(name, fi->filename, (size_t) name_len);
fi->filename[name_len] = '\0';
if (name[0] == ':' && name[1] == ':') {
- /* system file */
- if (mspack_memcmp(&name[2], &content_name[2], 31L) == 0) {
- if (mspack_memcmp(&name[33], &content_name[33], 8L) == 0) {
- chm->sec1.content = fi;
- }
- else if (mspack_memcmp(&name[33], &control_name[33], 11L) == 0) {
- chm->sec1.control = fi;
- }
- else if (mspack_memcmp(&name[33], &spaninfo_name[33], 8L) == 0) {
- chm->sec1.spaninfo = fi;
- }
- else if (mspack_memcmp(&name[33], &rtable_name[33], 72L) == 0) {
- chm->sec1.rtable = fi;
- }
- }
- fi->next = chm->sysfiles;
- chm->sysfiles = fi;
+ /* system file */
+ if (name_len == 40 && memcmp(name, content_name, 40) == 0) {
+ chm->sec1.content = fi;
+ }
+ else if (name_len == 44 && memcmp(name, control_name, 44) == 0) {
+ chm->sec1.control = fi;
+ }
+ else if (name_len == 41 && memcmp(name, spaninfo_name, 41) == 0) {
+ chm->sec1.spaninfo = fi;
+ }
+ else if (name_len == 105 && memcmp(name, rtable_name, 105) == 0) {
+ chm->sec1.rtable = fi;
+ }
+ fi->next = chm->sysfiles;
+ chm->sysfiles = fi;
}
else {
- /* normal file */
- if (link) link->next = fi; else chm->files = fi;
- link = fi;
+ /* normal file */
+ if (link) link->next = fi; else chm->files = fi;
+ link = fi;
}
}
@@ -481,21 +529,24 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
* directly from the on-disk index.
*
* TODO: protect against infinite loops in chunks (where pgml_NextChunk
- * or a PGMI index entry point to an already visited chunk)
+ * or a PMGI index entry point to an already visited chunk)
*/
static int chmd_fast_find(struct mschm_decompressor *base,
- struct mschmd_header *chm, const char *filename,
- struct mschmd_file *f_ptr, int f_size)
+ struct mschmd_header *chm, const char *filename,
+ struct mschmd_file *f_ptr, int f_size)
{
struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
struct mspack_system *sys;
struct mspack_file *fh;
- const unsigned char *chunk, *p, *end;
+ /* p and end are initialised to prevent MSVC warning about "potentially"
+ * uninitialised usage. This is provably untrue, but MS won't fix:
+ * https://developercommunity.visualstudio.com/content/problem/363489/c4701-false-positive-warning.html */
+ const unsigned char *chunk, *p = NULL, *end = NULL;
int err = MSPACK_ERR_OK, result = -1;
unsigned int n, sec;
if (!self || !chm || !f_ptr || (f_size != sizeof(struct mschmd_file))) {
- return MSPACK_ERR_ARGS;
+ return MSPACK_ERR_ARGS;
}
sys = self->system;
@@ -503,54 +554,59 @@ static int chmd_fast_find(struct mschm_decompressor *base,
memset(f_ptr, 0, f_size);
if (!(fh = sys->open(sys, chm->filename, MSPACK_SYS_OPEN_READ))) {
- return MSPACK_ERR_OPEN;
+ return MSPACK_ERR_OPEN;
}
/* go through PMGI chunk hierarchy to reach PMGL chunk */
if (chm->index_root < chm->num_chunks) {
- n = chm->index_root;
- for (;;) {
- if (!(chunk = read_chunk(self, chm, fh, n))) {
- sys->close(fh);
- return self->error;
- }
-
- /* search PMGI/PMGL chunk. exit early if no entry found */
- if ((result = search_chunk(chm, chunk, filename, &p, &end)) <= 0) {
- break;
- }
-
- /* found result. loop around for next chunk if this is PMGI */
- if (chunk[3] == 0x4C) break; else READ_ENCINT(n);
- }
+ n = chm->index_root;
+ for (;;) {
+ if (!(chunk = read_chunk(self, chm, fh, n))) {
+ sys->close(fh);
+ return self->error;
+ }
+
+ /* search PMGI/PMGL chunk. exit early if no entry found */
+ if ((result = search_chunk(chm, chunk, filename, &p, &end)) <= 0) {
+ break;
+ }
+
+ /* found result. loop around for next chunk if this is PMGI */
+ if (chunk[3] == 0x4C) break; else READ_ENCINT(n);
+ }
}
else {
- /* PMGL chunks only, search from first_pmgl to last_pmgl */
- for (n = chm->first_pmgl; n <= chm->last_pmgl;
- n = EndGetI32(&chunk[pmgl_NextChunk]))
- {
- if (!(chunk = read_chunk(self, chm, fh, n))) {
- err = self->error;
- break;
- }
-
- /* search PMGL chunk. exit if file found */
- if ((result = search_chunk(chm, chunk, filename, &p, &end)) > 0) {
- break;
- }
- }
+ /* PMGL chunks only, search from first_pmgl to last_pmgl */
+ for (n = chm->first_pmgl; n <= chm->last_pmgl;
+ n = EndGetI32(&chunk[pmgl_NextChunk]))
+ {
+ if (!(chunk = read_chunk(self, chm, fh, n))) {
+ err = self->error;
+ break;
+ }
+
+ /* search PMGL chunk. exit if file found */
+ if ((result = search_chunk(chm, chunk, filename, &p, &end)) > 0) {
+ break;
+ }
+
+ /* stop simple infinite loops: can't visit the same chunk twice */
+ if (n == EndGetI32(&chunk[pmgl_NextChunk])) {
+ break;
+ }
+ }
}
/* if we found a file, read it */
if (result > 0) {
- READ_ENCINT(sec);
- 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);
+ READ_ENCINT(sec);
+ 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);
}
else if (result < 0) {
- err = MSPACK_ERR_DATAFORMAT;
+ err = MSPACK_ERR_DATAFORMAT;
}
sys->close(fh);
@@ -566,24 +622,24 @@ static int chmd_fast_find(struct mschm_decompressor *base,
* so it doesn't need to be read from disk more than once
*/
static unsigned char *read_chunk(struct mschm_decompressor_p *self,
- struct mschmd_header *chm,
- struct mspack_file *fh,
- unsigned int chunk_num)
+ struct mschmd_header *chm,
+ struct mspack_file *fh,
+ unsigned int chunk_num)
{
struct mspack_system *sys = self->system;
unsigned char *buf;
/* check arguments - most are already checked by chmd_fast_find */
- if (chunk_num > chm->num_chunks) return NULL;
+ if (chunk_num >= chm->num_chunks) return NULL;
/* ensure chunk cache is available */
if (!chm->chunk_cache) {
- size_t size = sizeof(unsigned char *) * chm->num_chunks;
- if (!(chm->chunk_cache = (unsigned char **) sys->alloc(sys, size))) {
- self->error = MSPACK_ERR_NOMEMORY;
- return NULL;
- }
- memset(chm->chunk_cache, 0, size);
+ size_t size = sizeof(unsigned char *) * chm->num_chunks;
+ if (!(chm->chunk_cache = (unsigned char **) sys->alloc(sys, size))) {
+ self->error = MSPACK_ERR_NOMEMORY;
+ return NULL;
+ }
+ memset(chm->chunk_cache, 0, size);
}
/* try to answer out of chunk cache */
@@ -591,31 +647,31 @@ static unsigned char *read_chunk(struct mschm_decompressor_p *self,
/* need to read chunk - allocate memory for it */
if (!(buf = (unsigned char *) sys->alloc(sys, chm->chunk_size))) {
- self->error = MSPACK_ERR_NOMEMORY;
- return NULL;
+ self->error = MSPACK_ERR_NOMEMORY;
+ return NULL;
}
/* seek to block and read it */
if (sys->seek(fh, (off_t) (chm->dir_offset + (chunk_num * chm->chunk_size)),
- MSPACK_SYS_SEEK_START))
+ MSPACK_SYS_SEEK_START))
{
- self->error = MSPACK_ERR_SEEK;
- sys->free(buf);
- return NULL;
+ self->error = MSPACK_ERR_SEEK;
+ sys->free(buf);
+ return NULL;
}
if (sys->read(fh, buf, (int)chm->chunk_size) != (int)chm->chunk_size) {
- self->error = MSPACK_ERR_READ;
- sys->free(buf);
- return NULL;
+ self->error = MSPACK_ERR_READ;
+ sys->free(buf);
+ return NULL;
}
/* check the signature. Is is PMGL or PMGI? */
if (!((buf[0] == 0x50) && (buf[1] == 0x4D) && (buf[2] == 0x47) &&
- ((buf[3] == 0x4C) || (buf[3] == 0x49))))
+ ((buf[3] == 0x4C) || (buf[3] == 0x49))))
{
- self->error = MSPACK_ERR_SEEK;
- sys->free(buf);
- return NULL;
+ self->error = MSPACK_ERR_SEEK;
+ sys->free(buf);
+ return NULL;
}
/* all OK. Store chunk in cache and return it */
@@ -633,14 +689,14 @@ static unsigned char *read_chunk(struct mschm_decompressor_p *self,
* chunk that may eventually contain that entry has been found.
*/
static int search_chunk(struct mschmd_header *chm,
- const unsigned char *chunk,
- const char *filename,
- const unsigned char **result,
- const unsigned char **result_end)
+ const unsigned char *chunk,
+ const char *filename,
+ const unsigned char **result,
+ const unsigned char **result_end)
{
const unsigned char *start, *end, *p;
unsigned int qr_size, num_entries, qr_entries, qr_density, name_len;
- unsigned int L, R, M, sec, fname_len, entries_off, is_pmgl;
+ unsigned int L, R, M, fname_len, entries_off, is_pmgl;
int cmp;
fname_len = strlen(filename);
@@ -648,12 +704,12 @@ static int search_chunk(struct mschmd_header *chm,
/* PMGL chunk or PMGI chunk? (note: read_chunk() has already
* checked the rest of the characters in the chunk signature) */
if (chunk[3] == 0x4C) {
- is_pmgl = 1;
- entries_off = pmgl_Entries;
+ is_pmgl = 1;
+ entries_off = pmgl_Entries;
}
else {
- is_pmgl = 0;
- entries_off = pmgi_Entries;
+ is_pmgl = 0;
+ entries_off = pmgi_Entries;
}
/* Step 1: binary search first filename of each QR entry
@@ -674,55 +730,55 @@ static int search_chunk(struct mschmd_header *chm,
qr_entries = (num_entries + qr_density-1) / qr_density;
if (num_entries == 0) {
- D(("chunk has no entries"))
- return -1;
+ D(("chunk has no entries"))
+ return -1;
}
if (qr_size > chm->chunk_size) {
- D(("quickref size > chunk size"))
- return -1;
+ D(("quickref size > chunk size"))
+ return -1;
}
*result_end = end;
if (((int)qr_entries * 2) > (start - end)) {
- D(("WARNING; more quickrefs than quickref space"))
- qr_entries = 0; /* but we can live with it */
+ D(("WARNING; more quickrefs than quickref space"))
+ qr_entries = 0; /* but we can live with it */
}
if (qr_entries > 0) {
- L = 0;
- R = qr_entries - 1;
- do {
- /* pick new midpoint */
- M = (L + R) >> 1;
-
- /* compare filename with entry QR points to */
- p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
- READ_ENCINT(name_len);
- if (p + name_len > end) goto chunk_end;
- cmp = compare(filename, (char *)p, fname_len, name_len);
-
- if (cmp == 0) break;
- else if (cmp < 0) { if (M) R = M - 1; else return 0; }
- else if (cmp > 0) L = M + 1;
- } while (L <= R);
- M = (L + R) >> 1;
-
- if (cmp == 0) {
- /* exact match! */
- p += name_len;
- *result = p;
- return 1;
- }
-
- /* otherwise, read the group of entries for QR entry M */
- p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
- num_entries -= (M * qr_density);
- if (num_entries > qr_density) num_entries = qr_density;
+ L = 0;
+ R = qr_entries - 1;
+ do {
+ /* pick new midpoint */
+ M = (L + R) >> 1;
+
+ /* 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;
+ cmp = compare(filename, (char *)p, fname_len, name_len);
+
+ if (cmp == 0) break;
+ else if (cmp < 0) { if (M) R = M - 1; else return 0; }
+ else if (cmp > 0) L = M + 1;
+ } while (L <= R);
+ M = (L + R) >> 1;
+
+ if (cmp == 0) {
+ /* exact match! */
+ p += name_len;
+ *result = p;
+ return 1;
+ }
+
+ /* otherwise, read the group of entries for QR entry M */
+ p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
+ num_entries -= (M * qr_density);
+ if (num_entries > qr_density) num_entries = qr_density;
}
else {
- p = &chunk[entries_off];
+ p = &chunk[entries_off];
}
/* Step 2: linear search through the set of entries reached in step 1.
@@ -736,32 +792,32 @@ static int search_chunk(struct mschmd_header *chm,
*/
*result = NULL;
while (num_entries-- > 0) {
- READ_ENCINT(name_len);
- if (p + name_len > end) goto chunk_end;
- cmp = compare(filename, (char *)p, fname_len, name_len);
- p += name_len;
-
- if (cmp == 0) {
- /* entry found */
- *result = p;
- return 1;
- }
-
- if (cmp < 0) {
- /* entry not found (PMGL) / maybe found (PMGI) */
- break;
- }
-
- /* 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 */
- }
- else {
- *result = p; /* store potential final result */
- READ_ENCINT(R); /* skip chunk number */
- }
+ READ_ENCINT(name_len);
+ if (name_len > (unsigned int) (end - p)) goto chunk_end;
+ cmp = compare(filename, (char *)p, fname_len, name_len);
+ p += name_len;
+
+ if (cmp == 0) {
+ /* entry found */
+ *result = p;
+ return 1;
+ }
+
+ if (cmp < 0) {
+ /* entry not found (PMGL) / maybe found (PMGI) */
+ break;
+ }
+
+ /* 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 */
+ }
+ else {
+ *result = p; /* store potential final result */
+ READ_ENCINT(R); /* skip chunk number */
+ }
}
/* PMGL? not found. PMGI? maybe found */
@@ -773,66 +829,34 @@ static int search_chunk(struct mschmd_header *chm,
}
#if HAVE_TOWLOWER
-# if HAVE_WCTYPE_H
-# include <wctype.h>
-# endif
+# include <wctype.h>
# define TOLOWER(x) towlower(x)
-#elif HAVE_TOLOWER
-# if HAVE_CTYPE_H
-# include <ctype.h>
-# endif
-# define TOLOWER(x) tolower(x)
#else
-# define TOLOWER(x) (((x)<0||(x)>256)?(x):mspack_tolower_map[(x)])
-/* Map of char -> lowercase char for the first 256 chars. Generated with:
- * LC_CTYPE=en_GB.utf-8 perl -Mlocale -le 'print map{ord(lc chr).","} 0..255'
- */
-static const unsigned char mspack_tolower_map[256] = {
- 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,
- 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,
- 53,54,55,56,57,58,59,60,61,62,63,64,97,98,99,100,101,102,103,104,105,106,
- 107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,
- 95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
- 115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,
- 134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,
- 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,
- 172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,
- 191,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,
- 242,243,244,245,246,215,248,249,250,251,252,253,254,223,224,225,226,227,228,
- 229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,
- 248,249,250,251,252,253,254,255
-};
+# include <ctype.h>
+# define TOLOWER(x) tolower(x)
#endif
-/* decodes a UTF-8 character from s[] into c. Will not read past e. */
-#define GET_UTF8_CHAR(s, e, c) do { \
- unsigned char x = *s++; \
- if (x < 0x80) c = x; \
- else if (x < 0xC0) c = -1; \
- else if (x < 0xE0) { \
- c = (s >= e) ? -1 : ((x & 0x1F) << 6) | (*s++ & 0x3F); \
- } \
- else if (x < 0xF0) { \
- c = (s+2 > e) ? -1 : ((x & 0x0F) << 12) | ((s[0] & 0x3F) << 6) \
- | (s[1] & 0x3F); \
- s += 2; \
- } \
- else if (x < 0xF8) { \
- c = (s+3 > e) ? -1 : ((x & 0x07) << 18) | ((s[0] & 0x3F) << 12) \
- | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F); \
- s += 3; \
- } \
- else if (x < 0xFC) { \
- c = (s+4 > e) ? -1 : ((x & 0x03) << 24) | ((s[0] & 0x3F) << 18) \
- | ((s[1] & 0x3F) << 12)|((s[2] & 0x3F) << 6)|(s[3] & 0x3F); \
- s += 4; \
- } \
- else if (x < 0xFE) { \
- c = (s+5>e)?-1:((x&1)<<30)|((s[0]&0x3F)<<24)|((s[1]&0x3F)<<18)| \
- ((s[2] & 0x3F) << 12) | ((s[3] & 0x3F) << 6)|(s[4] & 0x3F); \
- s += 5; \
- } \
- else c = -1; \
+/* decodes a UTF-8 character from s[] into c. Will not read past e.
+ * doesn't test that extension bytes are %10xxxxxx.
+ * allows some overlong encodings.
+ */
+#define GET_UTF8_CHAR(s, e, c) do { \
+ unsigned char x = *s++; \
+ if (x < 0x80) c = x; \
+ else if (x >= 0xC2 && x < 0xE0 && s < e) { \
+ c = (x & 0x1F) << 6 | (*s++ & 0x3F); \
+ } \
+ else if (x >= 0xE0 && x < 0xF0 && s+1 < e) { \
+ c = (x & 0x0F) << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); \
+ s += 2; \
+ } \
+ else if (x >= 0xF0 && x <= 0xF5 && s+2 < e) { \
+ c = (x & 0x07) << 18 | (s[0] & 0x3F) << 12 | \
+ (s[1] & 0x3F) << 6 | (s[2] & 0x3F); \
+ if (c > 0x10FFFF) c = 0xFFFD; \
+ s += 3; \
+ } \
+ else c = 0xFFFD; \
} while (0)
/* case-insensitively compares two UTF8 encoded strings. String length for
@@ -844,12 +868,12 @@ static inline int compare(const char *s1, const char *s2, int l1, int l2) {
int c1, c2;
while (p1 < e1 && p2 < e2) {
- GET_UTF8_CHAR(p1, e1, c1);
- GET_UTF8_CHAR(p2, e2, c2);
- if (c1 == c2) continue;
- c1 = TOLOWER(c1);
- c2 = TOLOWER(c2);
- if (c1 != c2) return c1 - c2;
+ GET_UTF8_CHAR(p1, e1, c1);
+ GET_UTF8_CHAR(p2, e2, c2);
+ if (c1 == c2) continue;
+ c1 = TOLOWER(c1);
+ c2 = TOLOWER(c2);
+ if (c1 != c2) return c1 - c2;
}
return l1 - l2;
}
@@ -861,7 +885,7 @@ static inline int compare(const char *s1, const char *s2, int l1, int l2) {
* extracts a file from a CHM helpfile
*/
static int chmd_extract(struct mschm_decompressor *base,
- struct mschmd_file *file, const char *filename)
+ struct mschmd_file *file, const char *filename)
{
struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
struct mspack_system *sys;
@@ -915,7 +939,7 @@ static int chmd_extract(struct mschm_decompressor *base,
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))
+ + file->offset, MSPACK_SYS_SEEK_START))
{
self->error = MSPACK_ERR_SEEK;
}
@@ -923,17 +947,17 @@ static int chmd_extract(struct mschm_decompressor *base,
unsigned char buf[512];
off_t length = file->length;
while (length > 0) {
- int run = sizeof(buf);
- if ((off_t)run > length) run = (int)length;
- if (sys->read(self->d->infh, &buf[0], run) != run) {
- self->error = MSPACK_ERR_READ;
- break;
- }
- if (sys->write(fh, &buf[0], run) != run) {
- self->error = MSPACK_ERR_WRITE;
- break;
- }
- length -= run;
+ int run = sizeof(buf);
+ if ((off_t)run > length) run = (int)length;
+ if (sys->read(self->d->infh, &buf[0], run) != run) {
+ self->error = MSPACK_ERR_READ;
+ break;
+ }
+ if (sys->write(fh, &buf[0], run) != run) {
+ self->error = MSPACK_ERR_WRITE;
+ break;
+ }
+ length -= run;
}
}
break;
@@ -944,8 +968,8 @@ static int chmd_extract(struct mschm_decompressor *base,
*/
if (!self->d->state || (file->offset < self->d->offset)) {
if (self->d->state) {
- lzxd_free(self->d->state);
- self->d->state = NULL;
+ lzxd_free(self->d->state);
+ self->d->state = NULL;
}
if (chmd_init_decomp(self, file)) break;
}
@@ -1009,7 +1033,7 @@ static int chmd_sys_write(struct mspack_file *file, void *buffer, int bytes) {
* file.
*/
static int chmd_init_decomp(struct mschm_decompressor_p *self,
- struct mschmd_file *file)
+ struct mschmd_file *file)
{
int window_size, window_bits, reset_interval, entry, err;
struct mspack_system *sys = self->system;
@@ -1077,7 +1101,7 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
}
/* validate reset_interval */
- if (reset_interval % LZX_FRAME_SIZE) {
+ if (reset_interval == 0 || reset_interval % LZX_FRAME_SIZE) {
D(("bad controldata reset interval"))
return self->error = MSPACK_ERR_DATAFORMAT;
}
@@ -1116,9 +1140,9 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
/* initialise LZX stream */
self->d->state = lzxd_init(&self->d->sys, self->d->infh,
- (struct mspack_file *) self, window_bits,
- reset_interval / LZX_FRAME_SIZE,
- 4096, length);
+ (struct mspack_file *) self, window_bits,
+ reset_interval / LZX_FRAME_SIZE,
+ 4096, length, 0);
if (!self->d->state) self->error = MSPACK_ERR_NOMEMORY;
return self->error;
}
@@ -1131,12 +1155,13 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
* Returns non-zero for success, zero for failure.
*/
static int read_reset_table(struct mschm_decompressor_p *self,
- struct mschmd_sec_mscompressed *sec,
- int entry, off_t *length_ptr, off_t *offset_ptr)
+ struct mschmd_sec_mscompressed *sec,
+ unsigned int entry,
+ off_t *length_ptr, off_t *offset_ptr)
{
struct mspack_system *sys = self->system;
unsigned char *data;
- int pos, entrysize;
+ unsigned int pos, entrysize;
/* do we have a ResetTable file? */
int err = find_sys_file(self, sec, &sec->rtable, rtable_name);
@@ -1144,25 +1169,25 @@ static int read_reset_table(struct mschm_decompressor_p *self,
/* read ResetTable file */
if (sec->rtable->length < lzxrt_headerSIZEOF) {
- D(("ResetTable file is too short"))
- return 0;
+ D(("ResetTable file is too short"))
+ return 0;
}
if (!(data = read_sys_file(self, sec->rtable))) {
- D(("can't read reset table"))
- return 0;
+ D(("can't read reset table"))
+ return 0;
}
/* check sanity of reset table */
if (EndGetI32(&data[lzxrt_FrameLen]) != LZX_FRAME_SIZE) {
- D(("bad reset table frame length"))
- sys->free(data);
- return 0;
+ D(("bad reset table frame length"))
+ sys->free(data);
+ return 0;
}
/* get the uncompressed length of the LZX stream */
- if (read_off64(length_ptr, data, sys, self->d->infh)) {
- sys->free(data);
- return 0;
+ if (read_off64(length_ptr, &data[lzxrt_UncompLen], sys, self->d->infh)) {
+ sys->free(data);
+ return 0;
}
entrysize = EndGetI32(&data[lzxrt_EntrySize]);
@@ -1170,25 +1195,25 @@ static int read_reset_table(struct mschm_decompressor_p *self,
/* ensure reset table entry for this offset exists */
if (entry < EndGetI32(&data[lzxrt_NumEntries]) &&
- ((pos + entrysize) <= sec->rtable->length))
+ pos <= (sec->rtable->length - entrysize))
{
- switch (entrysize) {
- case 4:
- *offset_ptr = EndGetI32(&data[pos]);
- err = 0;
- break;
- case 8:
- err = read_off64(offset_ptr, &data[pos], sys, self->d->infh);
- break;
- default:
- D(("reset table entry size neither 4 nor 8"))
- err = 1;
- break;
- }
+ switch (entrysize) {
+ case 4:
+ *offset_ptr = EndGetI32(&data[pos]);
+ err = 0;
+ break;
+ case 8:
+ err = read_off64(offset_ptr, &data[pos], sys, self->d->infh);
+ break;
+ default:
+ D(("reset table entry size neither 4 nor 8"))
+ err = 1;
+ break;
+ }
}
else {
- D(("bad reset interval"))
- err = 1;
+ D(("bad reset interval"))
+ err = 1;
}
/* free the reset table */
@@ -1205,8 +1230,8 @@ static int read_reset_table(struct mschm_decompressor_p *self,
* Returns zero for success or a non-zero error code for failure.
*/
static int read_spaninfo(struct mschm_decompressor_p *self,
- struct mschmd_sec_mscompressed *sec,
- off_t *length_ptr)
+ struct mschmd_sec_mscompressed *sec,
+ off_t *length_ptr)
{
struct mspack_system *sys = self->system;
unsigned char *data;
@@ -1217,21 +1242,27 @@ static int read_spaninfo(struct mschm_decompressor_p *self,
/* check it's large enough */
if (sec->spaninfo->length != 8) {
- D(("SpanInfo file is wrong size"))
- return MSPACK_ERR_DATAFORMAT;
+ D(("SpanInfo file is wrong size"))
+ return MSPACK_ERR_DATAFORMAT;
}
/* read the SpanInfo file */
if (!(data = read_sys_file(self, sec->spaninfo))) {
- D(("can't read SpanInfo file"))
- return self->error;
+ D(("can't read SpanInfo file"))
+ return self->error;
}
/* get the uncompressed length of the LZX stream */
err = read_off64(length_ptr, data, sys, self->d->infh);
-
sys->free(data);
- return (err) ? MSPACK_ERR_DATAFORMAT : MSPACK_ERR_OK;
+ if (err) return MSPACK_ERR_DATAFORMAT;
+
+ if (*length_ptr <= 0) {
+ D(("output length is invalid"))
+ return MSPACK_ERR_DATAFORMAT;
+ }
+
+ return MSPACK_ERR_OK;
}
/***************************************
@@ -1242,8 +1273,8 @@ static int read_spaninfo(struct mschm_decompressor_p *self,
* for success, non-zero for both failure and the file not existing.
*/
static int find_sys_file(struct mschm_decompressor_p *self,
- struct mschmd_sec_mscompressed *sec,
- struct mschmd_file **f_ptr, const char *name)
+ struct mschmd_sec_mscompressed *sec,
+ struct mschmd_file **f_ptr, const char *name)
{
struct mspack_system *sys = self->system;
struct mschmd_file result;
@@ -1254,13 +1285,13 @@ static int find_sys_file(struct mschm_decompressor_p *self,
/* try using fast_find to find the file - return DATAFORMAT error if
* it fails, or successfully doesn't find the file */
if (chmd_fast_find((struct mschm_decompressor *) self, sec->base.chm,
- name, &result, (int)sizeof(result)) || !result.section)
+ name, &result, (int)sizeof(result)) || !result.section)
{
- return MSPACK_ERR_DATAFORMAT;
+ return MSPACK_ERR_DATAFORMAT;
}
if (!(*f_ptr = (struct mschmd_file *) sys->alloc(sys, sizeof(result)))) {
- return MSPACK_ERR_NOMEMORY;
+ return MSPACK_ERR_NOMEMORY;
}
/* copy result */
@@ -1280,7 +1311,7 @@ static int find_sys_file(struct mschm_decompressor_p *self,
* memory.
*/
static unsigned char *read_sys_file(struct mschm_decompressor_p *self,
- struct mschmd_file *file)
+ struct mschmd_file *file)
{
struct mspack_system *sys = self->system;
unsigned char *data = NULL;
@@ -1298,7 +1329,7 @@ static unsigned char *read_sys_file(struct mschm_decompressor_p *self,
return NULL;
}
if (sys->seek(self->d->infh, file->section->chm->sec0.offset
- + file->offset, MSPACK_SYS_SEEK_START))
+ + file->offset, MSPACK_SYS_SEEK_START))
{
self->error = MSPACK_ERR_SEEK;
sys->free(data);
@@ -1331,15 +1362,15 @@ static int chmd_error(struct mschm_decompressor *base) {
* are accepted, offsets beyond that cause an error message.
*/
static int read_off64(off_t *var, unsigned char *mem,
- struct mspack_system *sys, struct mspack_file *fh)
+ struct mspack_system *sys, struct mspack_file *fh)
{
-#ifdef LARGEFILE_SUPPORT
+#if LARGEFILE_SUPPORT
*var = EndGetI64(mem);
#else
*var = EndGetI32(mem);
if ((*var & 0x80000000) || EndGetI32(mem+4)) {
- sys->message(fh, (char *)largefile_msg);
- return 1;
+ sys->message(fh, (char *)largefile_msg);
+ return 1;
}
#endif
return 0;
diff --git a/rbutil/rbutilqt/mspack/kwajd.c b/rbutil/rbutilqt/mspack/kwajd.c
index 440f1dcfdd..24e0b0613b 100644
--- a/rbutil/rbutilqt/mspack/kwajd.c
+++ b/rbutil/rbutilqt/mspack/kwajd.c
@@ -1,5 +1,5 @@
/* This file is part of libmspack.
- * (C) 2003-2010 Stuart Caie.
+ * (C) 2003-2011 Stuart Caie.
*
* KWAJ is a format very similar to SZDD. KWAJ method 3 (LZH) was
* written by Jeff Johnson.
@@ -14,6 +14,7 @@
#include "system-mspack.h"
#include "kwaj.h"
+#include "mszip.h"
/* prototypes */
static struct mskwajd_header *kwajd_open(
@@ -40,7 +41,7 @@ static void lzh_free(
static int lzh_read_lens(
struct kwajd_stream *kwaj,
unsigned int type, unsigned int numsyms,
- unsigned char *lens, unsigned short *table);
+ unsigned char *lens);
static int lzh_read_input(
struct kwajd_stream *kwaj);
@@ -79,8 +80,8 @@ void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *base)
{
struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
if (self) {
- struct mspack_system *sys = self->system;
- sys->free(self);
+ struct mspack_system *sys = self->system;
+ sys->free(self);
}
}
@@ -90,7 +91,7 @@ void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *base)
* opens a KWAJ file without decompressing, reads header
*/
static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base,
- const char *filename)
+ const char *filename)
{
struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
struct mskwajd_header *hdr;
@@ -103,18 +104,18 @@ static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base,
fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
hdr = (struct mskwajd_header *) sys->alloc(sys, sizeof(struct mskwajd_header_p));
if (fh && hdr) {
- ((struct mskwajd_header_p *) hdr)->fh = fh;
- self->error = kwajd_read_headers(sys, fh, hdr);
+ ((struct mskwajd_header_p *) hdr)->fh = fh;
+ self->error = kwajd_read_headers(sys, fh, hdr);
}
else {
- if (!fh) self->error = MSPACK_ERR_OPEN;
- if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
+ if (!fh) self->error = MSPACK_ERR_OPEN;
+ if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
}
if (self->error) {
- if (fh) sys->close(fh);
- if (hdr) sys->free(hdr);
- hdr = NULL;
+ if (fh) sys->close(fh);
+ sys->free(hdr);
+ hdr = NULL;
}
return hdr;
@@ -126,7 +127,7 @@ static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base,
* closes a KWAJ file
*/
static void kwajd_close(struct mskwaj_decompressor *base,
- struct mskwajd_header *hdr)
+ struct mskwajd_header *hdr)
{
struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
struct mskwajd_header_p *hdr_p = (struct mskwajd_header_p *) hdr;
@@ -148,22 +149,22 @@ static void kwajd_close(struct mskwaj_decompressor *base,
* reads the headers of a KWAJ format file
*/
static int kwajd_read_headers(struct mspack_system *sys,
- struct mspack_file *fh,
- struct mskwajd_header *hdr)
+ struct mspack_file *fh,
+ struct mskwajd_header *hdr)
{
unsigned char buf[16];
int i;
/* read in the header */
if (sys->read(fh, &buf[0], kwajh_SIZEOF) != kwajh_SIZEOF) {
- return MSPACK_ERR_READ;
+ return MSPACK_ERR_READ;
}
/* check for "KWAJ" signature */
if (((unsigned int) EndGetI32(&buf[kwajh_Signature1]) != 0x4A41574B) ||
- ((unsigned int) EndGetI32(&buf[kwajh_Signature2]) != 0xD127F088))
+ ((unsigned int) EndGetI32(&buf[kwajh_Signature2]) != 0xD127F088))
{
- return MSPACK_ERR_SIGNATURE;
+ return MSPACK_ERR_SIGNATURE;
}
/* basic header fields */
@@ -179,61 +180,67 @@ static int kwajd_read_headers(struct mspack_system *sys,
/* 4 bytes: length of unpacked file */
if (hdr->headers & MSKWAJ_HDR_HASLENGTH) {
- if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ;
- hdr->length = EndGetI32(&buf[0]);
+ if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ;
+ hdr->length = EndGetI32(&buf[0]);
}
/* 2 bytes: unknown purpose */
if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN1) {
- if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
+ if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
}
/* 2 bytes: length of section, then [length] bytes: unknown purpose */
if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN2) {
- if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
- i = EndGetI16(&buf[0]);
- if (sys->seek(fh, (off_t)i, MSPACK_SYS_SEEK_CUR)) return MSPACK_ERR_SEEK;
+ if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
+ i = EndGetI16(&buf[0]);
+ if (sys->seek(fh, (off_t)i, MSPACK_SYS_SEEK_CUR)) return MSPACK_ERR_SEEK;
}
/* filename and extension */
if (hdr->headers & (MSKWAJ_HDR_HASFILENAME | MSKWAJ_HDR_HASFILEEXT)) {
- off_t pos = sys->tell(fh);
- char *fn = (char *) sys->alloc(sys, (size_t) 13);
-
- /* allocate memory for maximum length filename */
- if (! fn) return MSPACK_ERR_NOMEMORY;
- hdr->filename = fn;
-
- /* copy filename if present */
- if (hdr->headers & MSKWAJ_HDR_HASFILENAME) {
- if (sys->read(fh, &buf[0], 9) != 9) return MSPACK_ERR_READ;
- for (i = 0; i < 9; i++, fn++) if (!(*fn = buf[i])) break;
- pos += (i < 9) ? i+1 : 9;
- if (sys->seek(fh, pos, MSPACK_SYS_SEEK_START))
- return MSPACK_ERR_SEEK;
- }
-
- /* copy extension if present */
- if (hdr->headers & MSKWAJ_HDR_HASFILEEXT) {
- *fn++ = '.';
- if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ;
- for (i = 0; i < 4; i++, fn++) if (!(*fn = buf[i])) break;
- pos += (i < 4) ? i+1 : 4;
- if (sys->seek(fh, pos, MSPACK_SYS_SEEK_START))
- return MSPACK_ERR_SEEK;
- }
- *fn = '\0';
+ int len;
+ /* allocate memory for maximum length filename */
+ char *fn = (char *) sys->alloc(sys, (size_t) 13);
+ if (!(hdr->filename = fn)) return MSPACK_ERR_NOMEMORY;
+
+ /* copy filename if present */
+ if (hdr->headers & MSKWAJ_HDR_HASFILENAME) {
+ /* read and copy up to 9 bytes of a null terminated string */
+ if ((len = sys->read(fh, &buf[0], 9)) < 2) return MSPACK_ERR_READ;
+ for (i = 0; i < len; i++) if (!(*fn++ = buf[i])) break;
+ /* if string was 9 bytes with no null terminator, reject it */
+ if (i == 9 && buf[8] != '\0') return MSPACK_ERR_DATAFORMAT;
+ /* seek to byte after string ended in file */
+ if (sys->seek(fh, (off_t)(i + 1 - len), MSPACK_SYS_SEEK_CUR))
+ return MSPACK_ERR_SEEK;
+ fn--; /* remove the null terminator */
+ }
+
+ /* copy extension if present */
+ if (hdr->headers & MSKWAJ_HDR_HASFILEEXT) {
+ *fn++ = '.';
+ /* read and copy up to 4 bytes of a null terminated string */
+ if ((len = sys->read(fh, &buf[0], 4)) < 2) return MSPACK_ERR_READ;
+ for (i = 0; i < len; i++) if (!(*fn++ = buf[i])) break;
+ /* if string was 4 bytes with no null terminator, reject it */
+ if (i == 4 && buf[3] != '\0') return MSPACK_ERR_DATAFORMAT;
+ /* seek to byte after string ended in file */
+ if (sys->seek(fh, (off_t)(i + 1 - len), MSPACK_SYS_SEEK_CUR))
+ return MSPACK_ERR_SEEK;
+ fn--; /* remove the null terminator */
+ }
+ *fn = '\0';
}
/* 2 bytes: extra text length then [length] bytes of extra text data */
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);
- if (! hdr->extra) return MSPACK_ERR_NOMEMORY;
- if (sys->read(fh, hdr->extra, i) != i) return MSPACK_ERR_READ;
- hdr->extra[i] = '\0';
- hdr->extra_length = i;
+ 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);
+ if (! hdr->extra) return MSPACK_ERR_NOMEMORY;
+ if (sys->read(fh, hdr->extra, i) != i) return MSPACK_ERR_READ;
+ hdr->extra[i] = '\0';
+ hdr->extra_length = i;
}
return MSPACK_ERR_OK;
}
@@ -244,7 +251,7 @@ static int kwajd_read_headers(struct mspack_system *sys,
* decompresses a KWAJ file
*/
static int kwajd_extract(struct mskwaj_decompressor *base,
- struct mskwajd_header *hdr, const char *filename)
+ struct mskwajd_header *hdr, const char *filename)
{
struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
struct mspack_system *sys;
@@ -258,51 +265,56 @@ static int kwajd_extract(struct mskwaj_decompressor *base,
/* seek to the compressed data */
if (sys->seek(fh, hdr->data_offset, MSPACK_SYS_SEEK_START)) {
- return self->error = MSPACK_ERR_SEEK;
+ return self->error = MSPACK_ERR_SEEK;
}
/* open file for output */
if (!(outfh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
- return self->error = MSPACK_ERR_OPEN;
+ return self->error = MSPACK_ERR_OPEN;
}
self->error = MSPACK_ERR_OK;
/* decompress based on format */
if (hdr->comp_type == MSKWAJ_COMP_NONE ||
- hdr->comp_type == MSKWAJ_COMP_XOR)
+ 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);
- if (buf) {
- int read, i;
- while ((read = sys->read(fh, buf, KWAJ_INPUT_SIZE)) > 0) {
- if (hdr->comp_type == MSKWAJ_COMP_XOR) {
- for (i = 0; i < read; i++) buf[i] ^= 0xFF;
- }
- if (sys->write(outfh, buf, read) != read) {
- self->error = MSPACK_ERR_WRITE;
- break;
- }
- }
- if (read < 0) self->error = MSPACK_ERR_READ;
- sys->free(buf);
- }
- else {
- self->error = MSPACK_ERR_NOMEMORY;
- }
+ /* 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);
+ if (buf) {
+ int read, i;
+ while ((read = sys->read(fh, buf, KWAJ_INPUT_SIZE)) > 0) {
+ if (hdr->comp_type == MSKWAJ_COMP_XOR) {
+ for (i = 0; i < read; i++) buf[i] ^= 0xFF;
+ }
+ if (sys->write(outfh, buf, read) != read) {
+ self->error = MSPACK_ERR_WRITE;
+ break;
+ }
+ }
+ if (read < 0) self->error = MSPACK_ERR_READ;
+ sys->free(buf);
+ }
+ else {
+ self->error = MSPACK_ERR_NOMEMORY;
+ }
}
else if (hdr->comp_type == MSKWAJ_COMP_SZDD) {
- self->error = lzss_decompress(sys, fh, outfh, KWAJ_INPUT_SIZE,
- LZSS_MODE_EXPAND);
+ self->error = lzss_decompress(sys, fh, outfh, KWAJ_INPUT_SIZE,
+ LZSS_MODE_EXPAND);
}
else if (hdr->comp_type == MSKWAJ_COMP_LZH) {
- struct kwajd_stream *lzh = lzh_init(sys, fh, outfh);
- self->error = (lzh) ? lzh_decompress(lzh) : MSPACK_ERR_NOMEMORY;
- lzh_free(lzh);
+ struct kwajd_stream *lzh = lzh_init(sys, fh, outfh);
+ self->error = (lzh) ? lzh_decompress(lzh) : MSPACK_ERR_NOMEMORY;
+ lzh_free(lzh);
+ }
+ else if (hdr->comp_type == MSKWAJ_COMP_MSZIP) {
+ struct mszipd_stream *zip = mszipd_init(sys,fh,outfh,KWAJ_INPUT_SIZE,0);
+ self->error = (zip) ? mszipd_decompress_kwaj(zip) : MSPACK_ERR_NOMEMORY;
+ mszipd_free(zip);
}
else {
- self->error = MSPACK_ERR_DATAFORMAT;
+ self->error = MSPACK_ERR_DATAFORMAT;
}
/* close output file */
@@ -317,7 +329,7 @@ static int kwajd_extract(struct mskwaj_decompressor *base,
* unpacks directly from input to output
*/
static int kwajd_decompress(struct mskwaj_decompressor *base,
- const char *input, const char *output)
+ const char *input, const char *output)
{
struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
struct mskwajd_header *hdr;
@@ -353,15 +365,15 @@ static int kwajd_error(struct mskwaj_decompressor *base)
#define BITS_VAR lzh
#define BITS_ORDER_MSB
#define BITS_NO_READ_INPUT
-#define READ_BYTES do { \
- if (i_ptr >= i_end) { \
- if ((err = lzh_read_input(lzh))) return err; \
- i_ptr = lzh->i_ptr; \
- i_end = lzh->i_end; \
- } \
- INJECT_BITS(*i_ptr++, 8); \
+#define READ_BYTES do { \
+ if (i_ptr >= i_end) { \
+ if ((err = lzh_read_input(lzh))) return err; \
+ i_ptr = lzh->i_ptr; \
+ i_end = lzh->i_end; \
+ } \
+ INJECT_BITS(*i_ptr++, 8); \
} while (0)
-#include "readbits.h"
+#include <readbits.h>
/* import huffman-reading macros and code */
#define TABLEBITS(tbl) KWAJ_TABLEBITS
@@ -369,7 +381,7 @@ static int kwajd_error(struct mskwaj_decompressor *base)
#define HUFF_TABLE(tbl,idx) lzh->tbl##_table[idx]
#define HUFF_LEN(tbl,idx) lzh->tbl##_len[idx]
#define HUFF_ERROR return MSPACK_ERR_DATAFORMAT
-#include "readhuff.h"
+#include <readhuff.h>
/* In the KWAJ LZH format, there is no special 'eof' marker, it just
* ends. Depending on how many bits are left in the final byte when
@@ -381,31 +393,30 @@ static int kwajd_error(struct mskwaj_decompressor *base)
* isn't how the default readbits.h read_input() works (it simply lets
* 2 fake bytes in then stops), so we implement our own.
*/
-#define READ_BITS_SAFE(val, n) do { \
- READ_BITS(val, n); \
- if (lzh->input_end && bits_left < lzh->input_end) \
- return MSPACK_ERR_OK; \
+#define READ_BITS_SAFE(val, n) do { \
+ READ_BITS(val, n); \
+ if (lzh->input_end && bits_left < lzh->input_end) \
+ return MSPACK_ERR_OK; \
} while (0)
-#define READ_HUFFSYM_SAFE(tbl, val) do { \
- READ_HUFFSYM(tbl, val); \
- if (lzh->input_end && bits_left < lzh->input_end) \
- return MSPACK_ERR_OK; \
+#define READ_HUFFSYM_SAFE(tbl, val) do { \
+ READ_HUFFSYM(tbl, val); \
+ if (lzh->input_end && bits_left < lzh->input_end) \
+ return MSPACK_ERR_OK; \
} while (0)
-#define BUILD_TREE(tbl, type) \
- STORE_BITS; \
- err = lzh_read_lens(lzh, type, MAXSYMBOLS(tbl), \
- &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0)); \
- if (err) return err; \
- RESTORE_BITS; \
- if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
- &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
- return MSPACK_ERR_DATAFORMAT;
-
-#define WRITE_BYTE do { \
- if (lzh->sys->write(lzh->output, &lzh->window[pos], 1) != 1) \
- return MSPACK_ERR_WRITE; \
+#define BUILD_TREE(tbl, type) \
+ STORE_BITS; \
+ err = lzh_read_lens(lzh, type, MAXSYMBOLS(tbl), &HUFF_LEN(tbl,0)); \
+ if (err) return err; \
+ RESTORE_BITS; \
+ if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
+ &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
+ return MSPACK_ERR_DATAFORMAT;
+
+#define WRITE_BYTE do { \
+ if (lzh->sys->write(lzh->output, &lzh->window[pos], 1) != 1) \
+ return MSPACK_ERR_WRITE; \
} while (0)
static struct kwajd_stream *lzh_init(struct mspack_system *sys,
@@ -447,33 +458,33 @@ static int lzh_decompress(struct kwajd_stream *lzh)
BUILD_TREE(LITERAL, types[4]);
while (!lzh->input_end) {
- if (lit_run) READ_HUFFSYM_SAFE(MATCHLEN2, len);
- else READ_HUFFSYM_SAFE(MATCHLEN1, len);
-
- if (len > 0) {
- len += 2;
- lit_run = 0; /* not the end of a literal run */
- READ_HUFFSYM_SAFE(OFFSET, j); offset = j << 6;
- READ_BITS_SAFE(j, 6); offset |= j;
-
- /* copy match as output and into the ring buffer */
- while (len-- > 0) {
- lzh->window[pos] = lzh->window[(pos+4096-offset) & 4095];
- WRITE_BYTE;
- pos++; pos &= 4095;
- }
- }
- else {
- READ_HUFFSYM_SAFE(LITLEN, len); len++;
- lit_run = (len == 32) ? 0 : 1; /* end of a literal run? */
- while (len-- > 0) {
- READ_HUFFSYM_SAFE(LITERAL, j);
- /* copy as output and into the ring buffer */
- lzh->window[pos] = j;
- WRITE_BYTE;
- pos++; pos &= 4095;
- }
- }
+ if (lit_run) READ_HUFFSYM_SAFE(MATCHLEN2, len);
+ else READ_HUFFSYM_SAFE(MATCHLEN1, len);
+
+ if (len > 0) {
+ len += 2;
+ lit_run = 0; /* not the end of a literal run */
+ READ_HUFFSYM_SAFE(OFFSET, j); offset = j << 6;
+ READ_BITS_SAFE(j, 6); offset |= j;
+
+ /* copy match as output and into the ring buffer */
+ while (len-- > 0) {
+ lzh->window[pos] = lzh->window[(pos+4096-offset) & 4095];
+ WRITE_BYTE;
+ pos++; pos &= 4095;
+ }
+ }
+ else {
+ READ_HUFFSYM_SAFE(LITLEN, len); len++;
+ lit_run = (len == 32) ? 0 : 1; /* end of a literal run? */
+ while (len-- > 0) {
+ READ_HUFFSYM_SAFE(LITERAL, j);
+ /* copy as output and into the ring buffer */
+ lzh->window[pos] = j;
+ WRITE_BYTE;
+ pos++; pos &= 4095;
+ }
+ }
}
return MSPACK_ERR_OK;
}
@@ -487,8 +498,8 @@ static void lzh_free(struct kwajd_stream *lzh)
}
static int lzh_read_lens(struct kwajd_stream *lzh,
- unsigned int type, unsigned int numsyms,
- unsigned char *lens, unsigned short *table)
+ unsigned int type, unsigned int numsyms,
+ unsigned char *lens)
{
register unsigned int bit_buffer;
register int bits_left;
@@ -499,33 +510,33 @@ static int lzh_read_lens(struct kwajd_stream *lzh,
RESTORE_BITS;
switch (type) {
case 0:
- i = numsyms; c = (i==16)?4: (i==32)?5: (i==64)?6: (i==256)?8 :0;
- for (i = 0; i < numsyms; i++) lens[i] = c;
- break;
+ i = numsyms; c = (i==16)?4: (i==32)?5: (i==64)?6: (i==256)?8 :0;
+ for (i = 0; i < numsyms; i++) lens[i] = c;
+ break;
case 1:
- READ_BITS_SAFE(c, 4); lens[0] = c;
- for (i = 1; i < numsyms; i++) {
- READ_BITS_SAFE(sel, 1); if (sel == 0) lens[i] = c;
- else { READ_BITS_SAFE(sel, 1); if (sel == 0) lens[i] = ++c;
- else { READ_BITS_SAFE(c, 4); lens[i] = c; }}
- }
- break;
+ READ_BITS_SAFE(c, 4); lens[0] = c;
+ for (i = 1; i < numsyms; i++) {
+ READ_BITS_SAFE(sel, 1); if (sel == 0) lens[i] = c;
+ else { READ_BITS_SAFE(sel, 1); if (sel == 0) lens[i] = ++c;
+ else { READ_BITS_SAFE(c, 4); lens[i] = c; }}
+ }
+ break;
case 2:
- READ_BITS_SAFE(c, 4); lens[0] = c;
- for (i = 1; i < numsyms; i++) {
- READ_BITS_SAFE(sel, 2);
- if (sel == 3) READ_BITS_SAFE(c, 4); else c += (char) sel-1;
- lens[i] = c;
- }
- break;
+ READ_BITS_SAFE(c, 4); lens[0] = c;
+ for (i = 1; i < numsyms; i++) {
+ READ_BITS_SAFE(sel, 2);
+ if (sel == 3) READ_BITS_SAFE(c, 4); else c += (char) sel-1;
+ lens[i] = c;
+ }
+ break;
case 3:
- for (i = 0; i < numsyms; i++) {
- READ_BITS_SAFE(c, 4); lens[i] = c;
- }
- break;
+ for (i = 0; i < numsyms; i++) {
+ READ_BITS_SAFE(c, 4); lens[i] = c;
+ }
+ break;
}
STORE_BITS;
return MSPACK_ERR_OK;
@@ -534,18 +545,18 @@ static int lzh_read_lens(struct kwajd_stream *lzh,
static int lzh_read_input(struct kwajd_stream *lzh) {
int read;
if (lzh->input_end) {
- lzh->input_end += 8;
- lzh->inbuf[0] = 0;
- read = 1;
+ lzh->input_end += 8;
+ lzh->inbuf[0] = 0;
+ read = 1;
}
else {
- read = lzh->sys->read(lzh->input, &lzh->inbuf[0], KWAJ_INPUT_SIZE);
- if (read < 0) return MSPACK_ERR_READ;
- if (read == 0) {
- lzh->input_end = 8;
- lzh->inbuf[0] = 0;
- read = 1;
- }
+ read = lzh->sys->read(lzh->input, &lzh->inbuf[0], KWAJ_INPUT_SIZE);
+ if (read < 0) return MSPACK_ERR_READ;
+ if (read == 0) {
+ lzh->input_end = 8;
+ lzh->inbuf[0] = 0;
+ read = 1;
+ }
}
/* update i_ptr and i_end */
diff --git a/rbutil/rbutilqt/mspack/lzss.h b/rbutil/rbutilqt/mspack/lzss.h
index 55e761b5bf..aa946e52ae 100644
--- a/rbutil/rbutilqt/mspack/lzss.h
+++ b/rbutil/rbutilqt/mspack/lzss.h
@@ -54,10 +54,10 @@ extern "C" {
* @return an error code, or MSPACK_ERR_OK if successful
*/
extern int lzss_decompress(struct mspack_system *system,
- struct mspack_file *input,
- struct mspack_file *output,
- int input_buffer_size,
- int mode);
+ struct mspack_file *input,
+ struct mspack_file *output,
+ int input_buffer_size,
+ int mode);
#ifdef __cplusplus
}
diff --git a/rbutil/rbutilqt/mspack/lzssd.c b/rbutil/rbutilqt/mspack/lzssd.c
index f1a47c7a01..63716d414a 100644
--- a/rbutil/rbutilqt/mspack/lzssd.c
+++ b/rbutil/rbutilqt/mspack/lzssd.c
@@ -14,31 +14,31 @@
#include "system-mspack.h"
#include "lzss.h"
-#define ENSURE_BYTES do { \
- if (i_ptr >= i_end) { \
- read = system->read(input, &inbuf[0], \
- input_buffer_size); \
- if (read <= 0) { \
- system->free(window); \
- return (read < 0) ? MSPACK_ERR_READ \
- : MSPACK_ERR_OK; \
- } \
- i_ptr = &inbuf[0]; i_end = &inbuf[read]; \
- } \
+#define ENSURE_BYTES do { \
+ if (i_ptr >= i_end) { \
+ read = system->read(input, &inbuf[0], \
+ input_buffer_size); \
+ if (read <= 0) { \
+ system->free(window); \
+ return (read < 0) ? MSPACK_ERR_READ \
+ : MSPACK_ERR_OK; \
+ } \
+ i_ptr = &inbuf[0]; i_end = &inbuf[read]; \
+ } \
} while (0)
-#define WRITE_BYTE do { \
- if (system->write(output, &window[pos], 1) != 1) { \
- system->free(window); \
- return MSPACK_ERR_WRITE; \
- } \
+#define WRITE_BYTE do { \
+ if (system->write(output, &window[pos], 1) != 1) { \
+ system->free(window); \
+ return MSPACK_ERR_WRITE; \
+ } \
} while (0)
int lzss_decompress(struct mspack_system *system,
- struct mspack_file *input,
- struct mspack_file *output,
- int input_buffer_size,
- int mode)
+ struct mspack_file *input,
+ struct mspack_file *output,
+ int input_buffer_size,
+ int mode)
{
unsigned char *window, *inbuf, *i_ptr, *i_end;
unsigned int pos, i, c, invert, mpos, len;
@@ -48,7 +48,7 @@ int lzss_decompress(struct mspack_system *system,
if (!system || input_buffer_size < 1 || (mode != LZSS_MODE_EXPAND &&
mode != LZSS_MODE_MSHELP && mode != LZSS_MODE_QBASIC))
{
- return MSPACK_ERR_ARGS;
+ return MSPACK_ERR_ARGS;
}
/* allocate memory */
@@ -64,27 +64,27 @@ int lzss_decompress(struct mspack_system *system,
/* loop forever; exit condition is in ENSURE_BYTES macro */
for (;;) {
- ENSURE_BYTES; c = *i_ptr++ ^ invert;
- for (i = 0x01; i & 0xFF; i <<= 1) {
- if (c & i) {
- /* literal */
- ENSURE_BYTES; window[pos] = *i_ptr++;
- WRITE_BYTE;
- pos++; pos &= LZSS_WINDOW_SIZE - 1;
- }
- else {
- /* match */
- ENSURE_BYTES; mpos = *i_ptr++;
- ENSURE_BYTES; mpos |= (*i_ptr & 0xF0) << 4;
- len = (*i_ptr++ & 0x0F) + 3;
- while (len--) {
- window[pos] = window[mpos];
- WRITE_BYTE;
- pos++; pos &= LZSS_WINDOW_SIZE - 1;
- mpos++; mpos &= LZSS_WINDOW_SIZE - 1;
- }
- }
- }
+ ENSURE_BYTES; c = *i_ptr++ ^ invert;
+ for (i = 0x01; i & 0xFF; i <<= 1) {
+ if (c & i) {
+ /* literal */
+ ENSURE_BYTES; window[pos] = *i_ptr++;
+ WRITE_BYTE;
+ pos++; pos &= LZSS_WINDOW_SIZE - 1;
+ }
+ else {
+ /* match */
+ ENSURE_BYTES; mpos = *i_ptr++;
+ ENSURE_BYTES; mpos |= (*i_ptr & 0xF0) << 4;
+ len = (*i_ptr++ & 0x0F) + 3;
+ while (len--) {
+ window[pos] = window[mpos];
+ WRITE_BYTE;
+ pos++; pos &= LZSS_WINDOW_SIZE - 1;
+ mpos++; mpos &= LZSS_WINDOW_SIZE - 1;
+ }
+ }
+ }
}
/* not reached */
diff --git a/rbutil/rbutilqt/mspack/lzx.h b/rbutil/rbutilqt/mspack/lzx.h
index fc69928c96..a6152f622b 100644
--- a/rbutil/rbutilqt/mspack/lzx.h
+++ b/rbutil/rbutilqt/mspack/lzx.h
@@ -1,5 +1,5 @@
/* This file is part of libmspack.
- * (C) 2003-2004 Stuart Caie.
+ * (C) 2003-2013 Stuart Caie.
*
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
* by Microsoft Corporation.
@@ -35,7 +35,7 @@ extern "C" {
/* LZX huffman defines: tweak tablebits as desired */
#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
#define LZX_PRETREE_TABLEBITS (6)
-#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8)
+#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 290*8)
#define LZX_MAINTREE_TABLEBITS (12)
#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
#define LZX_LENGTH_TABLEBITS (12)
@@ -55,6 +55,8 @@ struct lzxd_stream {
unsigned char *window; /* decoding window */
unsigned int window_size; /* window size */
+ unsigned int ref_data_size; /* LZX DELTA reference data size */
+ unsigned int num_offsets; /* number of match_offset entries in table */
unsigned int window_posn; /* decompression offset within window */
unsigned int frame_posn; /* current frame offset within in window */
unsigned int frame; /* the number of 32kb frames processed */
@@ -70,8 +72,8 @@ struct lzxd_stream {
unsigned char intel_started; /* has intel E8 decoding started? */
unsigned char block_type; /* type of the current block */
unsigned char header_read; /* have we started decoding at all yet? */
- unsigned char posn_slots; /* how many posn slots in stream? */
unsigned char input_end; /* have we reached the end of input? */
+ unsigned char is_delta; /* does stream follow LZX DELTA spec? */
int error;
@@ -87,13 +89,13 @@ struct lzxd_stream {
/* huffman decoding tables */
unsigned short PRETREE_table [(1 << LZX_PRETREE_TABLEBITS) +
- (LZX_PRETREE_MAXSYMBOLS * 2)];
+ (LZX_PRETREE_MAXSYMBOLS * 2)];
unsigned short MAINTREE_table[(1 << LZX_MAINTREE_TABLEBITS) +
- (LZX_MAINTREE_MAXSYMBOLS * 2)];
+ (LZX_MAINTREE_MAXSYMBOLS * 2)];
unsigned short LENGTH_table [(1 << LZX_LENGTH_TABLEBITS) +
- (LZX_LENGTH_MAXSYMBOLS * 2)];
+ (LZX_LENGTH_MAXSYMBOLS * 2)];
unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) +
- (LZX_ALIGNED_MAXSYMBOLS * 2)];
+ (LZX_ALIGNED_MAXSYMBOLS * 2)];
unsigned char LENGTH_empty;
/* this is used purely for doing the intel E8 transform */
@@ -114,12 +116,14 @@ struct lzxd_stream {
* @param input an input stream with the LZX data.
* @param output an output stream to write the decoded data to.
* @param window_bits the size of the decoding window, which must be
- * between 15 and 21 inclusive.
+ * between 15 and 21 inclusive for regular LZX
+ * data, or between 17 and 25 inclusive for
+ * LZX DELTA data.
* @param reset_interval the interval at which the LZX bitstream is
* reset, in multiples of LZX frames (32678
* bytes), e.g. a value of 2 indicates the input
* stream resets after every 65536 output bytes.
- * A value of 0 indicates that the bistream never
+ * A value of 0 indicates that the bitstream never
* resets, such as in CAB LZX streams.
* @param input_buffer_size the number of bytes to use as an input
* bitstream buffer.
@@ -135,26 +139,49 @@ struct lzxd_stream {
* lzxd_set_output_length() once it is
* known. If never set, 4 of the final 6 bytes
* of the output stream may be incorrect.
+ * @param is_delta should be zero for all regular LZX data,
+ * non-zero for LZX DELTA encoded data.
* @return a pointer to an initialised lzxd_stream structure, or NULL if
* there was not enough memory or parameters to the function were wrong.
*/
extern struct lzxd_stream *lzxd_init(struct mspack_system *system,
- struct mspack_file *input,
- struct mspack_file *output,
- int window_bits,
- int reset_interval,
- int input_buffer_size,
- off_t output_length);
+ struct mspack_file *input,
+ struct mspack_file *output,
+ int window_bits,
+ int reset_interval,
+ int input_buffer_size,
+ off_t output_length,
+ char is_delta);
/* see description of output_length in lzxd_init() */
extern void lzxd_set_output_length(struct lzxd_stream *lzx,
- off_t output_length);
+ off_t output_length);
+
+/**
+ * Reads LZX DELTA reference data into the window and allows
+ * lzxd_decompress() to reference it.
+ *
+ * Call this before the first call to lzxd_decompress().
+
+ * @param lzx the LZX stream to apply this reference data to
+ * @param system an mspack_system implementation to use with the
+ * input param. Only read() will be called.
+ * @param input an input file handle to read reference data using
+ * system->read().
+ * @param length the length of the reference data. Cannot be longer
+ * than the LZX window size.
+ * @return an error code, or MSPACK_ERR_OK if successful
+ */
+extern int lzxd_set_reference_data(struct lzxd_stream *lzx,
+ struct mspack_system *system,
+ struct mspack_file *input,
+ unsigned int length);
/**
* Decompresses entire or partial LZX streams.
*
* The number of bytes of data that should be decompressed is given as the
- * out_bytes parameter. If more bytes are decoded than are needed, they
+ * out_bytes parameter. If more bytes are decoded than are needed, they
* will be kept over for a later invocation.
*
* The output bytes will be passed to the system->write() function given in
diff --git a/rbutil/rbutilqt/mspack/lzxd.c b/rbutil/rbutilqt/mspack/lzxd.c
index 9b26bac3e0..88cfd90c2a 100644
--- a/rbutil/rbutilqt/mspack/lzxd.c
+++ b/rbutil/rbutilqt/mspack/lzxd.c
@@ -1,5 +1,5 @@
/* This file is part of libmspack.
- * (C) 2003-2004 Stuart Caie.
+ * (C) 2003-2013 Stuart Caie.
*
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
* by Microsoft Corporation.
@@ -70,6 +70,10 @@
* The maximum window size has increased from 2MB to 32MB. This also
* increases the maximum number of position slots, etc.
*
+ * If the match length is 257 (the maximum possible), this signals
+ * a further length decoding step, that allows for matches up to
+ * 33024 bytes long.
+ *
* The format now allows for "reference data", supplied by the caller.
* If match offsets go further back than the number of bytes
* decompressed so far, that is them accessing the reference data.
@@ -79,11 +83,11 @@
#define BITS_TYPE struct lzxd_stream
#define BITS_VAR lzx
#define BITS_ORDER_MSB
-#define READ_BYTES do { \
- unsigned char b0, b1; \
- READ_IF_NEEDED; b0 = *i_ptr++; \
- READ_IF_NEEDED; b1 = *i_ptr++; \
- INJECT_BITS((b1 << 8) | b0, 16); \
+#define READ_BYTES do { \
+ unsigned char b0, b1; \
+ READ_IF_NEEDED; b0 = *i_ptr++; \
+ READ_IF_NEEDED; b1 = *i_ptr++; \
+ INJECT_BITS((b1 << 8) | b0, 16); \
} while (0)
#include "readbits.h"
@@ -96,43 +100,43 @@
#include "readhuff.h"
/* BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */
-#define BUILD_TABLE(tbl) \
- if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
- &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
- { \
- D(("failed to build %s table", #tbl)) \
- return lzx->error = MSPACK_ERR_DECRUNCH; \
+#define BUILD_TABLE(tbl) \
+ if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
+ &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
+ { \
+ D(("failed to build %s table", #tbl)) \
+ return lzx->error = MSPACK_ERR_DECRUNCH; \
}
-#define BUILD_TABLE_MAYBE_EMPTY(tbl) do { \
- lzx->tbl##_empty = 0; \
- if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
- &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
- { \
- for (i = 0; i < MAXSYMBOLS(tbl); i++) { \
- if (HUFF_LEN(tbl, i) > 0) { \
- D(("failed to build %s table", #tbl)) \
- return lzx->error = MSPACK_ERR_DECRUNCH; \
- } \
- } \
- /* empty tree - allow it, but don't decode symbols with it */ \
- lzx->tbl##_empty = 1; \
- } \
+#define BUILD_TABLE_MAYBE_EMPTY(tbl) do { \
+ lzx->tbl##_empty = 0; \
+ if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
+ &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
+ { \
+ for (i = 0; i < MAXSYMBOLS(tbl); i++) { \
+ if (HUFF_LEN(tbl, i) > 0) { \
+ D(("failed to build %s table", #tbl)) \
+ return lzx->error = MSPACK_ERR_DECRUNCH; \
+ } \
+ } \
+ /* empty tree - allow it, but don't decode symbols with it */ \
+ lzx->tbl##_empty = 1; \
+ } \
} while (0)
/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols
* first to last in the given table. The code lengths are stored in their
* own special LZX way.
*/
-#define READ_LENGTHS(tbl, first, last) do { \
- STORE_BITS; \
- if (lzxd_read_lens(lzx, &HUFF_LEN(tbl, 0), (first), \
- (unsigned int)(last))) return lzx->error; \
- RESTORE_BITS; \
+#define READ_LENGTHS(tbl, first, last) do { \
+ STORE_BITS; \
+ if (lzxd_read_lens(lzx, &HUFF_LEN(tbl, 0), (first), \
+ (unsigned int)(last))) return lzx->error; \
+ RESTORE_BITS; \
} while (0)
static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens,
- unsigned int first, unsigned int last)
+ unsigned int first, unsigned int last)
{
/* bit buffer and huffman symbol decode variables */
register unsigned int bit_buffer;
@@ -189,27 +193,70 @@ static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens,
* a small 'position slot' number and a small offset from that slot are
* encoded instead of one large offset.
*
+ * The number of slots is decided by how many are needed to encode the
+ * largest offset for a given window size. This is easy when the gap between
+ * slots is less than 128Kb, it's a linear relationship. But when extra_bits
+ * reaches its limit of 17 (because LZX can only ensure reading 17 bits of
+ * data at a time), we can only jump 128Kb at a time and have to start
+ * using more and more position slots as each window size doubles.
+ *
* position_base[] is an index to the position slot bases
*
* extra_bits[] states how many bits of offset-from-base data is needed.
*
- * They are generated like so:
- * for (i = 0; i < 4; i++) extra_bits[i] = 0;
- * for (i = 4, j = 0; i < 36; i+=2) extra_bits[i] = extra_bits[i+1] = j++;
- * for (i = 36; i < 51; i++) extra_bits[i] = 17;
- * for (i = 0, j = 0; i < 51; j += 1 << extra_bits[i++]) position_base[i] = j;
+ * They are calculated as follows:
+ * extra_bits[i] = 0 where i < 4
+ * extra_bits[i] = floor(i/2)-1 where i >= 4 && i < 36
+ * extra_bits[i] = 17 where i >= 36
+ * position_base[0] = 0
+ * position_base[i] = position_base[i-1] + (1 << extra_bits[i-1])
*/
-static const unsigned int position_base[51] = {
- 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256,
- 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288,
- 16384, 24576, 32768, 49152, 65536, 98304, 131072, 196608, 262144,
- 393216, 524288, 655360, 786432, 917504, 1048576, 1179648, 1310720,
- 1441792, 1572864, 1703936, 1835008, 1966080, 2097152
+static const unsigned int position_slots[11] = {
+ 30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
+};
+static const unsigned char extra_bits[36] = {
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16
};
-static const unsigned char extra_bits[51] = {
- 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
- 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
- 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
+static const unsigned int position_base[290] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512,
+ 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768,
+ 49152, 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360,
+ 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
+ 1835008, 1966080, 2097152, 2228224, 2359296, 2490368, 2621440, 2752512,
+ 2883584, 3014656, 3145728, 3276800, 3407872, 3538944, 3670016, 3801088,
+ 3932160, 4063232, 4194304, 4325376, 4456448, 4587520, 4718592, 4849664,
+ 4980736, 5111808, 5242880, 5373952, 5505024, 5636096, 5767168, 5898240,
+ 6029312, 6160384, 6291456, 6422528, 6553600, 6684672, 6815744, 6946816,
+ 7077888, 7208960, 7340032, 7471104, 7602176, 7733248, 7864320, 7995392,
+ 8126464, 8257536, 8388608, 8519680, 8650752, 8781824, 8912896, 9043968,
+ 9175040, 9306112, 9437184, 9568256, 9699328, 9830400, 9961472, 10092544,
+ 10223616, 10354688, 10485760, 10616832, 10747904, 10878976, 11010048,
+ 11141120, 11272192, 11403264, 11534336, 11665408, 11796480, 11927552,
+ 12058624, 12189696, 12320768, 12451840, 12582912, 12713984, 12845056,
+ 12976128, 13107200, 13238272, 13369344, 13500416, 13631488, 13762560,
+ 13893632, 14024704, 14155776, 14286848, 14417920, 14548992, 14680064,
+ 14811136, 14942208, 15073280, 15204352, 15335424, 15466496, 15597568,
+ 15728640, 15859712, 15990784, 16121856, 16252928, 16384000, 16515072,
+ 16646144, 16777216, 16908288, 17039360, 17170432, 17301504, 17432576,
+ 17563648, 17694720, 17825792, 17956864, 18087936, 18219008, 18350080,
+ 18481152, 18612224, 18743296, 18874368, 19005440, 19136512, 19267584,
+ 19398656, 19529728, 19660800, 19791872, 19922944, 20054016, 20185088,
+ 20316160, 20447232, 20578304, 20709376, 20840448, 20971520, 21102592,
+ 21233664, 21364736, 21495808, 21626880, 21757952, 21889024, 22020096,
+ 22151168, 22282240, 22413312, 22544384, 22675456, 22806528, 22937600,
+ 23068672, 23199744, 23330816, 23461888, 23592960, 23724032, 23855104,
+ 23986176, 24117248, 24248320, 24379392, 24510464, 24641536, 24772608,
+ 24903680, 25034752, 25165824, 25296896, 25427968, 25559040, 25690112,
+ 25821184, 25952256, 26083328, 26214400, 26345472, 26476544, 26607616,
+ 26738688, 26869760, 27000832, 27131904, 27262976, 27394048, 27525120,
+ 27656192, 27787264, 27918336, 28049408, 28180480, 28311552, 28442624,
+ 28573696, 28704768, 28835840, 28966912, 29097984, 29229056, 29360128,
+ 29491200, 29622272, 29753344, 29884416, 30015488, 30146560, 30277632,
+ 30408704, 30539776, 30670848, 30801920, 30932992, 31064064, 31195136,
+ 31326208, 31457280, 31588352, 31719424, 31850496, 31981568, 32112640,
+ 32243712, 32374784, 32505856, 32636928, 32768000, 32899072, 33030144,
+ 33161216, 33292288, 33423360
};
static void lzxd_reset_state(struct lzxd_stream *lzx) {
@@ -230,23 +277,37 @@ static void lzxd_reset_state(struct lzxd_stream *lzx) {
/*-------- main LZX code --------*/
struct lzxd_stream *lzxd_init(struct mspack_system *system,
- struct mspack_file *input,
- struct mspack_file *output,
- int window_bits,
- int reset_interval,
- int input_buffer_size,
- off_t output_length)
+ struct mspack_file *input,
+ struct mspack_file *output,
+ int window_bits,
+ int reset_interval,
+ int input_buffer_size,
+ off_t output_length,
+ char is_delta)
{
unsigned int window_size = 1 << window_bits;
struct lzxd_stream *lzx;
if (!system) return NULL;
- /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */
- if (window_bits < 15 || window_bits > 21) return NULL;
+ /* LZX DELTA window sizes are between 2^17 (128KiB) and 2^25 (32MiB),
+ * regular LZX windows are between 2^15 (32KiB) and 2^21 (2MiB)
+ */
+ if (is_delta) {
+ if (window_bits < 17 || window_bits > 25) return NULL;
+ }
+ else {
+ if (window_bits < 15 || window_bits > 21) return NULL;
+ }
+ if (reset_interval < 0 || output_length < 0) {
+ D(("reset interval or output length < 0"))
+ return NULL;
+ }
+
+ /* round up input buffer size to multiple of two */
input_buffer_size = (input_buffer_size + 1) & -2;
- if (!input_buffer_size) return NULL;
+ if (input_buffer_size < 2) return NULL;
/* allocate decompression state */
if (!(lzx = (struct lzxd_stream *) system->alloc(system, sizeof(struct lzxd_stream)))) {
@@ -272,6 +333,7 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system,
lzx->inbuf_size = input_buffer_size;
lzx->window_size = 1 << window_bits;
+ lzx->ref_data_size = 0;
lzx->window_posn = 0;
lzx->frame_posn = 0;
lzx->frame = 0;
@@ -280,11 +342,8 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system,
lzx->intel_curpos = 0;
lzx->intel_started = 0;
lzx->error = MSPACK_ERR_OK;
-
- /* window bits: 15 16 17 18 19 20 21
- * position slots: 30 32 34 36 38 42 50 */
- lzx->posn_slots = ((window_bits == 21) ? 50 :
- ((window_bits == 20) ? 42 : (window_bits << 1)));
+ lzx->num_offsets = position_slots[window_bits - 15] << 3;
+ lzx->is_delta = is_delta;
lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0];
lzxd_reset_state(lzx);
@@ -292,8 +351,44 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system,
return lzx;
}
+int lzxd_set_reference_data(struct lzxd_stream *lzx,
+ struct mspack_system *system,
+ struct mspack_file *input,
+ unsigned int length)
+{
+ if (!lzx) return MSPACK_ERR_ARGS;
+
+ if (!lzx->is_delta) {
+ D(("only LZX DELTA streams support reference data"))
+ return MSPACK_ERR_ARGS;
+ }
+ if (lzx->offset) {
+ D(("too late to set reference data after decoding starts"))
+ return MSPACK_ERR_ARGS;
+ }
+ if (length > lzx->window_size) {
+ D(("reference length (%u) is longer than the window", length))
+ return MSPACK_ERR_ARGS;
+ }
+ if (length > 0 && (!system || !input)) {
+ D(("length > 0 but no system or input"))
+ return MSPACK_ERR_ARGS;
+ }
+
+ lzx->ref_data_size = length;
+ if (length > 0) {
+ /* copy reference data */
+ unsigned char *pos = &lzx->window[lzx->window_size - length];
+ int bytes = system->read(input, pos, length);
+ /* length can't be more than 2^25, so no signedness problem */
+ if (bytes < (int)length) return MSPACK_ERR_READ;
+ }
+ lzx->ref_data_size = length;
+ return MSPACK_ERR_OK;
+}
+
void lzxd_set_output_length(struct lzxd_stream *lzx, off_t out_bytes) {
- if (lzx) lzx->length = out_bytes;
+ if (lzx && out_bytes > 0) lzx->length = out_bytes;
}
int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
@@ -304,7 +399,7 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
register unsigned short sym;
int match_length, length_footer, extra, verbatim_bits, bytes_todo;
- int this_run, main_element, aligned_bits, j;
+ 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;
@@ -340,8 +435,12 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* have we reached the reset interval? (if there is one?) */
if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) {
if (lzx->block_remaining) {
- D(("%d bytes remaining at reset interval", lzx->block_remaining))
- return lzx->error = MSPACK_ERR_DECRUNCH;
+ /* this is a file format error, we can make a best effort to extract what we can */
+ D(("%d bytes remaining at reset interval", lzx->block_remaining))
+ if (!warned) {
+ lzx->sys->message(NULL, "WARNING; invalid reset interval detected during LZX decompression");
+ warned++;
+ }
}
/* re-read the intel header and reset the huffman lengths */
@@ -351,6 +450,12 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
R2 = lzx->R2;
}
+ /* LZX DELTA format has chunk_size, not present in LZX format */
+ if (lzx->is_delta) {
+ ENSURE_BITS(16);
+ REMOVE_BITS(16);
+ }
+
/* read header if necessary */
if (!lzx->header_read) {
/* read 1 bit. if bit=0, intel filesize = 0.
@@ -373,62 +478,61 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
while (bytes_todo > 0) {
/* initialise new block, if one is needed */
if (lzx->block_remaining == 0) {
- /* realign if previous block was an odd-sized UNCOMPRESSED block */
- if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) &&
- (lzx->block_length & 1))
- {
- READ_IF_NEEDED;
- i_ptr++;
- }
-
- /* read block type (3 bits) and block length (24 bits) */
- READ_BITS(lzx->block_type, 3);
- READ_BITS(i, 16); READ_BITS(j, 8);
- lzx->block_remaining = lzx->block_length = (i << 8) | j;
- /*D(("new block t%d len %u", lzx->block_type, lzx->block_length))*/
-
- /* read individual block headers */
- switch (lzx->block_type) {
- case LZX_BLOCKTYPE_ALIGNED:
- /* read lengths of and build aligned huffman decoding tree */
- for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; }
- BUILD_TABLE(ALIGNED);
- /* no break -- rest of aligned header is same as verbatim */
- case LZX_BLOCKTYPE_VERBATIM:
- /* read lengths of and build main huffman decoding tree */
- READ_LENGTHS(MAINTREE, 0, 256);
- READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + (lzx->posn_slots << 3));
- BUILD_TABLE(MAINTREE);
- /* if the literal 0xE8 is anywhere in the block... */
- if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1;
- /* read lengths of and build lengths huffman decoding tree */
- READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
- BUILD_TABLE_MAYBE_EMPTY(LENGTH);
- break;
-
- case LZX_BLOCKTYPE_UNCOMPRESSED:
- /* because we can't assume otherwise */
- lzx->intel_started = 1;
-
- /* read 1-16 (not 0-15) bits to align to bytes */
- ENSURE_BITS(16);
- if (bits_left > 16) i_ptr -= 2;
- bits_left = 0; bit_buffer = 0;
-
- /* read 12 bytes of stored R0 / R1 / R2 values */
- for (rundest = &buf[0], i = 0; i < 12; i++) {
- 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);
- break;
-
- default:
- D(("bad block type"))
- return lzx->error = MSPACK_ERR_DECRUNCH;
- }
+ /* realign if previous block was an odd-sized UNCOMPRESSED block */
+ if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) &&
+ (lzx->block_length & 1))
+ {
+ READ_IF_NEEDED;
+ i_ptr++;
+ }
+
+ /* read block type (3 bits) and block length (24 bits) */
+ READ_BITS(lzx->block_type, 3);
+ READ_BITS(i, 16); READ_BITS(j, 8);
+ lzx->block_remaining = lzx->block_length = (i << 8) | j;
+ /*D(("new block t%d len %u", lzx->block_type, lzx->block_length))*/
+
+ /* read individual block headers */
+ switch (lzx->block_type) {
+ case LZX_BLOCKTYPE_ALIGNED:
+ /* read lengths of and build aligned huffman decoding tree */
+ for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; }
+ BUILD_TABLE(ALIGNED);
+ /* rest of aligned header is same as verbatim */ /*@fallthrough@*/
+ case LZX_BLOCKTYPE_VERBATIM:
+ /* read lengths of and build main huffman decoding tree */
+ READ_LENGTHS(MAINTREE, 0, 256);
+ READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx->num_offsets);
+ BUILD_TABLE(MAINTREE);
+ /* if the literal 0xE8 is anywhere in the block... */
+ if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1;
+ /* read lengths of and build lengths huffman decoding tree */
+ READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
+ BUILD_TABLE_MAYBE_EMPTY(LENGTH);
+ break;
+
+ case LZX_BLOCKTYPE_UNCOMPRESSED:
+ /* because we can't assume otherwise */
+ lzx->intel_started = 1;
+
+ /* read 1-16 (not 0-15) bits to align to bytes */
+ if (bits_left == 0) ENSURE_BITS(16);
+ bits_left = 0; bit_buffer = 0;
+
+ /* read 12 bytes of stored R0 / R1 / R2 values */
+ for (rundest = &buf[0], i = 0; i < 12; i++) {
+ 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);
+ break;
+
+ default:
+ D(("bad block type"))
+ return lzx->error = MSPACK_ERR_DECRUNCH;
+ }
}
/* decode more of the block:
@@ -443,208 +547,270 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* decode at least this_run bytes */
switch (lzx->block_type) {
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) {
+ 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 = 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;
- }
-
- 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) {
- /* 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;
+ 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) {
- 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) {
+ 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;
- default:
- extra = extra_bits[match_offset];
- match_offset = position_base[match_offset] - 2;
- if (extra > 3) {
- /* verbatim and aligned bits */
- extra -= 3;
- READ_BITS(verbatim_bits, extra);
- 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);
- 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;
- }
-
- 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) {
- /* 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;
+ 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;
+ default:
+ extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
+ match_offset = position_base[match_offset] - 2;
+ if (extra > 3) {
+ /* verbatim and aligned bits */
+ extra -= 3;
+ READ_BITS(verbatim_bits, extra);
+ 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);
+ 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;
+ }
+
+ /* 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_UNCOMPRESSED:
- /* as this_run is limited not to wrap a frame, this also means it
- * won't wrap the window (as the window is a multiple of 32k) */
- rundest = &window[window_posn];
- window_posn += this_run;
- while (this_run > 0) {
- if ((i = i_end - i_ptr) == 0) {
- READ_IF_NEEDED;
- }
- else {
- if (i > this_run) i = this_run;
- lzx->sys->copy(i_ptr, rundest, (size_t) i);
- rundest += i;
- i_ptr += i;
- this_run -= i;
- }
- }
- break;
+ /* as this_run is limited not to wrap a frame, this also means it
+ * won't wrap the window (as the window is a multiple of 32k) */
+ rundest = &window[window_posn];
+ window_posn += this_run;
+ while (this_run > 0) {
+ if ((i = i_end - i_ptr) == 0) {
+ READ_IF_NEEDED;
+ }
+ else {
+ if (i > this_run) i = this_run;
+ lzx->sys->copy(i_ptr, rundest, (size_t) i);
+ rundest += i;
+ i_ptr += i;
+ this_run -= i;
+ }
+ }
+ break;
default:
- return lzx->error = MSPACK_ERR_DECRUNCH; /* might as well */
+ return lzx->error = MSPACK_ERR_DECRUNCH; /* might as well */
}
/* did the final match overrun our desired this_run length? */
if (this_run < 0) {
- if ((unsigned int)(-this_run) > lzx->block_remaining) {
- D(("overrun went past end of block by %d (%d remaining)",
- -this_run, lzx->block_remaining ))
- return lzx->error = MSPACK_ERR_DECRUNCH;
- }
- lzx->block_remaining -= -this_run;
+ if ((unsigned int)(-this_run) > lzx->block_remaining) {
+ D(("overrun went past end of block by %d (%d remaining)",
+ -this_run, lzx->block_remaining ))
+ return lzx->error = MSPACK_ERR_DECRUNCH;
+ }
+ lzx->block_remaining -= -this_run;
}
} /* while (bytes_todo > 0) */
/* streams don't extend over frame boundaries */
if ((window_posn - lzx->frame_posn) != frame_size) {
D(("decode beyond output frame limits! %d != %d",
- window_posn - lzx->frame_posn, frame_size))
+ window_posn - lzx->frame_posn, frame_size))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
@@ -654,13 +820,14 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
/* check that we've used all of the previous frame first */
if (lzx->o_ptr != lzx->o_end) {
- D(("%ld avail bytes, new %d frame", lzx->o_end-lzx->o_ptr, frame_size))
+ D(("%ld avail bytes, new %d frame",
+ (long)(lzx->o_end - lzx->o_ptr), frame_size))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
/* 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];
@@ -673,17 +840,17 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
lzx->sys->copy(&lzx->window[lzx->frame_posn], data, frame_size);
while (data < dataend) {
- if (*data++ != 0xE8) { curpos++; continue; }
- abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
- if ((abs_off >= -curpos) && (abs_off < filesize)) {
- rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
- data[0] = (unsigned char) rel_off;
- data[1] = (unsigned char) (rel_off >> 8);
- data[2] = (unsigned char) (rel_off >> 16);
- data[3] = (unsigned char) (rel_off >> 24);
- }
- data += 4;
- curpos += 5;
+ if (*data++ != 0xE8) { curpos++; continue; }
+ abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
+ if ((abs_off >= -curpos) && (abs_off < filesize)) {
+ rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
+ data[0] = (unsigned char) rel_off;
+ data[1] = (unsigned char) (rel_off >> 8);
+ data[2] = (unsigned char) (rel_off >> 16);
+ data[3] = (unsigned char) (rel_off >> 24);
+ }
+ data += 4;
+ curpos += 5;
}
lzx->intel_curpos += frame_size;
}
diff --git a/rbutil/rbutilqt/mspack/mspack.h b/rbutil/rbutilqt/mspack/mspack.h
index 7f6bdf1465..3e99624463 100644
--- a/rbutil/rbutilqt/mspack/mspack.h
+++ b/rbutil/rbutilqt/mspack/mspack.h
@@ -1,5 +1,5 @@
/* libmspack -- a library for working with Microsoft compression formats.
- * (C) 2003-2011 Stuart Caie <kyzer@4u.net>
+ * (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
*
* 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
@@ -30,6 +30,7 @@
* - .CAB (MS Cabinet) files, which use deflate, LZX or Quantum compression
* - .CHM (HTML Help) files, which use LZX compression
* - .LIT (MS EBook) files, which use LZX compression and DES encryption
+ * - .LZX (Exchange Offline Addressbook) files, which use LZX compression
*
* To determine the capabilities of the library, and the binary
* compatibility version of any particular compressor or decompressor, use
@@ -60,6 +61,7 @@
* - mspack_create_hlp_compressor() creates a mshlp_compressor
* - mspack_create_szdd_compressor() creates a msszdd_compressor
* - mspack_create_kwaj_compressor() creates a mskwaj_compressor
+ * - mspack_create_oab_compressor() creates a msoab_compressor
*
* For decompression:
* - mspack_create_cab_decompressor() creates a mscab_decompressor
@@ -68,6 +70,7 @@
* - mspack_create_hlp_decompressor() creates a mshlp_decompressor
* - mspack_create_szdd_decompressor() creates a msszdd_decompressor
* - mspack_create_kwaj_decompressor() creates a mskwaj_decompressor
+ * - mspack_create_oab_decompressor() creates a msoab_decompressor
*
* Once finished working with a format, each kind of
* compressor/decompressor has its own specific destructor:
@@ -83,6 +86,8 @@
* - mspack_destroy_szdd_decompressor()
* - mspack_destroy_kwaj_compressor()
* - mspack_destroy_kwaj_decompressor()
+ * - mspack_destroy_oab_compressor()
+ * - mspack_destroy_oab_decompressor()
*
* Destroying a compressor or decompressor does not destroy any objects,
* structures or handles that have been created using that compressor or
@@ -208,6 +213,8 @@ extern int mspack_sys_selftest_internal(int);
* - #MSPACK_VER_MSSZDDC: the msszdd_compressor interface
* - #MSPACK_VER_MSKWAJD: the mskwaj_decompressor interface
* - #MSPACK_VER_MSKWAJC: the mskwaj_compressor interface
+ * - #MSPACK_VER_MSOABD: the msoab_decompressor interface
+ * - #MSPACK_VER_MSOABC: the msoab_compressor interface
*
* The result of the function should be interpreted as follows:
* - -1: this interface is completely unknown to the library
@@ -249,6 +256,10 @@ extern int mspack_version(int entity);
#define MSPACK_VER_MSKWAJD (12)
/** Pass to mspack_version() to get the mskwaj_compressor version */
#define MSPACK_VER_MSKWAJC (13)
+/** Pass to mspack_version() to get the msoab_decompressor version */
+#define MSPACK_VER_MSOABD (14)
+/** Pass to mspack_version() to get the msoab_compressor version */
+#define MSPACK_VER_MSOABC (15)
/* --- file I/O abstraction ------------------------------------------------ */
@@ -297,8 +308,8 @@ struct mspack_system {
* @see close(), read(), write(), seek(), tell(), message()
*/
struct mspack_file * (*open)(struct mspack_system *self,
- const char *filename,
- int mode);
+ const char *filename,
+ int mode);
/**
* Closes a previously opened file. If any memory was allocated for this
@@ -317,12 +328,14 @@ struct mspack_system {
* @param bytes the number of bytes to read from the file.
* @return the number of bytes successfully read (this can be less than
* the number requested), zero to mark the end of file, or less
- * than zero to indicate an error.
+ * than zero to indicate an error. The library does not "retry"
+ * reads and assumes short reads are due to EOF, so you should
+ * avoid returning short reads because of transient errors.
* @see open(), write()
*/
int (*read)(struct mspack_file *file,
- void *buffer,
- int bytes);
+ void *buffer,
+ int bytes);
/**
* Writes a given number of bytes to an open file.
@@ -338,8 +351,8 @@ struct mspack_system {
* @see open(), read()
*/
int (*write)(struct mspack_file *file,
- void *buffer,
- int bytes);
+ void *buffer,
+ int bytes);
/**
* Seeks to a specific file offset within an open file.
@@ -365,8 +378,8 @@ struct mspack_system {
* @see open(), tell()
*/
int (*seek)(struct mspack_file *file,
- off_t offset,
- int mode);
+ off_t offset,
+ int mode);
/**
* Returns the current file position (in bytes) of the given file.
@@ -392,8 +405,8 @@ struct mspack_system {
* @see open()
*/
void (*message)(struct mspack_file *file,
- const char *format,
- ...);
+ const char *format,
+ ...);
/**
* Allocates memory.
@@ -406,12 +419,12 @@ struct mspack_system {
* @see free()
*/
void * (*alloc)(struct mspack_system *self,
- size_t bytes);
+ size_t bytes);
/**
* Frees memory.
*
- * @param ptr the memory to be freed.
+ * @param ptr the memory to be freed. NULL is accepted and ignored.
* @see alloc()
*/
void (*free)(void *ptr);
@@ -429,8 +442,8 @@ struct mspack_system {
* @param bytes the size of the memory region, in bytes
*/
void (*copy)(void *src,
- void *dest,
- size_t bytes);
+ void *dest,
+ size_t bytes);
/**
* A null pointer to mark the end of mspack_system. It must equal NULL.
@@ -645,6 +658,31 @@ extern void mspack_destroy_kwaj_compressor(struct mskwaj_compressor *self);
extern void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *self);
+/** Creates a new OAB compressor.
+ * @param sys a custom mspack_system structure, or NULL to use the default
+ * @return a #msoab_compressor or NULL
+ */
+extern struct msoab_compressor *
+ mspack_create_oab_compressor(struct mspack_system *sys);
+
+/** Creates a new OAB decompressor.
+ * @param sys a custom mspack_system structure, or NULL to use the default
+ * @return a #msoab_decompressor or NULL
+ */
+extern struct msoab_decompressor *
+ mspack_create_oab_decompressor(struct mspack_system *sys);
+
+/** Destroys an existing OAB compressor.
+ * @param self the #msoab_compressor to destroy
+ */
+extern void mspack_destroy_oab_compressor(struct msoab_compressor *self);
+
+/** Destroys an existing OAB decompressor.
+ * @param self the #msoab_decompressor to destroy
+ */
+extern void mspack_destroy_oab_decompressor(struct msoab_decompressor *self);
+
+
/* --- support for .CAB (MS Cabinet) file format --------------------------- */
/**
@@ -896,6 +934,13 @@ struct mscabd_file {
#define MSCABD_PARAM_FIXMSZIP (1)
/** mscab_decompressor::set_param() parameter: size of decompression buffer */
#define MSCABD_PARAM_DECOMPBUF (2)
+/** mscab_decompressor::set_param() parameter: salvage data from bad cabinets?
+ * If enabled, open() will skip file with bad folder indices or filenames
+ * rather than reject the whole cabinet, and extract() will limit rather than
+ * reject files with invalid offsets and lengths, and bad data block checksums
+ * will be ignored. Available only in CAB decoder version 2 and above.
+ */
+#define MSCABD_PARAM_SALVAGE (3)
/** TODO */
struct mscab_compressor {
@@ -931,7 +976,7 @@ struct mscab_decompressor {
* @see close(), search(), last_error()
*/
struct mscabd_cabinet * (*open) (struct mscab_decompressor *self,
- const char *filename);
+ const char *filename);
/**
* Closes a previously opened cabinet or cabinet set.
@@ -963,7 +1008,7 @@ struct mscab_decompressor {
* @see open(), search(), append(), prepend()
*/
void (*close)(struct mscab_decompressor *self,
- struct mscabd_cabinet *cab);
+ struct mscabd_cabinet *cab);
/**
* Searches a regular file for embedded cabinets.
@@ -1000,7 +1045,7 @@ struct mscab_decompressor {
* @see close(), open(), last_error()
*/
struct mscabd_cabinet * (*search) (struct mscab_decompressor *self,
- const char *filename);
+ const char *filename);
/**
* Appends one mscabd_cabinet to another, forming or extending a cabinet
@@ -1043,8 +1088,8 @@ struct mscab_decompressor {
* @see prepend(), open(), close()
*/
int (*append) (struct mscab_decompressor *self,
- struct mscabd_cabinet *cab,
- struct mscabd_cabinet *nextcab);
+ struct mscabd_cabinet *cab,
+ struct mscabd_cabinet *nextcab);
/**
* Prepends one mscabd_cabinet to another, forming or extending a
@@ -1065,8 +1110,8 @@ struct mscab_decompressor {
* @see append(), open(), close()
*/
int (*prepend) (struct mscab_decompressor *self,
- struct mscabd_cabinet *cab,
- struct mscabd_cabinet *prevcab);
+ struct mscabd_cabinet *cab,
+ struct mscabd_cabinet *prevcab);
/**
* Extracts a file from a cabinet or cabinet set.
@@ -1091,8 +1136,8 @@ struct mscab_decompressor {
* @return an error code, or MSPACK_ERR_OK if successful
*/
int (*extract)(struct mscab_decompressor *self,
- struct mscabd_file *file,
- const char *filename);
+ struct mscabd_file *file,
+ const char *filename);
/**
* Sets a CAB decompression engine parameter.
@@ -1117,8 +1162,8 @@ struct mscab_decompressor {
* @see search(), extract()
*/
int (*set_param)(struct mscab_decompressor *self,
- int param,
- int value);
+ int param,
+ int value);
/**
* Returns the error code set by the most recently called method.
@@ -1403,8 +1448,8 @@ struct mschm_compressor {
* @see use_temporary_file() set_param()
*/
int (*generate)(struct mschm_compressor *self,
- struct mschmc_file file_list[],
- const char *output_file);
+ struct mschmc_file file_list[],
+ const char *output_file);
/**
* Specifies whether a temporary file is used during CHM generation.
@@ -1460,8 +1505,8 @@ struct mschm_compressor {
* @see generate()
*/
int (*use_temporary_file)(struct mschm_compressor *self,
- int use_temp_file,
- const char *temp_file);
+ int use_temp_file,
+ const char *temp_file);
/**
* Sets a CHM compression engine parameter.
*
@@ -1508,8 +1553,8 @@ struct mschm_compressor {
* @see generate()
*/
int (*set_param)(struct mschm_compressor *self,
- int param,
- unsigned int value);
+ int param,
+ int value);
/**
* Returns the error code set by the most recently called method.
@@ -1551,7 +1596,7 @@ struct mschm_decompressor {
* @see close()
*/
struct mschmd_header *(*open)(struct mschm_decompressor *self,
- const char *filename);
+ const char *filename);
/**
* Closes a previously opened CHM helpfile.
@@ -1571,7 +1616,7 @@ struct mschm_decompressor {
* @see open(), fast_open()
*/
void (*close)(struct mschm_decompressor *self,
- struct mschmd_header *chm);
+ struct mschmd_header *chm);
/**
* Extracts a file from a CHM helpfile.
@@ -1592,8 +1637,8 @@ struct mschm_decompressor {
* @return an error code, or MSPACK_ERR_OK if successful
*/
int (*extract)(struct mschm_decompressor *self,
- struct mschmd_file *file,
- const char *filename);
+ struct mschmd_file *file,
+ const char *filename);
/**
* Returns the error code set by the most recently called method.
@@ -1631,7 +1676,7 @@ struct mschm_decompressor {
* @see open(), close(), fast_find(), extract()
*/
struct mschmd_header *(*fast_open)(struct mschm_decompressor *self,
- const char *filename);
+ const char *filename);
/**
* Finds file details quickly.
@@ -1672,10 +1717,10 @@ struct mschm_decompressor {
* @see open(), close(), fast_find(), extract()
*/
int (*fast_find)(struct mschm_decompressor *self,
- struct mschmd_header *chm,
- const char *filename,
- struct mschmd_file *f_ptr,
- int f_size);
+ struct mschmd_header *chm,
+ const char *filename,
+ struct mschmd_file *f_ptr,
+ int f_size);
};
/* --- support for .LIT (EBook) file format -------------------------------- */
@@ -1781,9 +1826,9 @@ struct msszdd_compressor {
* @see set_param()
*/
int (*compress)(struct msszdd_compressor *self,
- const char *input,
- const char *output,
- off_t length);
+ const char *input,
+ const char *output,
+ off_t length);
/**
* Sets an SZDD compression engine parameter.
@@ -1807,8 +1852,8 @@ struct msszdd_compressor {
* @see compress()
*/
int (*set_param)(struct msszdd_compressor *self,
- int param,
- unsigned int value);
+ int param,
+ int value);
/**
* Returns the error code set by the most recently called method.
@@ -1849,7 +1894,7 @@ struct msszdd_decompressor {
* @see close()
*/
struct msszddd_header *(*open)(struct msszdd_decompressor *self,
- const char *filename);
+ const char *filename);
/**
* Closes a previously opened SZDD file.
@@ -1865,7 +1910,7 @@ struct msszdd_decompressor {
* @see open()
*/
void (*close)(struct msszdd_decompressor *self,
- struct msszddd_header *szdd);
+ struct msszddd_header *szdd);
/**
* Extracts the compressed data from a SZDD file.
@@ -1881,8 +1926,8 @@ struct msszdd_decompressor {
* @return an error code, or MSPACK_ERR_OK if successful
*/
int (*extract)(struct msszdd_decompressor *self,
- struct msszddd_header *szdd,
- const char *filename);
+ struct msszddd_header *szdd,
+ const char *filename);
/**
* Decompresses an SZDD file to an output file in one step.
@@ -1902,8 +1947,8 @@ struct msszdd_decompressor {
* @return an error code, or MSPACK_ERR_OK if successful
*/
int (*decompress)(struct msszdd_decompressor *self,
- const char *input,
- const char *output);
+ const char *input,
+ const char *output);
/**
* Returns the error code set by the most recently called method.
@@ -1937,6 +1982,8 @@ struct msszdd_decompressor {
#define MSKWAJ_COMP_SZDD (2)
/** KWAJ compression type: LZ+Huffman compression */
#define MSKWAJ_COMP_LZH (3)
+/** KWAJ compression type: MSZIP */
+#define MSKWAJ_COMP_MSZIP (4)
/** KWAJ optional header flag: decompressed file length is included */
#define MSKWAJ_HDR_HASLENGTH (0x01)
@@ -2015,9 +2062,9 @@ struct mskwaj_compressor {
* @see set_param()
*/
int (*compress)(struct mskwaj_compressor *self,
- const char *input,
- const char *output,
- off_t length);
+ const char *input,
+ const char *output,
+ off_t length);
/**
* Sets an KWAJ compression engine parameter.
@@ -2043,8 +2090,8 @@ struct mskwaj_compressor {
* @see generate()
*/
int (*set_param)(struct mskwaj_compressor *self,
- int param,
- unsigned int value);
+ int param,
+ int value);
/**
@@ -2065,7 +2112,7 @@ struct mskwaj_compressor {
* filename is too long
*/
int (*set_filename)(struct mskwaj_compressor *self,
- const char *filename);
+ const char *filename);
/**
* Sets arbitrary data that will be stored in the header of the
@@ -2085,8 +2132,8 @@ struct mskwaj_compressor {
* is too long
*/
int (*set_extra_data)(struct mskwaj_compressor *self,
- void *data,
- size_t bytes);
+ void *data,
+ size_t bytes);
/**
* Returns the error code set by the most recently called method.
@@ -2127,7 +2174,7 @@ struct mskwaj_decompressor {
* @see close()
*/
struct mskwajd_header *(*open)(struct mskwaj_decompressor *self,
- const char *filename);
+ const char *filename);
/**
* Closes a previously opened KWAJ file.
@@ -2142,7 +2189,7 @@ struct mskwaj_decompressor {
* @see open()
*/
void (*close)(struct mskwaj_decompressor *self,
- struct mskwajd_header *kwaj);
+ struct mskwajd_header *kwaj);
/**
* Extracts the compressed data from a KWAJ file.
@@ -2158,8 +2205,8 @@ struct mskwaj_decompressor {
* @return an error code, or MSPACK_ERR_OK if successful
*/
int (*extract)(struct mskwaj_decompressor *self,
- struct mskwajd_header *kwaj,
- const char *filename);
+ struct mskwajd_header *kwaj,
+ const char *filename);
/**
* Decompresses an KWAJ file to an output file in one step.
@@ -2179,8 +2226,8 @@ struct mskwaj_decompressor {
* @return an error code, or MSPACK_ERR_OK if successful
*/
int (*decompress)(struct mskwaj_decompressor *self,
- const char *input,
- const char *output);
+ const char *input,
+ const char *output);
/**
* Returns the error code set by the most recently called method.
@@ -2196,6 +2243,141 @@ struct mskwaj_decompressor {
int (*last_error)(struct mskwaj_decompressor *self);
};
+/* --- support for .LZX (Offline Address Book) file format ----------------- */
+
+/**
+ * A compressor for the Offline Address Book (OAB) format.
+ *
+ * All fields are READ ONLY.
+ *
+ * @see mspack_create_oab_compressor(), mspack_destroy_oab_compressor()
+ */
+struct msoab_compressor {
+ /**
+ * Compress a full OAB file.
+ *
+ * The input file will be read and the compressed contents written to the
+ * output file.
+ *
+ * @param self a self-referential pointer to the msoab_decompressor
+ * instance being called
+ * @param input the filename of the input file. This is passed
+ * directly to mspack_system::open().
+ * @param output the filename of the output file. This is passed
+ * directly to mspack_system::open().
+ * @return an error code, or MSPACK_ERR_OK if successful
+ */
+ int (*compress) (struct msoab_compressor *self,
+ const char *input,
+ const char *output);
+
+ /**
+ * Generate a compressed incremental OAB patch file.
+ *
+ * The two uncompressed files "input" and "base" will be read, and an
+ * incremental patch to generate "input" from "base" will be written to
+ * the output file.
+ *
+ * @param self a self-referential pointer to the msoab_compressor
+ * instance being called
+ * @param input the filename of the input file containing the new
+ * version of its contents. This is passed directly
+ * to mspack_system::open().
+ * @param base the filename of the original base file containing
+ * the old version of its contents, against which the
+ * incremental patch shall generated. This is passed
+ * directly to mspack_system::open().
+ * @param output the filename of the output file. This is passed
+ * directly to mspack_system::open().
+ * @return an error code, or MSPACK_ERR_OK if successful
+ */
+ int (*compress_incremental) (struct msoab_compressor *self,
+ const char *input,
+ const char *base,
+ const char *output);
+};
+
+/**
+ * A decompressor for .LZX (Offline Address Book) files
+ *
+ * All fields are READ ONLY.
+ *
+ * @see mspack_create_oab_decompressor(), mspack_destroy_oab_decompressor()
+ */
+struct msoab_decompressor {
+ /**
+ * Decompresses a full Offline Address Book file.
+ *
+ * If the input file is a valid compressed Offline Address Book file,
+ * it will be read and the decompressed contents will be written to
+ * the output file.
+ *
+ * @param self a self-referential pointer to the msoab_decompressor
+ * instance being called
+ * @param input the filename of the input file. This is passed
+ * directly to mspack_system::open().
+ * @param output the filename of the output file. This is passed
+ * directly to mspack_system::open().
+ * @return an error code, or MSPACK_ERR_OK if successful
+ */
+ int (*decompress) (struct msoab_decompressor *self,
+ const char *input,
+ const char *output);
+
+ /**
+ * Decompresses an Offline Address Book with an incremental patch file.
+ *
+ * This requires both a full UNCOMPRESSED Offline Address Book file to
+ * act as the "base", and a compressed incremental patch file as input.
+ * If the input file is valid, it will be decompressed with reference to
+ * the base file, and the decompressed contents will be written to the
+ * output file.
+ *
+ * There is no way to tell what the right base file is for the given
+ * incremental patch, but if you get it wrong, this will usually result
+ * in incorrect data being decompressed, which will then fail a checksum
+ * test.
+ *
+ * @param self a self-referential pointer to the msoab_decompressor
+ * instance being called
+ * @param input the filename of the input file. This is passed
+ * directly to mspack_system::open().
+ * @param base the filename of the base file to which the
+ * incremental patch shall be applied. This is passed
+ * directly to mspack_system::open().
+ * @param output the filename of the output file. This is passed
+ * directly to mspack_system::open().
+ * @return an error code, or MSPACK_ERR_OK if successful
+ */
+ int (*decompress_incremental) (struct msoab_decompressor *self,
+ const char *input,
+ const char *base,
+ const char *output);
+
+ /**
+ * Sets an OAB decompression engine parameter. Available only in OAB
+ * decompressor version 2 and above.
+ *
+ * - #MSOABD_PARAM_DECOMPBUF: How many bytes should be used as an input
+ * buffer by decompressors? The minimum value is 16. The default value
+ * is 4096.
+ *
+ * @param self a self-referential pointer to the msoab_decompressor
+ * instance being called
+ * @param param the parameter to set
+ * @param value the value to set the parameter to
+ * @return MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
+ * is a problem with either parameter or value.
+ */
+ int (*set_param)(struct msoab_decompressor *self,
+ int param,
+ int value);
+
+};
+
+/** msoab_decompressor::set_param() parameter: size of decompression buffer */
+#define MSOABD_PARAM_DECOMPBUF (0)
+
#ifdef __cplusplus
}
#endif
diff --git a/rbutil/rbutilqt/mspack/mszip.h b/rbutil/rbutilqt/mspack/mszip.h
index 13c9542ee6..2cd608234e 100644
--- a/rbutil/rbutilqt/mspack/mszip.h
+++ b/rbutil/rbutilqt/mspack/mszip.h
@@ -32,14 +32,14 @@ extern "C" {
# define MSZIP_LITERAL_TABLESIZE (MSZIP_LITERAL_MAXSYMBOLS * 4)
#else
# define MSZIP_LITERAL_TABLESIZE ((1 << MSZIP_LITERAL_TABLEBITS) + \
- (MSZIP_LITERAL_MAXSYMBOLS * 2))
+ (MSZIP_LITERAL_MAXSYMBOLS * 2))
#endif
#if (1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2)
# define MSZIP_DISTANCE_TABLESIZE (MSZIP_DISTANCE_MAXSYMBOLS * 4)
#else
# define MSZIP_DISTANCE_TABLESIZE ((1 << MSZIP_DISTANCE_TABLEBITS) + \
- (MSZIP_DISTANCE_MAXSYMBOLS * 2))
+ (MSZIP_DISTANCE_MAXSYMBOLS * 2))
#endif
struct mszipd_stream {
@@ -83,10 +83,10 @@ struct mszipd_stream {
* a partial recovery of erroneous data.
*/
extern struct mszipd_stream *mszipd_init(struct mspack_system *system,
- struct mspack_file *input,
- struct mspack_file *output,
- int input_buffer_size,
- int repair_mode);
+ struct mspack_file *input,
+ struct mspack_file *output,
+ int input_buffer_size,
+ int repair_mode);
/* decompresses, or decompresses more of, an MS-ZIP stream.
*
@@ -108,6 +108,11 @@ extern struct mszipd_stream *mszipd_init(struct mspack_system *system,
*/
extern int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes);
+/* decompresses an entire MS-ZIP stream in a KWAJ file. Acts very much
+ * like mszipd_decompress(), but doesn't take an out_bytes parameter
+ */
+extern int mszipd_decompress_kwaj(struct mszipd_stream *zip);
+
/* frees all stream associated with an MS-ZIP data stream
*
* - calls system->free() using the system pointer given in mszipd_init()
diff --git a/rbutil/rbutilqt/mspack/mszipd.c b/rbutil/rbutilqt/mspack/mszipd.c
index 3c158fbd4d..c1b02b1207 100644
--- a/rbutil/rbutilqt/mspack/mszipd.c
+++ b/rbutil/rbutilqt/mspack/mszipd.c
@@ -20,9 +20,9 @@
#define BITS_VAR zip
#define BITS_ORDER_LSB
#define BITS_LSB_TABLE
-#define READ_BYTES do { \
- READ_IF_NEEDED; \
- INJECT_BITS(*i_ptr++, 8); \
+#define READ_BYTES do { \
+ READ_IF_NEEDED; \
+ INJECT_BITS(*i_ptr++, 8); \
} while (0)
#include "readbits.h"
@@ -34,13 +34,13 @@
#define HUFF_ERROR return INF_ERR_HUFFSYM
#include "readhuff.h"
-#define FLUSH_IF_NEEDED do { \
- if (zip->window_posn == MSZIP_FRAME_SIZE) { \
- if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) { \
- return INF_ERR_FLUSH; \
- } \
- zip->window_posn = 0; \
- } \
+#define FLUSH_IF_NEEDED do { \
+ if (zip->window_posn == MSZIP_FRAME_SIZE) { \
+ if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) { \
+ return INF_ERR_FLUSH; \
+ } \
+ zip->window_posn = 0; \
+ } \
} while (0)
/* match lengths for literal codes 257.. 285 */
@@ -181,14 +181,14 @@ static int inflate(struct mszipd_stream *zip) {
/* read 4 bytes of data, emptying the bit-buffer if necessary */
for (i = 0; (bits_left >= 8); i++) {
- if (i == 4) return INF_ERR_BITBUF;
- lens_buf[i] = PEEK_BITS(8);
- REMOVE_BITS(8);
+ if (i == 4) return INF_ERR_BITBUF;
+ lens_buf[i] = PEEK_BITS(8);
+ REMOVE_BITS(8);
}
if (bits_left != 0) return INF_ERR_BITBUF;
while (i < 4) {
- READ_IF_NEEDED;
- lens_buf[i++] = *i_ptr++;
+ READ_IF_NEEDED;
+ lens_buf[i++] = *i_ptr++;
}
/* get the length and its complement */
@@ -198,18 +198,18 @@ static int inflate(struct mszipd_stream *zip) {
/* read and copy the uncompressed data into the window */
while (length > 0) {
- READ_IF_NEEDED;
-
- this_run = length;
- if (this_run > (unsigned int)(i_end - i_ptr)) this_run = i_end - i_ptr;
- if (this_run > (MSZIP_FRAME_SIZE - zip->window_posn))
- this_run = MSZIP_FRAME_SIZE - zip->window_posn;
-
- zip->sys->copy(i_ptr, &zip->window[zip->window_posn], this_run);
- zip->window_posn += this_run;
- i_ptr += this_run;
- length -= this_run;
- FLUSH_IF_NEEDED;
+ READ_IF_NEEDED;
+
+ this_run = length;
+ if (this_run > (unsigned int)(i_end - i_ptr)) this_run = i_end - i_ptr;
+ if (this_run > (MSZIP_FRAME_SIZE - zip->window_posn))
+ this_run = MSZIP_FRAME_SIZE - zip->window_posn;
+
+ zip->sys->copy(i_ptr, &zip->window[zip->window_posn], this_run);
+ zip->window_posn += this_run;
+ i_ptr += this_run;
+ length -= this_run;
+ FLUSH_IF_NEEDED;
}
}
else if ((block_type == 1) || (block_type == 2)) {
@@ -217,92 +217,92 @@ static int inflate(struct mszipd_stream *zip) {
unsigned int match_posn, code;
if (block_type == 1) {
- /* block with fixed Huffman codes */
- i = 0;
- while (i < 144) zip->LITERAL_len[i++] = 8;
- while (i < 256) zip->LITERAL_len[i++] = 9;
- while (i < 280) zip->LITERAL_len[i++] = 7;
- while (i < 288) zip->LITERAL_len[i++] = 8;
- for (i = 0; i < 32; i++) zip->DISTANCE_len[i] = 5;
+ /* block with fixed Huffman codes */
+ i = 0;
+ while (i < 144) zip->LITERAL_len[i++] = 8;
+ while (i < 256) zip->LITERAL_len[i++] = 9;
+ while (i < 280) zip->LITERAL_len[i++] = 7;
+ while (i < 288) zip->LITERAL_len[i++] = 8;
+ for (i = 0; i < 32; i++) zip->DISTANCE_len[i] = 5;
}
else {
- /* block with dynamic Huffman codes */
- STORE_BITS;
- if ((i = zip_read_lens(zip))) return i;
- RESTORE_BITS;
+ /* block with dynamic Huffman codes */
+ STORE_BITS;
+ if ((i = zip_read_lens(zip))) return i;
+ RESTORE_BITS;
}
/* now huffman lengths are read for either kind of block,
* create huffman decoding tables */
if (make_decode_table(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS,
- &zip->LITERAL_len[0], &zip->LITERAL_table[0]))
+ &zip->LITERAL_len[0], &zip->LITERAL_table[0]))
{
- return INF_ERR_LITERALTBL;
+ return INF_ERR_LITERALTBL;
}
if (make_decode_table(MSZIP_DISTANCE_MAXSYMBOLS,MSZIP_DISTANCE_TABLEBITS,
- &zip->DISTANCE_len[0], &zip->DISTANCE_table[0]))
+ &zip->DISTANCE_len[0], &zip->DISTANCE_table[0]))
{
- return INF_ERR_DISTANCETBL;
+ return INF_ERR_DISTANCETBL;
}
/* decode forever until end of block code */
for (;;) {
- READ_HUFFSYM(LITERAL, code);
- if (code < 256) {
- zip->window[zip->window_posn++] = (unsigned char) code;
- FLUSH_IF_NEEDED;
- }
- else if (code == 256) {
- /* END OF BLOCK CODE: loop break point */
- break;
- }
- else {
- code -= 257; /* codes 257-285 are matches */
- if (code >= 29) return INF_ERR_LITCODE; /* codes 286-287 are illegal */
- READ_BITS_T(length, lit_extrabits[code]);
- length += lit_lengths[code];
-
- READ_HUFFSYM(DISTANCE, code);
- if (code > 30) return INF_ERR_DISTCODE;
- READ_BITS_T(distance, dist_extrabits[code]);
- distance += dist_offsets[code];
-
- /* match position is window position minus distance. If distance
- * is more than window position numerically, it must 'wrap
- * around' the frame size. */
- match_posn = ((distance > zip->window_posn) ? MSZIP_FRAME_SIZE : 0)
- + zip->window_posn - distance;
-
- /* copy match */
- if (length < 12) {
- /* short match, use slower loop but no loop setup code */
- while (length--) {
- zip->window[zip->window_posn++] = zip->window[match_posn++];
- match_posn &= MSZIP_FRAME_SIZE - 1;
- FLUSH_IF_NEEDED;
- }
- }
- else {
- /* longer match, use faster loop but with setup expense */
- unsigned char *runsrc, *rundest;
- do {
- this_run = length;
- if ((match_posn + this_run) > MSZIP_FRAME_SIZE)
- this_run = MSZIP_FRAME_SIZE - match_posn;
- if ((zip->window_posn + this_run) > MSZIP_FRAME_SIZE)
- this_run = MSZIP_FRAME_SIZE - zip->window_posn;
-
- rundest = &zip->window[zip->window_posn]; zip->window_posn += this_run;
- runsrc = &zip->window[match_posn]; match_posn += this_run;
- length -= this_run;
- while (this_run--) *rundest++ = *runsrc++;
- if (match_posn == MSZIP_FRAME_SIZE) match_posn = 0;
- FLUSH_IF_NEEDED;
- } while (length > 0);
- }
-
- } /* else (code >= 257) */
+ READ_HUFFSYM(LITERAL, code);
+ if (code < 256) {
+ zip->window[zip->window_posn++] = (unsigned char) code;
+ FLUSH_IF_NEEDED;
+ }
+ else if (code == 256) {
+ /* END OF BLOCK CODE: loop break point */
+ break;
+ }
+ else {
+ code -= 257; /* codes 257-285 are matches */
+ if (code >= 29) return INF_ERR_LITCODE; /* codes 286-287 are illegal */
+ READ_BITS_T(length, lit_extrabits[code]);
+ length += lit_lengths[code];
+
+ READ_HUFFSYM(DISTANCE, code);
+ if (code >= 30) return INF_ERR_DISTCODE;
+ READ_BITS_T(distance, dist_extrabits[code]);
+ distance += dist_offsets[code];
+
+ /* match position is window position minus distance. If distance
+ * is more than window position numerically, it must 'wrap
+ * around' the frame size. */
+ match_posn = ((distance > zip->window_posn) ? MSZIP_FRAME_SIZE : 0)
+ + zip->window_posn - distance;
+
+ /* copy match */
+ if (length < 12) {
+ /* short match, use slower loop but no loop setup code */
+ while (length--) {
+ zip->window[zip->window_posn++] = zip->window[match_posn++];
+ match_posn &= MSZIP_FRAME_SIZE - 1;
+ FLUSH_IF_NEEDED;
+ }
+ }
+ else {
+ /* longer match, use faster loop but with setup expense */
+ unsigned char *runsrc, *rundest;
+ do {
+ this_run = length;
+ if ((match_posn + this_run) > MSZIP_FRAME_SIZE)
+ this_run = MSZIP_FRAME_SIZE - match_posn;
+ if ((zip->window_posn + this_run) > MSZIP_FRAME_SIZE)
+ this_run = MSZIP_FRAME_SIZE - zip->window_posn;
+
+ rundest = &zip->window[zip->window_posn]; zip->window_posn += this_run;
+ runsrc = &zip->window[match_posn]; match_posn += this_run;
+ length -= this_run;
+ while (this_run--) *rundest++ = *runsrc++;
+ if (match_posn == MSZIP_FRAME_SIZE) match_posn = 0;
+ FLUSH_IF_NEEDED;
+ } while (length > 0);
+ }
+
+ } /* else (code >= 257) */
} /* for(;;) -- break point at 'code == 256' */
}
@@ -328,7 +328,7 @@ static int inflate(struct mszipd_stream *zip) {
* is flushed, an error is raised.
*/
static int mszipd_flush_window(struct mszipd_stream *zip,
- unsigned int data_flushed)
+ unsigned int data_flushed)
{
zip->bytes_output += data_flushed;
if (zip->bytes_output > MSZIP_FRAME_SIZE) {
@@ -340,17 +340,18 @@ static int mszipd_flush_window(struct mszipd_stream *zip,
}
struct mszipd_stream *mszipd_init(struct mspack_system *system,
- struct mspack_file *input,
- struct mspack_file *output,
- int input_buffer_size,
- int repair_mode)
+ struct mspack_file *input,
+ struct mspack_file *output,
+ int input_buffer_size,
+ int repair_mode)
{
struct mszipd_stream *zip;
if (!system) return NULL;
+ /* round up input buffer size to multiple of two */
input_buffer_size = (input_buffer_size + 1) & -2;
- if (!input_buffer_size) return NULL;
+ if (input_buffer_size < 2) return NULL;
/* allocate decompression state */
if (!(zip = (struct mszipd_stream *) system->alloc(system, sizeof(struct mszipd_stream)))) {
@@ -426,19 +427,19 @@ int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes) {
if ((error = inflate(zip))) {
D(("inflate error %d", error))
if (zip->repair_mode) {
- /* recover partially-inflated buffers */
- if (zip->bytes_output == 0 && zip->window_posn > 0) {
- zip->flush_window(zip, zip->window_posn);
- }
- zip->sys->message(NULL, "MSZIP error, %u bytes of data lost.",
- MSZIP_FRAME_SIZE - zip->bytes_output);
- for (i = zip->bytes_output; i < MSZIP_FRAME_SIZE; i++) {
- zip->window[i] = '\0';
- }
- zip->bytes_output = MSZIP_FRAME_SIZE;
+ /* recover partially-inflated buffers */
+ if (zip->bytes_output == 0 && zip->window_posn > 0) {
+ zip->flush_window(zip, zip->window_posn);
+ }
+ zip->sys->message(NULL, "MSZIP error, %u bytes of data lost.",
+ MSZIP_FRAME_SIZE - zip->bytes_output);
+ for (i = zip->bytes_output; i < MSZIP_FRAME_SIZE; i++) {
+ zip->window[i] = '\0';
+ }
+ zip->bytes_output = MSZIP_FRAME_SIZE;
}
else {
- return zip->error = (error > 0) ? error : MSPACK_ERR_DECRUNCH;
+ return zip->error = (error > 0) ? error : MSPACK_ERR_DECRUNCH;
}
}
zip->o_ptr = &zip->window[0];
@@ -465,6 +466,45 @@ int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes) {
return MSPACK_ERR_OK;
}
+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;
+
+ int i, error, block_len;
+
+ /* unpack blocks until block_len == 0 */
+ for (;;) {
+ RESTORE_BITS;
+
+ /* align to bytestream, read block_len */
+ i = bits_left & 7; REMOVE_BITS(i);
+ READ_BITS(block_len, 8);
+ READ_BITS(i, 8); block_len |= i << 8;
+
+ if (block_len == 0) break;
+
+ /* read "CK" header */
+ READ_BITS(i, 8); if (i != 'C') return MSPACK_ERR_DATAFORMAT;
+ READ_BITS(i, 8); if (i != 'K') return MSPACK_ERR_DATAFORMAT;
+
+ /* inflate block */
+ zip->window_posn = 0;
+ zip->bytes_output = 0;
+ STORE_BITS;
+ if ((error = inflate(zip))) {
+ D(("inflate error %d", error))
+ return zip->error = (error > 0) ? error : MSPACK_ERR_DECRUNCH;
+ }
+
+ /* write inflated block */
+ if (zip->sys->write(zip->output, &zip->window[0], zip->bytes_output)
+ != zip->bytes_output) return zip->error = MSPACK_ERR_WRITE;
+ }
+ return MSPACK_ERR_OK;
+}
+
void mszipd_free(struct mszipd_stream *zip) {
struct mspack_system *sys;
if (zip) {
diff --git a/rbutil/rbutilqt/mspack/qtm.h b/rbutil/rbutilqt/mspack/qtm.h
index ab0bb4c32c..20a38538a2 100644
--- a/rbutil/rbutilqt/mspack/qtm.h
+++ b/rbutil/rbutilqt/mspack/qtm.h
@@ -90,10 +90,10 @@ struct qtmd_stream {
* - input_buffer_size is the number of bytes to use to store bitstream data.
*/
extern struct qtmd_stream *qtmd_init(struct mspack_system *system,
- struct mspack_file *input,
- struct mspack_file *output,
- int window_bits,
- int input_buffer_size);
+ struct mspack_file *input,
+ struct mspack_file *output,
+ int window_bits,
+ int input_buffer_size);
/* decompresses, or decompresses more of, a Quantum stream.
*
diff --git a/rbutil/rbutilqt/mspack/qtmd.c b/rbutil/rbutilqt/mspack/qtmd.c
index 0fb20da167..58e4787b7f 100644
--- a/rbutil/rbutilqt/mspack/qtmd.c
+++ b/rbutil/rbutilqt/mspack/qtmd.c
@@ -27,11 +27,11 @@
#define BITS_TYPE struct qtmd_stream
#define BITS_VAR qtm
#define BITS_ORDER_MSB
-#define READ_BYTES do { \
- unsigned char b0, b1; \
- READ_IF_NEEDED; b0 = *i_ptr++; \
- READ_IF_NEEDED; b1 = *i_ptr++; \
- INJECT_BITS((b0 << 8) | b1, 16); \
+#define READ_BYTES do { \
+ unsigned char b0, b1; \
+ READ_IF_NEEDED; b0 = *i_ptr++; \
+ READ_IF_NEEDED; b1 = *i_ptr++; \
+ INJECT_BITS((b0 << 8) | b1, 16); \
} while (0)
#include "readbits.h"
@@ -115,7 +115,7 @@ static const unsigned char length_extra[27] = {
else break; \
} \
L <<= 1; H = (H << 1) | 1; \
- ENSURE_BITS(1); \
+ ENSURE_BITS(1); \
C = (C << 1) | PEEK_BITS(1); \
REMOVE_BITS(1); \
} \
@@ -130,7 +130,7 @@ static void qtmd_update_model(struct qtmd_model *model) {
/* -1, not -2; the 0 entry saves this */
model->syms[i].cumfreq >>= 1;
if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) {
- model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1;
+ model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1;
}
}
}
@@ -149,11 +149,11 @@ static void qtmd_update_model(struct qtmd_model *model) {
* characteristics */
for (i = 0; i < model->entries - 1; i++) {
for (j = i + 1; j < model->entries; j++) {
- if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
- tmp = model->syms[i];
- model->syms[i] = model->syms[j];
- model->syms[j] = tmp;
- }
+ if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
+ tmp = model->syms[i];
+ model->syms[i] = model->syms[j];
+ model->syms[j] = tmp;
+ }
}
}
@@ -166,7 +166,7 @@ static void qtmd_update_model(struct qtmd_model *model) {
/* Initialises a model to decode symbols from [start] to [start]+[len]-1 */
static void qtmd_init_model(struct qtmd_model *model,
- struct qtmd_modelsym *syms, int start, int len)
+ struct qtmd_modelsym *syms, int start, int len)
{
int i;
@@ -184,9 +184,9 @@ static void qtmd_init_model(struct qtmd_model *model,
/*-------- main Quantum code --------*/
struct qtmd_stream *qtmd_init(struct mspack_system *system,
- struct mspack_file *input,
- struct mspack_file *output,
- int window_bits, int input_buffer_size)
+ struct mspack_file *input,
+ struct mspack_file *output,
+ int window_bits, int input_buffer_size)
{
unsigned int window_size = 1 << window_bits;
struct qtmd_stream *qtm;
@@ -197,6 +197,7 @@ struct qtmd_stream *qtmd_init(struct mspack_system *system,
/* Quantum supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */
if (window_bits < 10 || window_bits > 21) return NULL;
+ /* round up input buffer size to multiple of two */
input_buffer_size = (input_buffer_size + 1) & -2;
if (input_buffer_size < 2) return NULL;
@@ -307,113 +308,113 @@ int qtmd_decompress(struct qtmd_stream *qtm, off_t out_bytes) {
while (window_posn < frame_end) {
GET_SYMBOL(qtm->model7, selector);
if (selector < 4) {
- /* literal byte */
- struct qtmd_model *mdl = (selector == 0) ? &qtm->model0 :
- ((selector == 1) ? &qtm->model1 :
- ((selector == 2) ? &qtm->model2 :
+ /* literal byte */
+ struct qtmd_model *mdl = (selector == 0) ? &qtm->model0 :
+ ((selector == 1) ? &qtm->model1 :
+ ((selector == 2) ? &qtm->model2 :
&qtm->model3));
- GET_SYMBOL((*mdl), sym);
- window[window_posn++] = sym;
- frame_todo--;
+ GET_SYMBOL((*mdl), sym);
+ window[window_posn++] = sym;
+ frame_todo--;
}
else {
- /* match repeated string */
- switch (selector) {
- case 4: /* selector 4 = fixed length match (3 bytes) */
- GET_SYMBOL(qtm->model4, sym);
- READ_MANY_BITS(extra, extra_bits[sym]);
- match_offset = position_base[sym] + extra + 1;
- match_length = 3;
- break;
-
- case 5: /* selector 5 = fixed length match (4 bytes) */
- GET_SYMBOL(qtm->model5, sym);
- READ_MANY_BITS(extra, extra_bits[sym]);
- match_offset = position_base[sym] + extra + 1;
- match_length = 4;
- break;
-
- case 6: /* selector 6 = variable length match */
- GET_SYMBOL(qtm->model6len, sym);
- READ_MANY_BITS(extra, length_extra[sym]);
- match_length = length_base[sym] + extra + 5;
-
- GET_SYMBOL(qtm->model6, sym);
- READ_MANY_BITS(extra, extra_bits[sym]);
- match_offset = position_base[sym] + extra + 1;
- break;
-
- default:
- /* should be impossible, model7 can only return 0-6 */
- D(("got %d from selector", selector))
- return qtm->error = MSPACK_ERR_DECRUNCH;
- }
-
- rundest = &window[window_posn];
- frame_todo -= match_length;
-
- /* does match destination wrap the window? This situation is possible
- * where the window size is less than the 32k frame size, but matches
- * must not go beyond a frame boundary */
- if ((window_posn + match_length) > qtm->window_size) {
+ /* match repeated string */
+ switch (selector) {
+ case 4: /* selector 4 = fixed length match (3 bytes) */
+ GET_SYMBOL(qtm->model4, sym);
+ READ_MANY_BITS(extra, extra_bits[sym]);
+ match_offset = position_base[sym] + extra + 1;
+ match_length = 3;
+ break;
+
+ case 5: /* selector 5 = fixed length match (4 bytes) */
+ GET_SYMBOL(qtm->model5, sym);
+ READ_MANY_BITS(extra, extra_bits[sym]);
+ match_offset = position_base[sym] + extra + 1;
+ match_length = 4;
+ break;
+
+ case 6: /* selector 6 = variable length match */
+ GET_SYMBOL(qtm->model6len, sym);
+ READ_MANY_BITS(extra, length_extra[sym]);
+ match_length = length_base[sym] + extra + 5;
+
+ GET_SYMBOL(qtm->model6, sym);
+ READ_MANY_BITS(extra, extra_bits[sym]);
+ match_offset = position_base[sym] + extra + 1;
+ break;
+
+ default:
+ /* should be impossible, model7 can only return 0-6 */
+ D(("got %d from selector", selector))
+ return qtm->error = MSPACK_ERR_DECRUNCH;
+ }
+
+ rundest = &window[window_posn];
+ frame_todo -= match_length;
+
+ /* does match destination wrap the window? This situation is possible
+ * where the window size is less than the 32k frame size, but matches
+ * must not go beyond a frame boundary */
+ if ((window_posn + match_length) > qtm->window_size) {
/* copy first part of match, before window end */
- i = qtm->window_size - window_posn;
- j = window_posn - match_offset;
- while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
-
- /* flush currently stored data */
- i = (&window[qtm->window_size] - qtm->o_ptr);
-
- /* this should not happen, but if it does then this code
- * can't handle the situation (can't flush up to the end of
- * the window, but can't break out either because we haven't
- * finished writing the match). bail out in this case */
- if (i > out_bytes) {
- D(("during window-wrap match; %d bytes to flush but only need %d",
- i, (int) out_bytes))
- return qtm->error = MSPACK_ERR_DECRUNCH;
- }
- if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
- return qtm->error = MSPACK_ERR_WRITE;
- }
- out_bytes -= i;
- qtm->o_ptr = &window[0];
- qtm->o_end = &window[0];
-
- /* copy second part of match, after window wrap */
- rundest = &window[0];
- i = match_length - (qtm->window_size - window_posn);
- while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
- window_posn = window_posn + match_length - qtm->window_size;
+ i = qtm->window_size - window_posn;
+ j = window_posn - match_offset;
+ while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
+
+ /* flush currently stored data */
+ i = (&window[qtm->window_size] - qtm->o_ptr);
+
+ /* this should not happen, but if it does then this code
+ * can't handle the situation (can't flush up to the end of
+ * the window, but can't break out either because we haven't
+ * finished writing the match). bail out in this case */
+ if (i > out_bytes) {
+ D(("during window-wrap match; %d bytes to flush but only need %d",
+ i, (int) out_bytes))
+ return qtm->error = MSPACK_ERR_DECRUNCH;
+ }
+ if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
+ return qtm->error = MSPACK_ERR_WRITE;
+ }
+ out_bytes -= i;
+ qtm->o_ptr = &window[0];
+ qtm->o_end = &window[0];
+
+ /* copy second part of match, after window wrap */
+ rundest = &window[0];
+ i = match_length - (qtm->window_size - window_posn);
+ while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
+ window_posn = window_posn + match_length - qtm->window_size;
break; /* because "window_posn < frame_end" has now failed */
- }
- else {
+ }
+ else {
/* normal match - output won't wrap window or frame end */
- i = match_length;
-
- /* does match _offset_ wrap the window? */
- if (match_offset > window_posn) {
- /* j = length from match offset to end of window */
- j = match_offset - window_posn;
- if (j > (int) qtm->window_size) {
- D(("match offset beyond window boundaries"))
- return qtm->error = MSPACK_ERR_DECRUNCH;
- }
- runsrc = &window[qtm->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++;
- }
- window_posn += match_length;
- }
+ i = match_length;
+
+ /* does match _offset_ wrap the window? */
+ if (match_offset > window_posn) {
+ /* j = length from match offset to end of window */
+ j = match_offset - window_posn;
+ if (j > (int) qtm->window_size) {
+ D(("match offset beyond window boundaries"))
+ return qtm->error = MSPACK_ERR_DECRUNCH;
+ }
+ runsrc = &window[qtm->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++;
+ }
+ window_posn += match_length;
+ }
} /* if (window_posn+match_length > frame_end) */
} /* while (window_posn < frame_end) */
@@ -448,7 +449,7 @@ int qtmd_decompress(struct qtmd_stream *qtm, off_t out_bytes) {
/* break out if we have more than enough to finish this request */
if (i >= out_bytes) break;
if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
- return qtm->error = MSPACK_ERR_WRITE;
+ return qtm->error = MSPACK_ERR_WRITE;
}
out_bytes -= i;
qtm->o_ptr = &window[0];
diff --git a/rbutil/rbutilqt/mspack/readbits.h b/rbutil/rbutilqt/mspack/readbits.h
index 457cbdd7d4..9b237a3693 100644
--- a/rbutil/rbutilqt/mspack/readbits.h
+++ b/rbutil/rbutilqt/mspack/readbits.h
@@ -100,48 +100,48 @@
#endif
#define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT)
-#define INIT_BITS do { \
- BITS_VAR->i_ptr = &BITS_VAR->inbuf[0]; \
- BITS_VAR->i_end = &BITS_VAR->inbuf[0]; \
- BITS_VAR->bit_buffer = 0; \
- BITS_VAR->bits_left = 0; \
- BITS_VAR->input_end = 0; \
+#define INIT_BITS do { \
+ BITS_VAR->i_ptr = &BITS_VAR->inbuf[0]; \
+ BITS_VAR->i_end = &BITS_VAR->inbuf[0]; \
+ BITS_VAR->bit_buffer = 0; \
+ BITS_VAR->bits_left = 0; \
+ BITS_VAR->input_end = 0; \
} while (0)
-#define STORE_BITS do { \
- BITS_VAR->i_ptr = i_ptr; \
- BITS_VAR->i_end = i_end; \
- BITS_VAR->bit_buffer = bit_buffer; \
- BITS_VAR->bits_left = bits_left; \
+#define STORE_BITS do { \
+ BITS_VAR->i_ptr = i_ptr; \
+ BITS_VAR->i_end = i_end; \
+ BITS_VAR->bit_buffer = bit_buffer; \
+ BITS_VAR->bits_left = bits_left; \
} while (0)
-#define RESTORE_BITS do { \
- i_ptr = BITS_VAR->i_ptr; \
- i_end = BITS_VAR->i_end; \
- bit_buffer = BITS_VAR->bit_buffer; \
- bits_left = BITS_VAR->bits_left; \
+#define RESTORE_BITS do { \
+ i_ptr = BITS_VAR->i_ptr; \
+ i_end = BITS_VAR->i_end; \
+ bit_buffer = BITS_VAR->bit_buffer; \
+ bits_left = BITS_VAR->bits_left; \
} while (0)
-#define ENSURE_BITS(nbits) do { \
- while (bits_left < (nbits)) READ_BYTES; \
+#define ENSURE_BITS(nbits) do { \
+ while (bits_left < (nbits)) READ_BYTES; \
} while (0)
-#define READ_BITS(val, nbits) do { \
- ENSURE_BITS(nbits); \
- (val) = PEEK_BITS(nbits); \
- REMOVE_BITS(nbits); \
+#define READ_BITS(val, nbits) do { \
+ ENSURE_BITS(nbits); \
+ (val) = PEEK_BITS(nbits); \
+ REMOVE_BITS(nbits); \
} while (0)
-#define READ_MANY_BITS(val, bits) do { \
- unsigned char needed = (bits), bitrun; \
- (val) = 0; \
- while (needed > 0) { \
- if (bits_left <= (BITBUF_WIDTH - 16)) READ_BYTES; \
- bitrun = (bits_left < needed) ? bits_left : needed; \
- (val) = ((val) << bitrun) | PEEK_BITS(bitrun); \
- REMOVE_BITS(bitrun); \
- needed -= bitrun; \
- } \
+#define READ_MANY_BITS(val, bits) do { \
+ unsigned char needed = (bits), bitrun; \
+ (val) = 0; \
+ while (needed > 0) { \
+ if (bits_left <= (BITBUF_WIDTH - 16)) READ_BYTES; \
+ bitrun = (bits_left < needed) ? bits_left : needed; \
+ (val) = ((val) << bitrun) | PEEK_BITS(bitrun); \
+ REMOVE_BITS(bitrun); \
+ needed -= bitrun; \
+ } \
} while (0)
#ifdef BITS_ORDER_MSB
@@ -163,21 +163,21 @@ static const unsigned short lsb_bit_mask[17] = {
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
};
# define PEEK_BITS_T(nbits) (bit_buffer & lsb_bit_mask[(nbits)])
-# define READ_BITS_T(val, nbits) do { \
- ENSURE_BITS(nbits); \
- (val) = PEEK_BITS_T(nbits); \
- REMOVE_BITS(nbits); \
+# define READ_BITS_T(val, nbits) do { \
+ ENSURE_BITS(nbits); \
+ (val) = PEEK_BITS_T(nbits); \
+ REMOVE_BITS(nbits); \
} while (0)
#endif
#ifndef BITS_NO_READ_INPUT
-# define READ_IF_NEEDED do { \
- if (i_ptr >= i_end) { \
- if (read_input(BITS_VAR)) \
- return BITS_VAR->error; \
- i_ptr = BITS_VAR->i_ptr; \
- i_end = BITS_VAR->i_end; \
- } \
+# define READ_IF_NEEDED do { \
+ if (i_ptr >= i_end) { \
+ if (read_input(BITS_VAR)) \
+ return BITS_VAR->error; \
+ i_ptr = BITS_VAR->i_ptr; \
+ i_end = BITS_VAR->i_end; \
+ } \
} while (0)
static int read_input(BITS_TYPE *p) {
@@ -187,15 +187,15 @@ static int read_input(BITS_TYPE *p) {
/* we might overrun the input stream by asking for bits we don't use,
* so fake 2 more bytes at the end of input */
if (read == 0) {
- if (p->input_end) {
- D(("out of input bytes"))
- return p->error = MSPACK_ERR_READ;
- }
- else {
- read = 2;
- p->inbuf[0] = p->inbuf[1] = 0;
- p->input_end = 1;
- }
+ if (p->input_end) {
+ D(("out of input bytes"))
+ return p->error = MSPACK_ERR_READ;
+ }
+ else {
+ read = 2;
+ p->inbuf[0] = p->inbuf[1] = 0;
+ p->input_end = 1;
+ }
}
/* update i_ptr and i_end */
diff --git a/rbutil/rbutilqt/mspack/readhuff.h b/rbutil/rbutilqt/mspack/readhuff.h
index bb15c0a123..4d94225789 100644
--- a/rbutil/rbutilqt/mspack/readhuff.h
+++ b/rbutil/rbutilqt/mspack/readhuff.h
@@ -1,5 +1,5 @@
/* This file is part of libmspack.
- * (C) 2003-2010 Stuart Caie.
+ * (C) 2003-2014 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
@@ -10,8 +10,7 @@
#ifndef MSPACK_READHUFF_H
#define MSPACK_READHUFF_H 1
-/* This implements a fast Huffman tree decoding system.
- */
+/* This implements a fast Huffman tree decoding system. */
#if !(defined(BITS_ORDER_MSB) || defined(BITS_ORDER_LSB))
# error "readhuff.h is used in conjunction with readbits.h, include that first"
@@ -32,32 +31,32 @@
/* 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); \
+#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); \
} while (0)
#ifdef BITS_ORDER_LSB
-# define HUFF_TRAVERSE(tbl) do { \
- i = TABLEBITS(tbl) - 1; \
- do { \
- if (i++ > HUFF_MAXBITS) HUFF_ERROR; \
- sym = HUFF_TABLE(tbl, \
- (sym << 1) | ((bit_buffer >> i) & 1)); \
- } while (sym >= MAXSYMBOLS(tbl)); \
+# define HUFF_TRAVERSE(tbl) do { \
+ i = TABLEBITS(tbl) - 1; \
+ do { \
+ if (i++ > HUFF_MAXBITS) HUFF_ERROR; \
+ sym = HUFF_TABLE(tbl, \
+ (sym << 1) | ((bit_buffer >> i) & 1)); \
+ } while (sym >= MAXSYMBOLS(tbl)); \
} while (0)
#else
-#define HUFF_TRAVERSE(tbl) do { \
- i = 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)); \
+#define HUFF_TRAVERSE(tbl) do { \
+ i = 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)); \
} while (0)
#endif
@@ -77,7 +76,7 @@
* Returns 0 for OK or 1 for error
*/
static int make_decode_table(unsigned int nsyms, unsigned int nbits,
- unsigned char *length, unsigned short *table)
+ unsigned char *length, unsigned short *table)
{
register unsigned short sym, next_symbol;
register unsigned int leaf, fill;
@@ -91,27 +90,27 @@ static int make_decode_table(unsigned int nsyms, unsigned int nbits,
/* fill entries for codes short enough for a direct mapping */
for (bit_num = 1; bit_num <= nbits; bit_num++) {
- for (sym = 0; sym < nsyms; sym++) {
- if (length[sym] != bit_num) continue;
+ for (sym = 0; sym < nsyms; sym++) {
+ if (length[sym] != bit_num) continue;
#ifdef BITS_ORDER_MSB
- leaf = pos;
+ leaf = pos;
#else
- /* reverse the significant bits */
- fill = length[sym]; reverse = pos >> (nbits - fill); leaf = 0;
- do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
+ /* reverse the significant bits */
+ fill = length[sym]; reverse = pos >> (nbits - fill); leaf = 0;
+ do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
#endif
- if((pos += bit_mask) > table_mask) return 1; /* table overrun */
+ if((pos += bit_mask) > table_mask) return 1; /* table overrun */
- /* fill all possible lookups of this symbol with the symbol itself */
+ /* fill all possible lookups of this symbol with the symbol itself */
#ifdef BITS_ORDER_MSB
- for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym;
+ for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym;
#else
- fill = bit_mask; next_symbol = 1 << bit_num;
- do { table[leaf] = sym; leaf += next_symbol; } while (--fill);
+ fill = bit_mask; next_symbol = 1 << bit_num;
+ do { table[leaf] = sym; leaf += next_symbol; } while (--fill);
#endif
- }
- bit_mask >>= 1;
+ }
+ bit_mask >>= 1;
}
/* exit with success if table is now complete */
@@ -120,11 +119,11 @@ static int make_decode_table(unsigned int nsyms, unsigned int nbits,
/* mark all remaining table entries as unused */
for (sym = pos; sym < table_mask; sym++) {
#ifdef BITS_ORDER_MSB
- table[sym] = 0xFFFF;
+ table[sym] = 0xFFFF;
#else
- reverse = sym; leaf = 0; fill = nbits;
- do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill);
- table[leaf] = 0xFFFF;
+ reverse = sym; leaf = 0; fill = nbits;
+ do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill);
+ table[leaf] = 0xFFFF;
#endif
}
@@ -138,33 +137,33 @@ static int make_decode_table(unsigned int nsyms, unsigned int nbits,
bit_mask = 1 << 15;
for (bit_num = nbits+1; bit_num <= HUFF_MAXBITS; bit_num++) {
- for (sym = 0; sym < nsyms; sym++) {
- if (length[sym] != bit_num) continue;
+ for (sym = 0; sym < nsyms; sym++) {
+ if (length[sym] != bit_num) continue;
+ if (pos >= table_mask) return 1; /* table overflow */
#ifdef BITS_ORDER_MSB
- leaf = pos >> 16;
+ leaf = pos >> 16;
#else
- /* leaf = the first nbits of the code, reversed */
- reverse = pos >> 16; leaf = 0; fill = nbits;
- do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
+ /* leaf = the first nbits of the code, reversed */
+ reverse = pos >> 16; leaf = 0; fill = nbits;
+ do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
#endif
- for (fill = 0; fill < (bit_num - nbits); fill++) {
- /* if this path hasn't been taken yet, 'allocate' two entries */
- if (table[leaf] == 0xFFFF) {
- table[(next_symbol << 1) ] = 0xFFFF;
- table[(next_symbol << 1) + 1 ] = 0xFFFF;
- table[leaf] = next_symbol++;
- }
-
- /* follow the path and select either left or right for next bit */
- leaf = table[leaf] << 1;
- if ((pos >> (15-fill)) & 1) leaf++;
- }
- table[leaf] = sym;
-
- if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
- }
- bit_mask >>= 1;
+ for (fill = 0; fill < (bit_num - nbits); fill++) {
+ /* if this path hasn't been taken yet, 'allocate' two entries */
+ if (table[leaf] == 0xFFFF) {
+ table[(next_symbol << 1) ] = 0xFFFF;
+ table[(next_symbol << 1) + 1 ] = 0xFFFF;
+ table[leaf] = next_symbol++;
+ }
+
+ /* follow the path and select either left or right for next bit */
+ leaf = table[leaf] << 1;
+ if ((pos >> (15-fill)) & 1) leaf++;
+ }
+ table[leaf] = sym;
+ pos += bit_mask;
+ }
+ bit_mask >>= 1;
}
/* full table? */
diff --git a/rbutil/rbutilqt/mspack/system-mspack.c b/rbutil/rbutilqt/mspack/system-mspack.c
index 13946576fc..9d4886a8db 100644
--- a/rbutil/rbutilqt/mspack/system-mspack.c
+++ b/rbutil/rbutilqt/mspack/system-mspack.c
@@ -8,7 +8,7 @@
*/
#ifdef HAVE_CONFIG_H
-# include <config.h>
+# include "config.h"
#endif
#include "system-mspack.h"
diff --git a/rbutil/rbutilqt/mspack/system-mspack.h b/rbutil/rbutilqt/mspack/system-mspack.h
index 7a033cb04a..a0e6cf3ca8 100644
--- a/rbutil/rbutilqt/mspack/system-mspack.h
+++ b/rbutil/rbutilqt/mspack/system-mspack.h
@@ -16,7 +16,7 @@ extern "C" {
/* ensure config.h is read before mspack.h */
#ifdef HAVE_CONFIG_H
-# include <config.h>
+# include "config.h"
#endif
#include "mspack.h"
@@ -61,7 +61,7 @@ extern "C" {
(defined(FILESIZEBITS) && FILESIZEBITS >= 64) || \
(defined(SIZEOF_OFF_T) && SIZEOF_OFF_T >= 8) || \
defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE))
-# define LARGEFILE_SUPPORT
+# define LARGEFILE_SUPPORT 1
# define LD "lld"
# define LU "llu"
#else
diff --git a/rbutil/rbutilqt/mspack/szddd.c b/rbutil/rbutilqt/mspack/szddd.c
index af77f15565..1d6d05f844 100644
--- a/rbutil/rbutilqt/mspack/szddd.c
+++ b/rbutil/rbutilqt/mspack/szddd.c
@@ -66,8 +66,8 @@ void mspack_destroy_szdd_decompressor(struct msszdd_decompressor *base)
{
struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
if (self) {
- struct mspack_system *sys = self->system;
- sys->free(self);
+ struct mspack_system *sys = self->system;
+ sys->free(self);
}
}
@@ -77,7 +77,7 @@ void mspack_destroy_szdd_decompressor(struct msszdd_decompressor *base)
* opens an SZDD file without decompressing, reads header
*/
static struct msszddd_header *szddd_open(struct msszdd_decompressor *base,
- const char *filename)
+ const char *filename)
{
struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
struct msszddd_header *hdr;
@@ -90,18 +90,18 @@ static struct msszddd_header *szddd_open(struct msszdd_decompressor *base,
fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
hdr = (struct msszddd_header *) sys->alloc(sys, sizeof(struct msszddd_header_p));
if (fh && hdr) {
- ((struct msszddd_header_p *) hdr)->fh = fh;
- self->error = szddd_read_headers(sys, fh, hdr);
+ ((struct msszddd_header_p *) hdr)->fh = fh;
+ self->error = szddd_read_headers(sys, fh, hdr);
}
else {
- if (!fh) self->error = MSPACK_ERR_OPEN;
- if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
+ if (!fh) self->error = MSPACK_ERR_OPEN;
+ if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
}
if (self->error) {
- if (fh) sys->close(fh);
- if (hdr) sys->free(hdr);
- hdr = NULL;
+ if (fh) sys->close(fh);
+ sys->free(hdr);
+ hdr = NULL;
}
return hdr;
@@ -113,7 +113,7 @@ static struct msszddd_header *szddd_open(struct msszdd_decompressor *base,
* closes an SZDD file
*/
static void szddd_close(struct msszdd_decompressor *base,
- struct msszddd_header *hdr)
+ struct msszddd_header *hdr)
{
struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
struct msszddd_header_p *hdr_p = (struct msszddd_header_p *) hdr;
@@ -142,33 +142,33 @@ static unsigned char szdd_signature_qbasic[8] = {
};
static int szddd_read_headers(struct mspack_system *sys,
- struct mspack_file *fh,
- struct msszddd_header *hdr)
+ struct mspack_file *fh,
+ struct msszddd_header *hdr)
{
unsigned char buf[8];
/* read and check signature */
if (sys->read(fh, buf, 8) != 8) return MSPACK_ERR_READ;
- if ((mspack_memcmp(buf, szdd_signature_expand, 8) == 0)) {
- /* common SZDD */
- hdr->format = MSSZDD_FMT_NORMAL;
+ if ((memcmp(buf, szdd_signature_expand, 8) == 0)) {
+ /* common SZDD */
+ hdr->format = MSSZDD_FMT_NORMAL;
- /* read the rest of the header */
- if (sys->read(fh, buf, 6) != 6) return MSPACK_ERR_READ;
- if (buf[0] != 0x41) return MSPACK_ERR_DATAFORMAT;
- hdr->missing_char = buf[1];
- hdr->length = EndGetI32(&buf[2]);
+ /* read the rest of the header */
+ if (sys->read(fh, buf, 6) != 6) return MSPACK_ERR_READ;
+ if (buf[0] != 0x41) return MSPACK_ERR_DATAFORMAT;
+ hdr->missing_char = buf[1];
+ hdr->length = EndGetI32(&buf[2]);
}
- else if ((mspack_memcmp(buf, szdd_signature_qbasic, 8) == 0)) {
- /* special QBasic SZDD */
- hdr->format = MSSZDD_FMT_QBASIC;
- if (sys->read(fh, buf, 4) != 4) return MSPACK_ERR_READ;
- hdr->missing_char = '\0';
- hdr->length = EndGetI32(buf);
+ else if ((memcmp(buf, szdd_signature_qbasic, 8) == 0)) {
+ /* special QBasic SZDD */
+ hdr->format = MSSZDD_FMT_QBASIC;
+ if (sys->read(fh, buf, 4) != 4) return MSPACK_ERR_READ;
+ hdr->missing_char = '\0';
+ hdr->length = EndGetI32(buf);
}
else {
- return MSPACK_ERR_SIGNATURE;
+ return MSPACK_ERR_SIGNATURE;
}
return MSPACK_ERR_OK;
}
@@ -179,7 +179,7 @@ static int szddd_read_headers(struct mspack_system *sys,
* decompresses an SZDD file
*/
static int szddd_extract(struct msszdd_decompressor *base,
- struct msszddd_header *hdr, const char *filename)
+ struct msszddd_header *hdr, const char *filename)
{
struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
struct mspack_file *fh, *outfh;
@@ -195,19 +195,19 @@ static int szddd_extract(struct msszdd_decompressor *base,
/* seek to the compressed data */
data_offset = (hdr->format == MSSZDD_FMT_NORMAL) ? 14 : 12;
if (sys->seek(fh, data_offset, MSPACK_SYS_SEEK_START)) {
- return self->error = MSPACK_ERR_SEEK;
+ return self->error = MSPACK_ERR_SEEK;
}
/* open file for output */
if (!(outfh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
- return self->error = MSPACK_ERR_OPEN;
+ return self->error = MSPACK_ERR_OPEN;
}
/* decompress the data */
self->error = lzss_decompress(sys, fh, outfh, SZDD_INPUT_SIZE,
- hdr->format == MSSZDD_FMT_NORMAL
- ? LZSS_MODE_EXPAND
- : LZSS_MODE_QBASIC);
+ hdr->format == MSSZDD_FMT_NORMAL
+ ? LZSS_MODE_EXPAND
+ : LZSS_MODE_QBASIC);
/* close output file */
sys->close(outfh);
@@ -221,7 +221,7 @@ static int szddd_extract(struct msszdd_decompressor *base,
* unpacks directly from input to output
*/
static int szddd_decompress(struct msszdd_decompressor *base,
- const char *input, const char *output)
+ const char *input, const char *output)
{
struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
struct msszddd_header *hdr;