rbutil: Update libmspack to 0.10.1alpha.

Update to the most recent release. Fix name / include clashes, as has
been done before.

Change-Id: Ia712bb2b5f4b9018b65a46b8bdd04ba42363be8b
This commit is contained in:
Dominik Riebeling 2020-06-08 21:44:02 +02:00
parent b0f22620a2
commit 729b6e4f33
19 changed files with 2066 additions and 1527 deletions

View file

@ -1,6 +1,6 @@
This folder contains the mspack project for MS files compression/decompression.
These files are distributed under the LGPL.
The source files have been last synced with libmspack-0.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

View file

@ -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;
};

View file

@ -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;
/* 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;
/* 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;
/* 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;
/* 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;
/* 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! */
/* 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;
/* 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;
/* 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;
}
#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;
/* 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 ...) */
@ -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;

File diff suppressed because it is too large Load diff

View file

@ -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);
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;
/* 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) {
/* 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 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';
/* 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 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; \
#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 (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;
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;
}
}
/* 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 */

View file

@ -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
}

View file

@ -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 */

View file

@ -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

View file

@ -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[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 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 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++;
}
/* 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 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;
/* 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;
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 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;
/* 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;
}
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;
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;
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) {
/* 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;
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;
}
/* 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;
}
if ((window_posn + match_length) > lzx->window_size) {
D(("match ran over window wrap"))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
/* 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;
}
/* 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++;
}
if ((window_posn + match_length) > lzx->window_size) {
D(("match ran over window wrap"))
return lzx->error = MSPACK_ERR_DECRUNCH;
}
this_run -= match_length;
window_posn += match_length;
}
} /* while (this_run > 0) */
break;
/* 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) {
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 = (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;
}

View file

@ -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

View file

@ -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()

View file

@ -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;
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;
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;
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(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];
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;
/* 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;
/* 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);
}
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) */
} /* 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) {

View file

@ -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.
*

View file

@ -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;
/* 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 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;
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;
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;
}
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;
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) {
/* 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)];
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);
/* 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];
/* 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;
/* 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;
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;
}
/* 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];

View file

@ -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 */

View file

@ -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++;
}
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;
/* 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? */

View file

@ -8,7 +8,7 @@
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
# include "config.h"
#endif
#include "system-mspack.h"

View file

@ -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

View file

@ -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;