mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-12-08 12:45:26 -05:00
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:
parent
b0f22620a2
commit
729b6e4f33
19 changed files with 2066 additions and 1527 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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? */
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "system-mspack.h"
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ extern "C" {
|
|||
|
||||
/* ensure config.h is read before mspack.h */
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include "mspack.h"
|
||||
|
|
@ -61,7 +61,7 @@ extern "C" {
|
|||
(defined(FILESIZEBITS) && FILESIZEBITS >= 64) || \
|
||||
(defined(SIZEOF_OFF_T) && SIZEOF_OFF_T >= 8) || \
|
||||
defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE))
|
||||
# define LARGEFILE_SUPPORT
|
||||
# define LARGEFILE_SUPPORT 1
|
||||
# define LD "lld"
|
||||
# define LU "llu"
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue