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.
|
This folder contains the mspack project for MS files compression/decompression.
|
||||||
These files are distributed under the LGPL.
|
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.
|
/* 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
|
* 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
|
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||||
|
|
@ -10,10 +10,6 @@
|
||||||
#ifndef MSPACK_CAB_H
|
#ifndef MSPACK_CAB_H
|
||||||
#define MSPACK_CAB_H 1
|
#define MSPACK_CAB_H 1
|
||||||
|
|
||||||
#include "mszip.h"
|
|
||||||
#include "qtm.h"
|
|
||||||
#include "lzx.h"
|
|
||||||
|
|
||||||
/* generic CAB definitions */
|
/* generic CAB definitions */
|
||||||
|
|
||||||
/* structure offsets */
|
/* structure offsets */
|
||||||
|
|
@ -70,6 +66,22 @@
|
||||||
#define CAB_BLOCKMAX (32768)
|
#define CAB_BLOCKMAX (32768)
|
||||||
#define CAB_INPUTMAX (CAB_BLOCKMAX+6144)
|
#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 */
|
/* CAB compression definitions */
|
||||||
|
|
||||||
struct mscab_compressor_p {
|
struct mscab_compressor_p {
|
||||||
|
|
@ -85,6 +97,7 @@ struct mscabd_decompress_state {
|
||||||
struct mscabd_folder_data *data; /* current folder split we're in */
|
struct mscabd_folder_data *data; /* current folder split we're in */
|
||||||
unsigned int offset; /* uncompressed offset within folder */
|
unsigned int offset; /* uncompressed offset within folder */
|
||||||
unsigned int block; /* which block are we decompressing? */
|
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 */
|
struct mspack_system sys; /* special I/O code for decompressor */
|
||||||
int comp_type; /* type of compression used by folder */
|
int comp_type; /* type of compression used by folder */
|
||||||
int (*decompress)(void *, off_t); /* decompressor code */
|
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 *infh; /* input file handle */
|
||||||
struct mspack_file *outfh; /* output file handle */
|
struct mspack_file *outfh; /* output file handle */
|
||||||
unsigned char *i_ptr, *i_end; /* input data consumed, end */
|
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_p {
|
||||||
struct mscab_decompressor base;
|
struct mscab_decompressor base;
|
||||||
struct mscabd_decompress_state *d;
|
struct mscabd_decompress_state *d;
|
||||||
struct mspack_system *system;
|
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;
|
int error, read_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of libmspack.
|
/* 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
|
* 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
|
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||||
|
|
@ -23,7 +23,9 @@
|
||||||
|
|
||||||
#include "system-mspack.h"
|
#include "system-mspack.h"
|
||||||
#include "cab.h"
|
#include "cab.h"
|
||||||
#include <assert.h>
|
#include "mszip.h"
|
||||||
|
#include "lzx.h"
|
||||||
|
#include "qtm.h"
|
||||||
|
|
||||||
/* Notes on compliance with cabinet specification:
|
/* Notes on compliance with cabinet specification:
|
||||||
*
|
*
|
||||||
|
|
@ -72,10 +74,9 @@ static void cabd_close(
|
||||||
struct mscab_decompressor *base, struct mscabd_cabinet *origcab);
|
struct mscab_decompressor *base, struct mscabd_cabinet *origcab);
|
||||||
static int cabd_read_headers(
|
static int cabd_read_headers(
|
||||||
struct mspack_system *sys, struct mspack_file *fh,
|
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(
|
static char *cabd_read_string(
|
||||||
struct mspack_system *sys, struct mspack_file *fh,
|
struct mspack_system *sys, struct mspack_file *fh, int *error);
|
||||||
struct mscabd_cabinet_p *cab, int *error);
|
|
||||||
|
|
||||||
static struct mscabd_cabinet *cabd_search(
|
static struct mscabd_cabinet *cabd_search(
|
||||||
struct mscab_decompressor *base, const char *filename);
|
struct mscab_decompressor *base, const char *filename);
|
||||||
|
|
@ -110,7 +111,7 @@ static int cabd_sys_write(
|
||||||
struct mspack_file *file, void *buffer, int bytes);
|
struct mspack_file *file, void *buffer, int bytes);
|
||||||
static int cabd_sys_read_block(
|
static int cabd_sys_read_block(
|
||||||
struct mspack_system *sys, struct mscabd_decompress_state *d, int *out,
|
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(
|
static unsigned int cabd_checksum(
|
||||||
unsigned char *data, unsigned int bytes, unsigned int cksum);
|
unsigned char *data, unsigned int bytes, unsigned int cksum);
|
||||||
static struct noned_state *noned_init(
|
static struct noned_state *noned_init(
|
||||||
|
|
@ -155,9 +156,10 @@ struct mscab_decompressor *
|
||||||
self->d = NULL;
|
self->d = NULL;
|
||||||
self->error = MSPACK_ERR_OK;
|
self->error = MSPACK_ERR_OK;
|
||||||
|
|
||||||
self->param[MSCABD_PARAM_SEARCHBUF] = 32768;
|
self->searchbuf_size = 32768;
|
||||||
self->param[MSCABD_PARAM_FIXMSZIP] = 0;
|
self->fix_mszip = 0;
|
||||||
self->param[MSCABD_PARAM_DECOMPBUF] = 4096;
|
self->buf_size = 4096;
|
||||||
|
self->salvage = 0;
|
||||||
}
|
}
|
||||||
return (struct mscab_decompressor *) self;
|
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;
|
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
|
||||||
if (self) {
|
if (self) {
|
||||||
struct mspack_system *sys = self->system;
|
struct mspack_system *sys = self->system;
|
||||||
cabd_free_decomp(self);
|
|
||||||
if (self->d) {
|
if (self->d) {
|
||||||
if (self->d->infh) sys->close(self->d->infh);
|
if (self->d->infh) sys->close(self->d->infh);
|
||||||
|
cabd_free_decomp(self);
|
||||||
sys->free(self->d);
|
sys->free(self->d);
|
||||||
}
|
}
|
||||||
sys->free(self);
|
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
|
* opens a file and tries to read it as a cabinet file
|
||||||
*/
|
*/
|
||||||
static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
|
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 mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
|
||||||
struct mscabd_cabinet_p *cab = NULL;
|
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 ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
|
||||||
if ((cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
|
if ((cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
|
||||||
cab->base.filename = filename;
|
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) {
|
if (error) {
|
||||||
cabd_close(base, (struct mscabd_cabinet *) cab);
|
cabd_close(base, (struct mscabd_cabinet *) cab);
|
||||||
cab = NULL;
|
cab = NULL;
|
||||||
}
|
}
|
||||||
self->error = error;
|
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.
|
* frees all memory associated with a given mscabd_cabinet.
|
||||||
*/
|
*/
|
||||||
static void cabd_close(struct mscab_decompressor *base,
|
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 mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
|
||||||
struct mscabd_folder_data *dat, *ndat;
|
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 */
|
/* free folder decompression state if it has been decompressed */
|
||||||
if (self->d && (self->d->folder == (struct mscabd_folder_p *) fol)) {
|
if (self->d && (self->d->folder == (struct mscabd_folder_p *) fol)) {
|
||||||
if (self->d->infh) sys->close(self->d->infh);
|
if (self->d->infh) sys->close(self->d->infh);
|
||||||
cabd_free_decomp(self);
|
cabd_free_decomp(self);
|
||||||
sys->free(self->d);
|
sys->free(self->d);
|
||||||
self->d = NULL;
|
self->d = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* free folder data segments */
|
/* free folder data segments */
|
||||||
for (dat = ((struct mscabd_folder_p *)fol)->data.next; dat; dat = ndat) {
|
for (dat = ((struct mscabd_folder_p *)fol)->data.next; dat; dat = ndat) {
|
||||||
ndat = dat->next;
|
ndat = dat->next;
|
||||||
sys->free(dat);
|
sys->free(dat);
|
||||||
}
|
}
|
||||||
sys->free(fol);
|
sys->free(fol);
|
||||||
}
|
}
|
||||||
|
|
@ -304,11 +306,11 @@ static void cabd_close(struct mscab_decompressor *base,
|
||||||
* for folders and files as necessary
|
* for folders and files as necessary
|
||||||
*/
|
*/
|
||||||
static int cabd_read_headers(struct mspack_system *sys,
|
static int cabd_read_headers(struct mspack_system *sys,
|
||||||
struct mspack_file *fh,
|
struct mspack_file *fh,
|
||||||
struct mscabd_cabinet_p *cab,
|
struct mscabd_cabinet_p *cab,
|
||||||
off_t offset, int quiet)
|
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_folder_p *fol, *linkfol = NULL;
|
||||||
struct mscabd_file *file, *linkfile = NULL;
|
struct mscabd_file *file, *linkfile = NULL;
|
||||||
unsigned char buf[64];
|
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 */
|
/* read the reserved-sizes part of header, if present */
|
||||||
cab->base.flags = EndGetI16(&buf[cfhead_Flags]);
|
cab->base.flags = EndGetI16(&buf[cfhead_Flags]);
|
||||||
|
|
||||||
if (cab->base.flags & cfheadRESERVE_PRESENT) {
|
if (cab->base.flags & cfheadRESERVE_PRESENT) {
|
||||||
if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) {
|
if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) {
|
||||||
return MSPACK_ERR_READ;
|
return MSPACK_ERR_READ;
|
||||||
|
|
@ -379,7 +382,7 @@ static int cabd_read_headers(struct mspack_system *sys,
|
||||||
/* skip the reserved header */
|
/* skip the reserved header */
|
||||||
if (cab->base.header_resv) {
|
if (cab->base.header_resv) {
|
||||||
if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) {
|
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 */
|
/* read name and info of preceeding cabinet in set, if present */
|
||||||
if (cab->base.flags & cfheadPREV_CABINET) {
|
if (cab->base.flags & cfheadPREV_CABINET) {
|
||||||
cab->base.prevname = cabd_read_string(sys, fh, cab, &x); if (x) return x;
|
cab->base.prevname = cabd_read_string(sys, fh, &err);
|
||||||
cab->base.previnfo = cabd_read_string(sys, fh, cab, &x); if (x) return x;
|
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 */
|
/* read name and info of next cabinet in set, if present */
|
||||||
if (cab->base.flags & cfheadNEXT_CABINET) {
|
if (cab->base.flags & cfheadNEXT_CABINET) {
|
||||||
cab->base.nextname = cabd_read_string(sys, fh, cab, &x); if (x) return x;
|
cab->base.nextname = cabd_read_string(sys, fh, &err);
|
||||||
cab->base.nextinfo = cabd_read_string(sys, fh, cab, &x); if (x) return x;
|
if (err) return err;
|
||||||
|
cab->base.nextinfo = cabd_read_string(sys, fh, &err);
|
||||||
|
if (err) return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read folders */
|
/* read folders */
|
||||||
|
|
@ -408,7 +415,7 @@ static int cabd_read_headers(struct mspack_system *sys,
|
||||||
}
|
}
|
||||||
if (folder_resv) {
|
if (folder_resv) {
|
||||||
if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) {
|
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]);
|
file->offset = EndGetI32(&buf[cffile_FolderOffset]);
|
||||||
|
|
||||||
/* set folder pointer */
|
/* set folder pointer */
|
||||||
x = EndGetI16(&buf[cffile_FolderIndex]);
|
fidx = EndGetI16(&buf[cffile_FolderIndex]);
|
||||||
if (x < cffileCONTINUED_FROM_PREV) {
|
if (fidx < cffileCONTINUED_FROM_PREV) {
|
||||||
/* normal folder index; count up to the correct folder. the folder
|
/* normal folder index; count up to the correct folder */
|
||||||
* pointer will be NULL if folder index is invalid */
|
if (fidx < num_folders) {
|
||||||
struct mscabd_folder *ifol = cab->base.folders;
|
struct mscabd_folder *ifol = cab->base.folders;
|
||||||
while (x--) if (ifol) ifol = ifol->next;
|
while (fidx--) if (ifol) ifol = ifol->next;
|
||||||
file->folder = ifol;
|
file->folder = ifol;
|
||||||
|
}
|
||||||
if (!ifol) {
|
else {
|
||||||
sys->free(file);
|
D(("invalid folder index"))
|
||||||
D(("invalid folder index"))
|
file->folder = NULL;
|
||||||
return MSPACK_ERR_DATAFORMAT;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or
|
/* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or
|
||||||
* CONTINUED_PREV_AND_NEXT */
|
* CONTINUED_PREV_AND_NEXT */
|
||||||
if ((x == cffileCONTINUED_TO_NEXT) ||
|
if ((fidx == cffileCONTINUED_TO_NEXT) ||
|
||||||
(x == cffileCONTINUED_PREV_AND_NEXT))
|
(fidx == cffileCONTINUED_PREV_AND_NEXT))
|
||||||
{
|
{
|
||||||
/* get last folder */
|
/* get last folder */
|
||||||
struct mscabd_folder *ifol = cab->base.folders;
|
struct mscabd_folder *ifol = cab->base.folders;
|
||||||
while (ifol->next) ifol = ifol->next;
|
while (ifol->next) ifol = ifol->next;
|
||||||
file->folder = ifol;
|
file->folder = ifol;
|
||||||
|
|
||||||
/* set "merge next" pointer */
|
/* set "merge next" pointer */
|
||||||
fol = (struct mscabd_folder_p *) ifol;
|
fol = (struct mscabd_folder_p *) ifol;
|
||||||
if (!fol->merge_next) fol->merge_next = file;
|
if (!fol->merge_next) fol->merge_next = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((x == cffileCONTINUED_FROM_PREV) ||
|
if ((fidx == cffileCONTINUED_FROM_PREV) ||
|
||||||
(x == cffileCONTINUED_PREV_AND_NEXT))
|
(fidx == cffileCONTINUED_PREV_AND_NEXT))
|
||||||
{
|
{
|
||||||
/* get first folder */
|
/* get first folder */
|
||||||
file->folder = cab->base.folders;
|
file->folder = cab->base.folders;
|
||||||
|
|
||||||
/* set "merge prev" pointer */
|
/* set "merge prev" pointer */
|
||||||
fol = (struct mscabd_folder_p *) file->folder;
|
fol = (struct mscabd_folder_p *) file->folder;
|
||||||
if (!fol->merge_prev) fol->merge_prev = file;
|
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;
|
file->date_y = (x >> 9) + 1980;
|
||||||
|
|
||||||
/* get filename */
|
/* get filename */
|
||||||
file->filename = cabd_read_string(sys, fh, cab, &x);
|
file->filename = cabd_read_string(sys, fh, &err);
|
||||||
if (x) {
|
|
||||||
|
/* if folder index or filename are bad, either skip it or fail */
|
||||||
|
if (err || !file->folder) {
|
||||||
|
sys->free(file->filename);
|
||||||
sys->free(file);
|
sys->free(file);
|
||||||
return x;
|
if (salvage) continue;
|
||||||
|
return err ? err : MSPACK_ERR_DATAFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* link file entry into file list */
|
/* link file entry into file list */
|
||||||
|
|
@ -514,23 +524,34 @@ static int cabd_read_headers(struct mspack_system *sys,
|
||||||
linkfile = file;
|
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;
|
return MSPACK_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *cabd_read_string(struct mspack_system *sys,
|
static char *cabd_read_string(struct mspack_system *sys,
|
||||||
struct mspack_file *fh,
|
struct mspack_file *fh, int *error)
|
||||||
struct mscabd_cabinet_p *cab, int *error)
|
|
||||||
{
|
{
|
||||||
off_t base = sys->tell(fh);
|
off_t base = sys->tell(fh);
|
||||||
char buf[256], *str;
|
char buf[256], *str;
|
||||||
unsigned int len, i, ok;
|
int len, i, ok;
|
||||||
(void)cab;
|
|
||||||
|
|
||||||
/* read up to 256 bytes */
|
/* 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 */
|
/* search for a null terminator in the buffer */
|
||||||
for (i = 0, ok = 0; i < len; i++) if (!buf[i]) { ok = 1; break; }
|
for (i = 0, ok = 0; i < len; i++) if (!buf[i]) { ok = 1; break; }
|
||||||
|
/* reject empty strings */
|
||||||
|
if (i == 0) ok = 0;
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
*error = MSPACK_ERR_DATAFORMAT;
|
*error = MSPACK_ERR_DATAFORMAT;
|
||||||
return NULL;
|
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
|
* break out of the loop and be sure that all resources are freed
|
||||||
*/
|
*/
|
||||||
static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
|
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 mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
|
||||||
struct mscabd_cabinet_p *cab = NULL;
|
struct mscabd_cabinet_p *cab = NULL;
|
||||||
|
|
@ -579,7 +600,7 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
|
||||||
sys = self->system;
|
sys = self->system;
|
||||||
|
|
||||||
/* allocate a search buffer */
|
/* 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) {
|
if (!search_buf) {
|
||||||
self->error = MSPACK_ERR_NOMEMORY;
|
self->error = MSPACK_ERR_NOMEMORY;
|
||||||
return NULL;
|
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 ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
|
||||||
if (!(self->error = mspack_sys_filelen(sys, fh, &filelen))) {
|
if (!(self->error = mspack_sys_filelen(sys, fh, &filelen))) {
|
||||||
self->error = cabd_find(self, search_buf, fh, filename,
|
self->error = cabd_find(self, search_buf, fh, filename,
|
||||||
filelen, &firstlen, &cab);
|
filelen, &firstlen, &cab);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* truncated / extraneous data warning: */
|
/* truncated / extraneous data warning: */
|
||||||
if (firstlen && (firstlen != filelen) &&
|
if (firstlen && (firstlen != filelen) &&
|
||||||
(!cab || (cab->base.base_offset == 0)))
|
(!cab || (cab->base.base_offset == 0)))
|
||||||
{
|
{
|
||||||
if (firstlen < filelen) {
|
if (firstlen < filelen) {
|
||||||
sys->message(fh, "WARNING; possible %" LD
|
sys->message(fh, "WARNING; possible %" LD
|
||||||
" extra bytes at end of file.",
|
" extra bytes at end of file.",
|
||||||
filelen - firstlen);
|
filelen - firstlen);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.",
|
sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.",
|
||||||
firstlen - filelen);
|
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,
|
static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
|
||||||
struct mspack_file *fh, const char *filename, off_t flen,
|
struct mspack_file *fh, const char *filename, off_t flen,
|
||||||
off_t *firstlen, struct mscabd_cabinet_p **firstcab)
|
off_t *firstlen, struct mscabd_cabinet_p **firstcab)
|
||||||
{
|
{
|
||||||
struct mscabd_cabinet_p *cab, *link = NULL;
|
struct mscabd_cabinet_p *cab, *link = NULL;
|
||||||
off_t caboff, offset, length;
|
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;
|
unsigned int cablen_u32 = 0, foffset_u32 = 0;
|
||||||
int false_cabs = 0;
|
int false_cabs = 0;
|
||||||
|
|
||||||
#ifndef LARGEFILE_SUPPORT
|
#if !LARGEFILE_SUPPORT
|
||||||
/* detect 32-bit off_t overflow */
|
/* detect 32-bit off_t overflow */
|
||||||
if (flen < 0) {
|
if (flen < 0) {
|
||||||
sys->message(fh, largefile_msg);
|
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
|
/* 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. */
|
* amount of data remaining to the end of the file, whichever is less. */
|
||||||
length = flen - offset;
|
length = flen - offset;
|
||||||
if (length > self->param[MSCABD_PARAM_SEARCHBUF]) {
|
if (length > self->searchbuf_size) {
|
||||||
length = self->param[MSCABD_PARAM_SEARCHBUF];
|
length = self->searchbuf_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fill the search buffer with data from disk */
|
/* 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 */
|
/* FAQ avoidance strategy */
|
||||||
if ((offset == 0) && (EndGetI32(&buf[0]) == 0x28635349)) {
|
if ((offset == 0) && (EndGetI32(&buf[0]) == 0x28635349)) {
|
||||||
sys->message(fh, "WARNING; found InstallShield header. "
|
sys->message(fh, "WARNING; found InstallShield header. Use unshield "
|
||||||
"This is probably an InstallShield file. "
|
"(https://github.com/twogood/unshield) to unpack this file");
|
||||||
"Use UNSHIELD from www.synce.org to unpack it.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read through the entire buffer. */
|
/* read through the entire buffer. */
|
||||||
for (p = &buf[0], pend = &buf[length]; p < pend; ) {
|
for (p = &buf[0], pend = &buf[length]; p < pend; ) {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
/* starting state */
|
/* starting state */
|
||||||
case 0:
|
case 0:
|
||||||
/* we spend most of our time in this while loop, looking for
|
/* we spend most of our time in this while loop, looking for
|
||||||
* a leading 'M' of the 'MSCF' signature */
|
* a leading 'M' of the 'MSCF' signature */
|
||||||
while (p < pend && *p != 0x4D) p++;
|
while (p < pend && *p != 0x4D) p++;
|
||||||
/* if we found tht 'M', advance state */
|
/* if we found tht 'M', advance state */
|
||||||
if (p++ < pend) state = 1;
|
if (p++ < pend) state = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* verify that the next 3 bytes are 'S', 'C' and 'F' */
|
/* verify that the next 3 bytes are 'S', 'C' and 'F' */
|
||||||
case 1: state = (*p++ == 0x53) ? 2 : 0; break;
|
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 17: foffset_u32 |= *p++ << 8; state++; break;
|
||||||
case 18: foffset_u32 |= *p++ << 16; state++; break;
|
case 18: foffset_u32 |= *p++ << 16; state++; break;
|
||||||
case 19: foffset_u32 |= *p++ << 24;
|
case 19: foffset_u32 |= *p++ << 24;
|
||||||
/* now we have recieved 20 bytes of potential cab header. work out
|
/* now we have recieved 20 bytes of potential cab header. work out
|
||||||
* the offset in the file of this potential cabinet */
|
* the offset in the file of this potential cabinet */
|
||||||
caboff = offset + (p - &buf[0]) - 20;
|
caboff = offset + (p - &buf[0]) - 20;
|
||||||
|
|
||||||
/* should reading cabinet fail, restart search just after 'MSCF' */
|
/* should reading cabinet fail, restart search just after 'MSCF' */
|
||||||
offset = caboff + 4;
|
offset = caboff + 4;
|
||||||
|
|
||||||
/* capture the "length of cabinet" field if there is a cabinet at
|
/* capture the "length of cabinet" field if there is a cabinet at
|
||||||
* offset 0 in the file, regardless of whether the cabinet can be
|
* offset 0 in the file, regardless of whether the cabinet can be
|
||||||
* read correctly or not */
|
* read correctly or not */
|
||||||
if (caboff == 0) *firstlen = (off_t) cablen_u32;
|
if (caboff == 0) *firstlen = (off_t) cablen_u32;
|
||||||
|
|
||||||
/* check that the files offset is less than the alleged length of
|
/* check that the files offset is less than the alleged length of
|
||||||
* the cabinet, and that the offset + the alleged length are
|
* the cabinet, and that the offset + the alleged length are
|
||||||
* 'roughly' within the end of overall file length */
|
* 'roughly' within the end of overall file length. In salvage
|
||||||
if ((foffset_u32 < cablen_u32) &&
|
* mode, don't check the alleged length, allow it to be garbage */
|
||||||
((caboff + (off_t) foffset_u32) < (flen + 32)) &&
|
if ((foffset_u32 < cablen_u32) &&
|
||||||
((caboff + (off_t) cablen_u32) < (flen + 32)) )
|
((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)))) {
|
/* likely cabinet found -- try reading it */
|
||||||
return MSPACK_ERR_NOMEMORY;
|
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)) {
|
cab->base.filename = filename;
|
||||||
/* destroy the failed cabinet */
|
if (cabd_read_headers(sys, fh, cab, caboff, self->salvage, 1)) {
|
||||||
cabd_close((struct mscab_decompressor *) self,
|
/* destroy the failed cabinet */
|
||||||
(struct mscabd_cabinet *) cab);
|
cabd_close((struct mscab_decompressor *) self,
|
||||||
false_cabs++;
|
(struct mscabd_cabinet *) cab);
|
||||||
}
|
false_cabs++;
|
||||||
else {
|
}
|
||||||
/* cabinet read correctly! */
|
else {
|
||||||
|
/* cabinet read correctly! */
|
||||||
|
|
||||||
/* link the cab into the list */
|
/* link the cab into the list */
|
||||||
if (!link) *firstcab = cab;
|
if (!link) *firstcab = cab;
|
||||||
else link->base.next = (struct mscabd_cabinet *) cab;
|
else link->base.next = (struct mscabd_cabinet *) cab;
|
||||||
link = cab;
|
link = cab;
|
||||||
|
|
||||||
/* cause the search to restart after this cab's data. */
|
/* cause the search to restart after this cab's data. */
|
||||||
offset = caboff + (off_t) cablen_u32;
|
offset = caboff + (off_t) cablen_u32;
|
||||||
|
|
||||||
#ifndef LARGEFILE_SUPPORT
|
#if !LARGEFILE_SUPPORT
|
||||||
/* detect 32-bit off_t overflow */
|
/* detect 32-bit off_t overflow */
|
||||||
if (offset < caboff) {
|
if (offset < caboff) {
|
||||||
sys->message(fh, largefile_msg);
|
sys->message(fh, largefile_msg);
|
||||||
return MSPACK_ERR_OK;
|
return MSPACK_ERR_OK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* restart search */
|
/* restart search */
|
||||||
if (offset >= flen) return MSPACK_ERR_OK;
|
if (offset >= flen) return MSPACK_ERR_OK;
|
||||||
if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
|
if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
|
||||||
return MSPACK_ERR_SEEK;
|
return MSPACK_ERR_SEEK;
|
||||||
}
|
}
|
||||||
length = 0;
|
length = 0;
|
||||||
p = pend;
|
p = pend;
|
||||||
state = 0;
|
state = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* for bytes 4-7 and 12-15, just advance state/pointer */
|
/* for bytes 4-7 and 12-15, just advance state/pointer */
|
||||||
default:
|
default:
|
||||||
p++, state++;
|
p++, state++;
|
||||||
} /* switch(state) */
|
} /* switch(state) */
|
||||||
} /* for (... p < pend ...) */
|
} /* for (... p < pend ...) */
|
||||||
} /* for (... offset < length ...) */
|
} /* for (... offset < length ...) */
|
||||||
|
|
@ -765,7 +786,7 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
|
||||||
|
|
||||||
return MSPACK_ERR_OK;
|
return MSPACK_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************************************
|
/***************************************
|
||||||
* CABD_MERGE, CABD_PREPEND, CABD_APPEND
|
* CABD_MERGE, CABD_PREPEND, CABD_APPEND
|
||||||
***************************************
|
***************************************
|
||||||
|
|
@ -775,22 +796,22 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
|
||||||
* merged folder's data parts list.
|
* merged folder's data parts list.
|
||||||
*/
|
*/
|
||||||
static int cabd_prepend(struct mscab_decompressor *base,
|
static int cabd_prepend(struct mscab_decompressor *base,
|
||||||
struct mscabd_cabinet *cab,
|
struct mscabd_cabinet *cab,
|
||||||
struct mscabd_cabinet *prevcab)
|
struct mscabd_cabinet *prevcab)
|
||||||
{
|
{
|
||||||
return cabd_merge(base, prevcab, cab);
|
return cabd_merge(base, prevcab, cab);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cabd_append(struct mscab_decompressor *base,
|
static int cabd_append(struct mscab_decompressor *base,
|
||||||
struct mscabd_cabinet *cab,
|
struct mscabd_cabinet *cab,
|
||||||
struct mscabd_cabinet *nextcab)
|
struct mscabd_cabinet *nextcab)
|
||||||
{
|
{
|
||||||
return cabd_merge(base, cab, nextcab);
|
return cabd_merge(base, cab, nextcab);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cabd_merge(struct mscab_decompressor *base,
|
static int cabd_merge(struct mscab_decompressor *base,
|
||||||
struct mscabd_cabinet *lcab,
|
struct mscabd_cabinet *lcab,
|
||||||
struct mscabd_cabinet *rcab)
|
struct mscabd_cabinet *rcab)
|
||||||
{
|
{
|
||||||
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
|
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
|
||||||
struct mscabd_folder_data *data, *ndata;
|
struct mscabd_folder_data *data, *ndata;
|
||||||
|
|
@ -880,7 +901,7 @@ static int cabd_merge(struct mscab_decompressor *base,
|
||||||
* instead */
|
* instead */
|
||||||
lfol->base.num_blocks += rfol->base.num_blocks - 1;
|
lfol->base.num_blocks += rfol->base.num_blocks - 1;
|
||||||
if ((rfol->merge_next == NULL) ||
|
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;
|
lfol->merge_next = rfol->merge_next;
|
||||||
}
|
}
|
||||||
|
|
@ -903,9 +924,9 @@ static int cabd_merge(struct mscab_decompressor *base,
|
||||||
rfi = fi->next;
|
rfi = fi->next;
|
||||||
/* if file's folder matches the merge folder, unlink and free it */
|
/* if file's folder matches the merge folder, unlink and free it */
|
||||||
if (fi->folder == (struct mscabd_folder *) rfol) {
|
if (fi->folder == (struct mscabd_folder *) rfol) {
|
||||||
if (lfi) lfi->next = rfi; else lcab->files = rfi;
|
if (lfi) lfi->next = rfi; else lcab->files = rfi;
|
||||||
sys->free(fi->filename);
|
sys->free(fi->filename);
|
||||||
sys->free(fi);
|
sys->free(fi);
|
||||||
}
|
}
|
||||||
else lfi = fi;
|
else lfi = fi;
|
||||||
}
|
}
|
||||||
|
|
@ -940,6 +961,12 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
|
||||||
return 0;
|
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)) {
|
if (!(lfi = lfol->merge_next) || !(rfi = rfol->merge_prev)) {
|
||||||
D(("folder merge: one cabinet has no files to merge"))
|
D(("folder merge: one cabinet has no files to merge"))
|
||||||
return 0;
|
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
|
* should be identical in number and order. to verify this, check the
|
||||||
* offset and length of each file. */
|
* offset and length of each file. */
|
||||||
for (l=lfi, r=rfi; l; l=l->next, r=r->next) {
|
for (l=lfi, r=rfi; l; l=l->next, r=r->next) {
|
||||||
if (!r || (l->offset != r->offset) || (l->length != r->length)) {
|
if (!r || (l->offset != r->offset) || (l->length != r->length)) {
|
||||||
matching = 0;
|
matching = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matching) return 1;
|
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. */
|
* the merge with a warning about missing files. */
|
||||||
matching = 0;
|
matching = 0;
|
||||||
for (l = lfi; l; l = l->next) {
|
for (l = lfi; l; l = l->next) {
|
||||||
for (r = rfi; r; r = r->next) {
|
for (r = rfi; r; r = r->next) {
|
||||||
if (l->offset == r->offset && l->length == r->length) break;
|
if (l->offset == r->offset && l->length == r->length) break;
|
||||||
}
|
}
|
||||||
if (r) matching = 1; else sys->message(NULL,
|
if (r) matching = 1; else sys->message(NULL,
|
||||||
"WARNING; merged file %s not listed in both cabinets", l->filename);
|
"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 mscabd_folder_p *fol;
|
||||||
struct mspack_system *sys;
|
struct mspack_system *sys;
|
||||||
struct mspack_file *fh;
|
struct mspack_file *fh;
|
||||||
|
off_t filelen;
|
||||||
|
|
||||||
if (!self) return MSPACK_ERR_ARGS;
|
if (!self) return MSPACK_ERR_ARGS;
|
||||||
if (!file) return self->error = 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;
|
sys = self->system;
|
||||||
fol = (struct mscabd_folder_p *) file->folder;
|
fol = (struct mscabd_folder_p *) file->folder;
|
||||||
|
|
||||||
/* check if file can be extracted */
|
/* if offset is beyond 2GB, nothing can be extracted */
|
||||||
if ((!fol) || (fol->merge_prev) ||
|
if (file->offset > CAB_LENGTHMAX) {
|
||||||
(((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);
|
|
||||||
return self->error = MSPACK_ERR_DATAFORMAT;
|
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 */
|
/* allocate generic decompression state */
|
||||||
if (!self->d) {
|
if (!self->d) {
|
||||||
self->d = (struct mscabd_decompress_state *) sys->alloc(sys, sizeof(struct mscabd_decompress_state));
|
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? */
|
/* 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? */
|
/* do we need to open a new cab file? */
|
||||||
if (!self->d->infh || (fol->data.cab != self->d->incab)) {
|
if (!self->d->infh || (fol->data.cab != self->d->incab)) {
|
||||||
/* close previous file handle if from a different cab */
|
/* close previous file handle if from a different cab */
|
||||||
if (self->d->infh) sys->close(self->d->infh);
|
if (self->d->infh) sys->close(self->d->infh);
|
||||||
self->d->incab = fol->data.cab;
|
self->d->incab = fol->data.cab;
|
||||||
self->d->infh = sys->open(sys, fol->data.cab->base.filename,
|
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;
|
if (!self->d->infh) return self->error = MSPACK_ERR_OPEN;
|
||||||
}
|
}
|
||||||
/* seek to start of data blocks */
|
/* 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->data = &fol->data;
|
||||||
self->d->offset = 0;
|
self->d->offset = 0;
|
||||||
self->d->block = 0;
|
self->d->block = 0;
|
||||||
|
self->d->outlen = 0;
|
||||||
self->d->i_ptr = self->d->i_end = &self->d->input[0];
|
self->d->i_ptr = self->d->i_end = &self->d->input[0];
|
||||||
|
|
||||||
/* read_error lasts for the lifetime of a decompressor */
|
/* 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;
|
self->error = MSPACK_ERR_OK;
|
||||||
|
|
||||||
/* if file has more than 0 bytes */
|
/* if file has more than 0 bytes */
|
||||||
if (file->length) {
|
if (filelen) {
|
||||||
off_t bytes;
|
off_t bytes;
|
||||||
int error;
|
int error;
|
||||||
/* get to correct offset.
|
/* get to correct offset.
|
||||||
|
|
@ -1065,14 +1127,14 @@ static int cabd_extract(struct mscab_decompressor *base,
|
||||||
*/
|
*/
|
||||||
self->d->outfh = NULL;
|
self->d->outfh = NULL;
|
||||||
if ((bytes = file->offset - self->d->offset)) {
|
if ((bytes = file->offset - self->d->offset)) {
|
||||||
error = self->d->decompress(self->d->state, bytes);
|
error = self->d->decompress(self->d->state, bytes);
|
||||||
self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
|
self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if getting to the correct offset was error free, unpack file */
|
/* if getting to the correct offset was error free, unpack file */
|
||||||
if (!self->error) {
|
if (!self->error) {
|
||||||
self->d->outfh = fh;
|
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;
|
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;
|
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;
|
self->d->comp_type = ct;
|
||||||
|
|
||||||
switch (ct & cffoldCOMPTYPE_MASK) {
|
switch (ct & cffoldCOMPTYPE_MASK) {
|
||||||
case cffoldCOMPTYPE_NONE:
|
case cffoldCOMPTYPE_NONE:
|
||||||
self->d->decompress = (int (*)(void *, off_t)) &noned_decompress;
|
self->d->decompress = (int (*)(void *, off_t)) &noned_decompress;
|
||||||
self->d->state = noned_init(&self->d->sys, fh, fh,
|
self->d->state = noned_init(&self->d->sys, fh, fh, self->buf_size);
|
||||||
self->param[MSCABD_PARAM_DECOMPBUF]);
|
|
||||||
break;
|
break;
|
||||||
case cffoldCOMPTYPE_MSZIP:
|
case cffoldCOMPTYPE_MSZIP:
|
||||||
self->d->decompress = (int (*)(void *, off_t)) &mszipd_decompress;
|
self->d->decompress = (int (*)(void *, off_t)) &mszipd_decompress;
|
||||||
self->d->state = mszipd_init(&self->d->sys, fh, fh,
|
self->d->state = mszipd_init(&self->d->sys, fh, fh, self->buf_size,
|
||||||
self->param[MSCABD_PARAM_DECOMPBUF],
|
self->fix_mszip);
|
||||||
self->param[MSCABD_PARAM_FIXMSZIP]);
|
|
||||||
break;
|
break;
|
||||||
case cffoldCOMPTYPE_QUANTUM:
|
case cffoldCOMPTYPE_QUANTUM:
|
||||||
self->d->decompress = (int (*)(void *, off_t)) &qtmd_decompress;
|
self->d->decompress = (int (*)(void *, off_t)) &qtmd_decompress;
|
||||||
self->d->state = qtmd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f,
|
self->d->state = qtmd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f,
|
||||||
self->param[MSCABD_PARAM_DECOMPBUF]);
|
self->buf_size);
|
||||||
break;
|
break;
|
||||||
case cffoldCOMPTYPE_LZX:
|
case cffoldCOMPTYPE_LZX:
|
||||||
self->d->decompress = (int (*)(void *, off_t)) &lzxd_decompress;
|
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->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;
|
break;
|
||||||
default:
|
default:
|
||||||
return self->error = MSPACK_ERR_DATAFORMAT;
|
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) {
|
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) {
|
switch (self->d->comp_type & cffoldCOMPTYPE_MASK) {
|
||||||
case cffoldCOMPTYPE_NONE: noned_free((struct noned_state *) self->d->state); break;
|
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;
|
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file;
|
||||||
unsigned char *buf = (unsigned char *) buffer;
|
unsigned char *buf = (unsigned char *) buffer;
|
||||||
struct mspack_system *sys = self->system;
|
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] &&
|
ignore_cksum = self->salvage ||
|
||||||
((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP);
|
(self->fix_mszip &&
|
||||||
|
((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP));
|
||||||
|
ignore_blocksize = self->salvage;
|
||||||
|
|
||||||
todo = bytes;
|
todo = bytes;
|
||||||
while (todo > 0) {
|
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 */
|
/* check if we're out of input blocks, advance block counter */
|
||||||
if (self->d->block++ >= self->d->folder->base.num_blocks) {
|
if (self->d->block++ >= self->d->folder->base.num_blocks) {
|
||||||
self->read_error = MSPACK_ERR_DATAFORMAT;
|
if (!self->salvage) {
|
||||||
break;
|
self->read_error = MSPACK_ERR_DATAFORMAT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
D(("Ran out of CAB input blocks prematurely"))
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read a block */
|
/* 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;
|
if (self->read_error) return -1;
|
||||||
|
self->d->outlen += outlen;
|
||||||
|
|
||||||
/* special Quantum hack -- trailer byte to allow the decompressor
|
/* special Quantum hack -- trailer byte to allow the decompressor
|
||||||
* to realign itself. CAB Quantum blocks, unlike LZX blocks, can have
|
* to realign itself. CAB Quantum blocks, unlike LZX blocks, can have
|
||||||
* anything from 0 to 4 trailing null bytes. */
|
* anything from 0 to 4 trailing null bytes. */
|
||||||
if ((self->d->comp_type & cffoldCOMPTYPE_MASK)==cffoldCOMPTYPE_QUANTUM) {
|
if ((self->d->comp_type & cffoldCOMPTYPE_MASK)==cffoldCOMPTYPE_QUANTUM) {
|
||||||
*self->d->i_end++ = 0xFF;
|
*self->d->i_end++ = 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* is this the last block? */
|
/* is this the last block? */
|
||||||
if (self->d->block >= self->d->folder->base.num_blocks) {
|
if (self->d->block >= self->d->folder->base.num_blocks) {
|
||||||
/* last block */
|
if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) {
|
||||||
if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) {
|
/* special LZX hack -- on the last block, inform LZX of the
|
||||||
/* special LZX hack -- on the last block, inform LZX of the
|
* size of the output data stream. */
|
||||||
* size of the output data stream. */
|
lzxd_set_output_length((struct lzxd_stream *) self->d->state, self->d->outlen);
|
||||||
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 (avail) */
|
} /* if (avail) */
|
||||||
} /* while (todo > 0) */
|
} /* 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
|
* one cab file, if it does then the fragments will be reassembled
|
||||||
*/
|
*/
|
||||||
static int cabd_sys_read_block(struct mspack_system *sys,
|
static int cabd_sys_read_block(struct mspack_system *sys,
|
||||||
struct mscabd_decompress_state *d,
|
struct mscabd_decompress_state *d,
|
||||||
int *out, int ignore_cksum)
|
int *out, int ignore_cksum,
|
||||||
|
int ignore_blocksize)
|
||||||
{
|
{
|
||||||
unsigned char hdr[cfdata_SIZEOF];
|
unsigned char hdr[cfdata_SIZEOF];
|
||||||
unsigned int cksum;
|
unsigned int cksum;
|
||||||
int len;
|
int len, full_len;
|
||||||
|
|
||||||
/* reset the input block pointer and end of block pointer */
|
/* reset the input block pointer and end of block pointer */
|
||||||
d->i_ptr = d->i_end = &d->input[0];
|
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 */
|
/* skip any reserved block headers */
|
||||||
if (d->data->cab->block_resv &&
|
if (d->data->cab->block_resv &&
|
||||||
sys->seek(d->infh, (off_t) d->data->cab->block_resv,
|
sys->seek(d->infh, (off_t) d->data->cab->block_resv,
|
||||||
MSPACK_SYS_SEEK_CUR))
|
MSPACK_SYS_SEEK_CUR))
|
||||||
{
|
{
|
||||||
return MSPACK_ERR_SEEK;
|
return MSPACK_ERR_SEEK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* blocks must not be over CAB_INPUTMAX in size */
|
/* blocks must not be over CAB_INPUTMAX in size */
|
||||||
len = EndGetI16(&hdr[cfdata_CompressedSize]);
|
len = EndGetI16(&hdr[cfdata_CompressedSize]);
|
||||||
if (((d->i_end - d->i_ptr) + len) > CAB_INPUTMAX) {
|
full_len = (d->i_end - d->i_ptr) + len; /* include cab-spanning blocks */
|
||||||
D(("block size > CAB_INPUTMAX (%ld + %d)", d->i_end - d->i_ptr, len))
|
if (full_len > CAB_INPUTMAX) {
|
||||||
return MSPACK_ERR_DATAFORMAT;
|
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 */
|
/* blocks must not expand to more than CAB_BLOCKMAX */
|
||||||
if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) {
|
if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) {
|
||||||
D(("block size > CAB_BLOCKMAX"))
|
D(("block size > CAB_BLOCKMAX"))
|
||||||
return MSPACK_ERR_DATAFORMAT;
|
if (!ignore_blocksize) return MSPACK_ERR_DATAFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read the block data */
|
/* read the block data */
|
||||||
|
|
@ -1284,8 +1344,8 @@ static int cabd_sys_read_block(struct mspack_system *sys,
|
||||||
if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) {
|
if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) {
|
||||||
unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0);
|
unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0);
|
||||||
if (cabd_checksum(&hdr[4], 4, sum2) != cksum) {
|
if (cabd_checksum(&hdr[4], 4, sum2) != cksum) {
|
||||||
if (!ignore_cksum) return MSPACK_ERR_CHECKSUM;
|
if (!ignore_cksum) return MSPACK_ERR_CHECKSUM;
|
||||||
sys->message(d->infh, "WARNING; bad block checksum found");
|
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 */
|
/* advance to next member in the cabinet set */
|
||||||
if (!(d->data = d->data->next)) {
|
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;
|
return MSPACK_ERR_DATAFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open next cab file */
|
/* open next cab file */
|
||||||
d->incab = d->data->cab;
|
d->incab = d->data->cab;
|
||||||
if (!(d->infh = sys->open(sys, d->incab->base.filename,
|
if (!(d->infh = sys->open(sys, d->incab->base.filename,
|
||||||
MSPACK_SYS_OPEN_READ)))
|
MSPACK_SYS_OPEN_READ)))
|
||||||
{
|
{
|
||||||
return MSPACK_ERR_OPEN;
|
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,
|
static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
|
||||||
unsigned int cksum)
|
unsigned int cksum)
|
||||||
{
|
{
|
||||||
unsigned int len, ul = 0;
|
unsigned int len, ul = 0;
|
||||||
|
|
||||||
|
|
@ -1342,8 +1402,8 @@ static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (bytes & 3) {
|
switch (bytes & 3) {
|
||||||
case 3: ul |= *data++ << 16;
|
case 3: ul |= *data++ << 16; /*@fallthrough@*/
|
||||||
case 2: ul |= *data++ << 8;
|
case 2: ul |= *data++ << 8; /*@fallthrough@*/
|
||||||
case 1: ul |= *data;
|
case 1: ul |= *data;
|
||||||
}
|
}
|
||||||
cksum ^= ul;
|
cksum ^= ul;
|
||||||
|
|
@ -1365,9 +1425,9 @@ struct noned_state {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct noned_state *noned_init(struct mspack_system *sys,
|
static struct noned_state *noned_init(struct mspack_system *sys,
|
||||||
struct mspack_file *in,
|
struct mspack_file *in,
|
||||||
struct mspack_file *out,
|
struct mspack_file *out,
|
||||||
int bufsize)
|
int bufsize)
|
||||||
{
|
{
|
||||||
struct noned_state *state = (struct noned_state *) sys->alloc(sys, sizeof(struct noned_state));
|
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);
|
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) {
|
switch (param) {
|
||||||
case MSCABD_PARAM_SEARCHBUF:
|
case MSCABD_PARAM_SEARCHBUF:
|
||||||
if (value < 4) return MSPACK_ERR_ARGS;
|
if (value < 4) return MSPACK_ERR_ARGS;
|
||||||
self->param[MSCABD_PARAM_SEARCHBUF] = value;
|
self->searchbuf_size = value;
|
||||||
break;
|
break;
|
||||||
case MSCABD_PARAM_FIXMSZIP:
|
case MSCABD_PARAM_FIXMSZIP:
|
||||||
self->param[MSCABD_PARAM_FIXMSZIP] = value;
|
self->fix_mszip = value;
|
||||||
break;
|
break;
|
||||||
case MSCABD_PARAM_DECOMPBUF:
|
case MSCABD_PARAM_DECOMPBUF:
|
||||||
if (value < 4) return MSPACK_ERR_ARGS;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
return MSPACK_ERR_ARGS;
|
return MSPACK_ERR_ARGS;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of libmspack.
|
/* 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
|
* KWAJ is a format very similar to SZDD. KWAJ method 3 (LZH) was
|
||||||
* written by Jeff Johnson.
|
* written by Jeff Johnson.
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include "system-mspack.h"
|
#include "system-mspack.h"
|
||||||
#include "kwaj.h"
|
#include "kwaj.h"
|
||||||
|
#include "mszip.h"
|
||||||
|
|
||||||
/* prototypes */
|
/* prototypes */
|
||||||
static struct mskwajd_header *kwajd_open(
|
static struct mskwajd_header *kwajd_open(
|
||||||
|
|
@ -40,7 +41,7 @@ static void lzh_free(
|
||||||
static int lzh_read_lens(
|
static int lzh_read_lens(
|
||||||
struct kwajd_stream *kwaj,
|
struct kwajd_stream *kwaj,
|
||||||
unsigned int type, unsigned int numsyms,
|
unsigned int type, unsigned int numsyms,
|
||||||
unsigned char *lens, unsigned short *table);
|
unsigned char *lens);
|
||||||
static int lzh_read_input(
|
static int lzh_read_input(
|
||||||
struct kwajd_stream *kwaj);
|
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;
|
struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
|
||||||
if (self) {
|
if (self) {
|
||||||
struct mspack_system *sys = self->system;
|
struct mspack_system *sys = self->system;
|
||||||
sys->free(self);
|
sys->free(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,7 +91,7 @@ void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *base)
|
||||||
* opens a KWAJ file without decompressing, reads header
|
* opens a KWAJ file without decompressing, reads header
|
||||||
*/
|
*/
|
||||||
static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base,
|
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 mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
|
||||||
struct mskwajd_header *hdr;
|
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);
|
fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
|
||||||
hdr = (struct mskwajd_header *) sys->alloc(sys, sizeof(struct mskwajd_header_p));
|
hdr = (struct mskwajd_header *) sys->alloc(sys, sizeof(struct mskwajd_header_p));
|
||||||
if (fh && hdr) {
|
if (fh && hdr) {
|
||||||
((struct mskwajd_header_p *) hdr)->fh = fh;
|
((struct mskwajd_header_p *) hdr)->fh = fh;
|
||||||
self->error = kwajd_read_headers(sys, fh, hdr);
|
self->error = kwajd_read_headers(sys, fh, hdr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!fh) self->error = MSPACK_ERR_OPEN;
|
if (!fh) self->error = MSPACK_ERR_OPEN;
|
||||||
if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
|
if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->error) {
|
if (self->error) {
|
||||||
if (fh) sys->close(fh);
|
if (fh) sys->close(fh);
|
||||||
if (hdr) sys->free(hdr);
|
sys->free(hdr);
|
||||||
hdr = NULL;
|
hdr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hdr;
|
return hdr;
|
||||||
|
|
@ -126,7 +127,7 @@ static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base,
|
||||||
* closes a KWAJ file
|
* closes a KWAJ file
|
||||||
*/
|
*/
|
||||||
static void kwajd_close(struct mskwaj_decompressor *base,
|
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 mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
|
||||||
struct mskwajd_header_p *hdr_p = (struct mskwajd_header_p *) hdr;
|
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
|
* reads the headers of a KWAJ format file
|
||||||
*/
|
*/
|
||||||
static int kwajd_read_headers(struct mspack_system *sys,
|
static int kwajd_read_headers(struct mspack_system *sys,
|
||||||
struct mspack_file *fh,
|
struct mspack_file *fh,
|
||||||
struct mskwajd_header *hdr)
|
struct mskwajd_header *hdr)
|
||||||
{
|
{
|
||||||
unsigned char buf[16];
|
unsigned char buf[16];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* read in the header */
|
/* read in the header */
|
||||||
if (sys->read(fh, &buf[0], kwajh_SIZEOF) != kwajh_SIZEOF) {
|
if (sys->read(fh, &buf[0], kwajh_SIZEOF) != kwajh_SIZEOF) {
|
||||||
return MSPACK_ERR_READ;
|
return MSPACK_ERR_READ;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for "KWAJ" signature */
|
/* check for "KWAJ" signature */
|
||||||
if (((unsigned int) EndGetI32(&buf[kwajh_Signature1]) != 0x4A41574B) ||
|
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 */
|
/* basic header fields */
|
||||||
|
|
@ -179,61 +180,67 @@ static int kwajd_read_headers(struct mspack_system *sys,
|
||||||
|
|
||||||
/* 4 bytes: length of unpacked file */
|
/* 4 bytes: length of unpacked file */
|
||||||
if (hdr->headers & MSKWAJ_HDR_HASLENGTH) {
|
if (hdr->headers & MSKWAJ_HDR_HASLENGTH) {
|
||||||
if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ;
|
if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ;
|
||||||
hdr->length = EndGetI32(&buf[0]);
|
hdr->length = EndGetI32(&buf[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2 bytes: unknown purpose */
|
/* 2 bytes: unknown purpose */
|
||||||
if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN1) {
|
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 */
|
/* 2 bytes: length of section, then [length] bytes: unknown purpose */
|
||||||
if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN2) {
|
if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN2) {
|
||||||
if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
|
if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
|
||||||
i = EndGetI16(&buf[0]);
|
i = EndGetI16(&buf[0]);
|
||||||
if (sys->seek(fh, (off_t)i, MSPACK_SYS_SEEK_CUR)) return MSPACK_ERR_SEEK;
|
if (sys->seek(fh, (off_t)i, MSPACK_SYS_SEEK_CUR)) return MSPACK_ERR_SEEK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* filename and extension */
|
/* filename and extension */
|
||||||
if (hdr->headers & (MSKWAJ_HDR_HASFILENAME | MSKWAJ_HDR_HASFILEEXT)) {
|
if (hdr->headers & (MSKWAJ_HDR_HASFILENAME | MSKWAJ_HDR_HASFILEEXT)) {
|
||||||
off_t pos = sys->tell(fh);
|
int len;
|
||||||
char *fn = (char *) sys->alloc(sys, (size_t) 13);
|
/* 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 */
|
/* copy filename if present */
|
||||||
if (! fn) return MSPACK_ERR_NOMEMORY;
|
if (hdr->headers & MSKWAJ_HDR_HASFILENAME) {
|
||||||
hdr->filename = fn;
|
/* 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 */
|
/* copy extension if present */
|
||||||
if (hdr->headers & MSKWAJ_HDR_HASFILENAME) {
|
if (hdr->headers & MSKWAJ_HDR_HASFILEEXT) {
|
||||||
if (sys->read(fh, &buf[0], 9) != 9) return MSPACK_ERR_READ;
|
*fn++ = '.';
|
||||||
for (i = 0; i < 9; i++, fn++) if (!(*fn = buf[i])) break;
|
/* read and copy up to 4 bytes of a null terminated string */
|
||||||
pos += (i < 9) ? i+1 : 9;
|
if ((len = sys->read(fh, &buf[0], 4)) < 2) return MSPACK_ERR_READ;
|
||||||
if (sys->seek(fh, pos, MSPACK_SYS_SEEK_START))
|
for (i = 0; i < len; i++) if (!(*fn++ = buf[i])) break;
|
||||||
return MSPACK_ERR_SEEK;
|
/* 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 */
|
||||||
/* copy extension if present */
|
if (sys->seek(fh, (off_t)(i + 1 - len), MSPACK_SYS_SEEK_CUR))
|
||||||
if (hdr->headers & MSKWAJ_HDR_HASFILEEXT) {
|
return MSPACK_ERR_SEEK;
|
||||||
*fn++ = '.';
|
fn--; /* remove the null terminator */
|
||||||
if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ;
|
}
|
||||||
for (i = 0; i < 4; i++, fn++) if (!(*fn = buf[i])) break;
|
*fn = '\0';
|
||||||
pos += (i < 4) ? i+1 : 4;
|
|
||||||
if (sys->seek(fh, pos, MSPACK_SYS_SEEK_START))
|
|
||||||
return MSPACK_ERR_SEEK;
|
|
||||||
}
|
|
||||||
*fn = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2 bytes: extra text length then [length] bytes of extra text data */
|
/* 2 bytes: extra text length then [length] bytes of extra text data */
|
||||||
if (hdr->headers & MSKWAJ_HDR_HASEXTRATEXT) {
|
if (hdr->headers & MSKWAJ_HDR_HASEXTRATEXT) {
|
||||||
if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
|
if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
|
||||||
i = EndGetI16(&buf[0]);
|
i = EndGetI16(&buf[0]);
|
||||||
hdr->extra = (char *) sys->alloc(sys, (size_t)i+1);
|
hdr->extra = (char *) sys->alloc(sys, (size_t)i+1);
|
||||||
if (! hdr->extra) return MSPACK_ERR_NOMEMORY;
|
if (! hdr->extra) return MSPACK_ERR_NOMEMORY;
|
||||||
if (sys->read(fh, hdr->extra, i) != i) return MSPACK_ERR_READ;
|
if (sys->read(fh, hdr->extra, i) != i) return MSPACK_ERR_READ;
|
||||||
hdr->extra[i] = '\0';
|
hdr->extra[i] = '\0';
|
||||||
hdr->extra_length = i;
|
hdr->extra_length = i;
|
||||||
}
|
}
|
||||||
return MSPACK_ERR_OK;
|
return MSPACK_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -244,7 +251,7 @@ static int kwajd_read_headers(struct mspack_system *sys,
|
||||||
* decompresses a KWAJ file
|
* decompresses a KWAJ file
|
||||||
*/
|
*/
|
||||||
static int kwajd_extract(struct mskwaj_decompressor *base,
|
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 mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
|
||||||
struct mspack_system *sys;
|
struct mspack_system *sys;
|
||||||
|
|
@ -258,51 +265,56 @@ static int kwajd_extract(struct mskwaj_decompressor *base,
|
||||||
|
|
||||||
/* seek to the compressed data */
|
/* seek to the compressed data */
|
||||||
if (sys->seek(fh, hdr->data_offset, MSPACK_SYS_SEEK_START)) {
|
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 */
|
/* open file for output */
|
||||||
if (!(outfh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
|
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;
|
self->error = MSPACK_ERR_OK;
|
||||||
|
|
||||||
/* decompress based on format */
|
/* decompress based on format */
|
||||||
if (hdr->comp_type == MSKWAJ_COMP_NONE ||
|
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 */
|
/* NONE is a straight copy. XOR is a copy xored with 0xFF */
|
||||||
unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) KWAJ_INPUT_SIZE);
|
unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) KWAJ_INPUT_SIZE);
|
||||||
if (buf) {
|
if (buf) {
|
||||||
int read, i;
|
int read, i;
|
||||||
while ((read = sys->read(fh, buf, KWAJ_INPUT_SIZE)) > 0) {
|
while ((read = sys->read(fh, buf, KWAJ_INPUT_SIZE)) > 0) {
|
||||||
if (hdr->comp_type == MSKWAJ_COMP_XOR) {
|
if (hdr->comp_type == MSKWAJ_COMP_XOR) {
|
||||||
for (i = 0; i < read; i++) buf[i] ^= 0xFF;
|
for (i = 0; i < read; i++) buf[i] ^= 0xFF;
|
||||||
}
|
}
|
||||||
if (sys->write(outfh, buf, read) != read) {
|
if (sys->write(outfh, buf, read) != read) {
|
||||||
self->error = MSPACK_ERR_WRITE;
|
self->error = MSPACK_ERR_WRITE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (read < 0) self->error = MSPACK_ERR_READ;
|
if (read < 0) self->error = MSPACK_ERR_READ;
|
||||||
sys->free(buf);
|
sys->free(buf);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self->error = MSPACK_ERR_NOMEMORY;
|
self->error = MSPACK_ERR_NOMEMORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (hdr->comp_type == MSKWAJ_COMP_SZDD) {
|
else if (hdr->comp_type == MSKWAJ_COMP_SZDD) {
|
||||||
self->error = lzss_decompress(sys, fh, outfh, KWAJ_INPUT_SIZE,
|
self->error = lzss_decompress(sys, fh, outfh, KWAJ_INPUT_SIZE,
|
||||||
LZSS_MODE_EXPAND);
|
LZSS_MODE_EXPAND);
|
||||||
}
|
}
|
||||||
else if (hdr->comp_type == MSKWAJ_COMP_LZH) {
|
else if (hdr->comp_type == MSKWAJ_COMP_LZH) {
|
||||||
struct kwajd_stream *lzh = lzh_init(sys, fh, outfh);
|
struct kwajd_stream *lzh = lzh_init(sys, fh, outfh);
|
||||||
self->error = (lzh) ? lzh_decompress(lzh) : MSPACK_ERR_NOMEMORY;
|
self->error = (lzh) ? lzh_decompress(lzh) : MSPACK_ERR_NOMEMORY;
|
||||||
lzh_free(lzh);
|
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 {
|
else {
|
||||||
self->error = MSPACK_ERR_DATAFORMAT;
|
self->error = MSPACK_ERR_DATAFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* close output file */
|
/* close output file */
|
||||||
|
|
@ -317,7 +329,7 @@ static int kwajd_extract(struct mskwaj_decompressor *base,
|
||||||
* unpacks directly from input to output
|
* unpacks directly from input to output
|
||||||
*/
|
*/
|
||||||
static int kwajd_decompress(struct mskwaj_decompressor *base,
|
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 mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
|
||||||
struct mskwajd_header *hdr;
|
struct mskwajd_header *hdr;
|
||||||
|
|
@ -353,15 +365,15 @@ static int kwajd_error(struct mskwaj_decompressor *base)
|
||||||
#define BITS_VAR lzh
|
#define BITS_VAR lzh
|
||||||
#define BITS_ORDER_MSB
|
#define BITS_ORDER_MSB
|
||||||
#define BITS_NO_READ_INPUT
|
#define BITS_NO_READ_INPUT
|
||||||
#define READ_BYTES do { \
|
#define READ_BYTES do { \
|
||||||
if (i_ptr >= i_end) { \
|
if (i_ptr >= i_end) { \
|
||||||
if ((err = lzh_read_input(lzh))) return err; \
|
if ((err = lzh_read_input(lzh))) return err; \
|
||||||
i_ptr = lzh->i_ptr; \
|
i_ptr = lzh->i_ptr; \
|
||||||
i_end = lzh->i_end; \
|
i_end = lzh->i_end; \
|
||||||
} \
|
} \
|
||||||
INJECT_BITS(*i_ptr++, 8); \
|
INJECT_BITS(*i_ptr++, 8); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#include "readbits.h"
|
#include <readbits.h>
|
||||||
|
|
||||||
/* import huffman-reading macros and code */
|
/* import huffman-reading macros and code */
|
||||||
#define TABLEBITS(tbl) KWAJ_TABLEBITS
|
#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_TABLE(tbl,idx) lzh->tbl##_table[idx]
|
||||||
#define HUFF_LEN(tbl,idx) lzh->tbl##_len[idx]
|
#define HUFF_LEN(tbl,idx) lzh->tbl##_len[idx]
|
||||||
#define HUFF_ERROR return MSPACK_ERR_DATAFORMAT
|
#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
|
/* 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
|
* 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
|
* isn't how the default readbits.h read_input() works (it simply lets
|
||||||
* 2 fake bytes in then stops), so we implement our own.
|
* 2 fake bytes in then stops), so we implement our own.
|
||||||
*/
|
*/
|
||||||
#define READ_BITS_SAFE(val, n) do { \
|
#define READ_BITS_SAFE(val, n) do { \
|
||||||
READ_BITS(val, n); \
|
READ_BITS(val, n); \
|
||||||
if (lzh->input_end && bits_left < lzh->input_end) \
|
if (lzh->input_end && bits_left < lzh->input_end) \
|
||||||
return MSPACK_ERR_OK; \
|
return MSPACK_ERR_OK; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define READ_HUFFSYM_SAFE(tbl, val) do { \
|
#define READ_HUFFSYM_SAFE(tbl, val) do { \
|
||||||
READ_HUFFSYM(tbl, val); \
|
READ_HUFFSYM(tbl, val); \
|
||||||
if (lzh->input_end && bits_left < lzh->input_end) \
|
if (lzh->input_end && bits_left < lzh->input_end) \
|
||||||
return MSPACK_ERR_OK; \
|
return MSPACK_ERR_OK; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define BUILD_TREE(tbl, type) \
|
#define BUILD_TREE(tbl, type) \
|
||||||
STORE_BITS; \
|
STORE_BITS; \
|
||||||
err = lzh_read_lens(lzh, type, MAXSYMBOLS(tbl), \
|
err = lzh_read_lens(lzh, type, MAXSYMBOLS(tbl), &HUFF_LEN(tbl,0)); \
|
||||||
&HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0)); \
|
if (err) return err; \
|
||||||
if (err) return err; \
|
RESTORE_BITS; \
|
||||||
RESTORE_BITS; \
|
if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
|
||||||
if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
|
&HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
|
||||||
&HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
|
return MSPACK_ERR_DATAFORMAT;
|
||||||
return MSPACK_ERR_DATAFORMAT;
|
|
||||||
|
|
||||||
#define WRITE_BYTE do { \
|
#define WRITE_BYTE do { \
|
||||||
if (lzh->sys->write(lzh->output, &lzh->window[pos], 1) != 1) \
|
if (lzh->sys->write(lzh->output, &lzh->window[pos], 1) != 1) \
|
||||||
return MSPACK_ERR_WRITE; \
|
return MSPACK_ERR_WRITE; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static struct kwajd_stream *lzh_init(struct mspack_system *sys,
|
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]);
|
BUILD_TREE(LITERAL, types[4]);
|
||||||
|
|
||||||
while (!lzh->input_end) {
|
while (!lzh->input_end) {
|
||||||
if (lit_run) READ_HUFFSYM_SAFE(MATCHLEN2, len);
|
if (lit_run) READ_HUFFSYM_SAFE(MATCHLEN2, len);
|
||||||
else READ_HUFFSYM_SAFE(MATCHLEN1, len);
|
else READ_HUFFSYM_SAFE(MATCHLEN1, len);
|
||||||
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
len += 2;
|
len += 2;
|
||||||
lit_run = 0; /* not the end of a literal run */
|
lit_run = 0; /* not the end of a literal run */
|
||||||
READ_HUFFSYM_SAFE(OFFSET, j); offset = j << 6;
|
READ_HUFFSYM_SAFE(OFFSET, j); offset = j << 6;
|
||||||
READ_BITS_SAFE(j, 6); offset |= j;
|
READ_BITS_SAFE(j, 6); offset |= j;
|
||||||
|
|
||||||
/* copy match as output and into the ring buffer */
|
/* copy match as output and into the ring buffer */
|
||||||
while (len-- > 0) {
|
while (len-- > 0) {
|
||||||
lzh->window[pos] = lzh->window[(pos+4096-offset) & 4095];
|
lzh->window[pos] = lzh->window[(pos+4096-offset) & 4095];
|
||||||
WRITE_BYTE;
|
WRITE_BYTE;
|
||||||
pos++; pos &= 4095;
|
pos++; pos &= 4095;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
READ_HUFFSYM_SAFE(LITLEN, len); len++;
|
READ_HUFFSYM_SAFE(LITLEN, len); len++;
|
||||||
lit_run = (len == 32) ? 0 : 1; /* end of a literal run? */
|
lit_run = (len == 32) ? 0 : 1; /* end of a literal run? */
|
||||||
while (len-- > 0) {
|
while (len-- > 0) {
|
||||||
READ_HUFFSYM_SAFE(LITERAL, j);
|
READ_HUFFSYM_SAFE(LITERAL, j);
|
||||||
/* copy as output and into the ring buffer */
|
/* copy as output and into the ring buffer */
|
||||||
lzh->window[pos] = j;
|
lzh->window[pos] = j;
|
||||||
WRITE_BYTE;
|
WRITE_BYTE;
|
||||||
pos++; pos &= 4095;
|
pos++; pos &= 4095;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MSPACK_ERR_OK;
|
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,
|
static int lzh_read_lens(struct kwajd_stream *lzh,
|
||||||
unsigned int type, unsigned int numsyms,
|
unsigned int type, unsigned int numsyms,
|
||||||
unsigned char *lens, unsigned short *table)
|
unsigned char *lens)
|
||||||
{
|
{
|
||||||
register unsigned int bit_buffer;
|
register unsigned int bit_buffer;
|
||||||
register int bits_left;
|
register int bits_left;
|
||||||
|
|
@ -499,33 +510,33 @@ static int lzh_read_lens(struct kwajd_stream *lzh,
|
||||||
RESTORE_BITS;
|
RESTORE_BITS;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 0:
|
case 0:
|
||||||
i = numsyms; c = (i==16)?4: (i==32)?5: (i==64)?6: (i==256)?8 :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;
|
for (i = 0; i < numsyms; i++) lens[i] = c;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
READ_BITS_SAFE(c, 4); lens[0] = c;
|
READ_BITS_SAFE(c, 4); lens[0] = c;
|
||||||
for (i = 1; i < numsyms; i++) {
|
for (i = 1; i < numsyms; i++) {
|
||||||
READ_BITS_SAFE(sel, 1); if (sel == 0) lens[i] = c;
|
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(sel, 1); if (sel == 0) lens[i] = ++c;
|
||||||
else { READ_BITS_SAFE(c, 4); lens[i] = c; }}
|
else { READ_BITS_SAFE(c, 4); lens[i] = c; }}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
READ_BITS_SAFE(c, 4); lens[0] = c;
|
READ_BITS_SAFE(c, 4); lens[0] = c;
|
||||||
for (i = 1; i < numsyms; i++) {
|
for (i = 1; i < numsyms; i++) {
|
||||||
READ_BITS_SAFE(sel, 2);
|
READ_BITS_SAFE(sel, 2);
|
||||||
if (sel == 3) READ_BITS_SAFE(c, 4); else c += (char) sel-1;
|
if (sel == 3) READ_BITS_SAFE(c, 4); else c += (char) sel-1;
|
||||||
lens[i] = c;
|
lens[i] = c;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
for (i = 0; i < numsyms; i++) {
|
for (i = 0; i < numsyms; i++) {
|
||||||
READ_BITS_SAFE(c, 4); lens[i] = c;
|
READ_BITS_SAFE(c, 4); lens[i] = c;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
STORE_BITS;
|
STORE_BITS;
|
||||||
return MSPACK_ERR_OK;
|
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) {
|
static int lzh_read_input(struct kwajd_stream *lzh) {
|
||||||
int read;
|
int read;
|
||||||
if (lzh->input_end) {
|
if (lzh->input_end) {
|
||||||
lzh->input_end += 8;
|
lzh->input_end += 8;
|
||||||
lzh->inbuf[0] = 0;
|
lzh->inbuf[0] = 0;
|
||||||
read = 1;
|
read = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
read = lzh->sys->read(lzh->input, &lzh->inbuf[0], KWAJ_INPUT_SIZE);
|
read = lzh->sys->read(lzh->input, &lzh->inbuf[0], KWAJ_INPUT_SIZE);
|
||||||
if (read < 0) return MSPACK_ERR_READ;
|
if (read < 0) return MSPACK_ERR_READ;
|
||||||
if (read == 0) {
|
if (read == 0) {
|
||||||
lzh->input_end = 8;
|
lzh->input_end = 8;
|
||||||
lzh->inbuf[0] = 0;
|
lzh->inbuf[0] = 0;
|
||||||
read = 1;
|
read = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update i_ptr and i_end */
|
/* update i_ptr and i_end */
|
||||||
|
|
|
||||||
|
|
@ -54,10 +54,10 @@ extern "C" {
|
||||||
* @return an error code, or MSPACK_ERR_OK if successful
|
* @return an error code, or MSPACK_ERR_OK if successful
|
||||||
*/
|
*/
|
||||||
extern int lzss_decompress(struct mspack_system *system,
|
extern int lzss_decompress(struct mspack_system *system,
|
||||||
struct mspack_file *input,
|
struct mspack_file *input,
|
||||||
struct mspack_file *output,
|
struct mspack_file *output,
|
||||||
int input_buffer_size,
|
int input_buffer_size,
|
||||||
int mode);
|
int mode);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,31 +14,31 @@
|
||||||
#include "system-mspack.h"
|
#include "system-mspack.h"
|
||||||
#include "lzss.h"
|
#include "lzss.h"
|
||||||
|
|
||||||
#define ENSURE_BYTES do { \
|
#define ENSURE_BYTES do { \
|
||||||
if (i_ptr >= i_end) { \
|
if (i_ptr >= i_end) { \
|
||||||
read = system->read(input, &inbuf[0], \
|
read = system->read(input, &inbuf[0], \
|
||||||
input_buffer_size); \
|
input_buffer_size); \
|
||||||
if (read <= 0) { \
|
if (read <= 0) { \
|
||||||
system->free(window); \
|
system->free(window); \
|
||||||
return (read < 0) ? MSPACK_ERR_READ \
|
return (read < 0) ? MSPACK_ERR_READ \
|
||||||
: MSPACK_ERR_OK; \
|
: MSPACK_ERR_OK; \
|
||||||
} \
|
} \
|
||||||
i_ptr = &inbuf[0]; i_end = &inbuf[read]; \
|
i_ptr = &inbuf[0]; i_end = &inbuf[read]; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define WRITE_BYTE do { \
|
#define WRITE_BYTE do { \
|
||||||
if (system->write(output, &window[pos], 1) != 1) { \
|
if (system->write(output, &window[pos], 1) != 1) { \
|
||||||
system->free(window); \
|
system->free(window); \
|
||||||
return MSPACK_ERR_WRITE; \
|
return MSPACK_ERR_WRITE; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
int lzss_decompress(struct mspack_system *system,
|
int lzss_decompress(struct mspack_system *system,
|
||||||
struct mspack_file *input,
|
struct mspack_file *input,
|
||||||
struct mspack_file *output,
|
struct mspack_file *output,
|
||||||
int input_buffer_size,
|
int input_buffer_size,
|
||||||
int mode)
|
int mode)
|
||||||
{
|
{
|
||||||
unsigned char *window, *inbuf, *i_ptr, *i_end;
|
unsigned char *window, *inbuf, *i_ptr, *i_end;
|
||||||
unsigned int pos, i, c, invert, mpos, len;
|
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 &&
|
if (!system || input_buffer_size < 1 || (mode != LZSS_MODE_EXPAND &&
|
||||||
mode != LZSS_MODE_MSHELP && mode != LZSS_MODE_QBASIC))
|
mode != LZSS_MODE_MSHELP && mode != LZSS_MODE_QBASIC))
|
||||||
{
|
{
|
||||||
return MSPACK_ERR_ARGS;
|
return MSPACK_ERR_ARGS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* allocate memory */
|
/* allocate memory */
|
||||||
|
|
@ -64,27 +64,27 @@ int lzss_decompress(struct mspack_system *system,
|
||||||
|
|
||||||
/* loop forever; exit condition is in ENSURE_BYTES macro */
|
/* loop forever; exit condition is in ENSURE_BYTES macro */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ENSURE_BYTES; c = *i_ptr++ ^ invert;
|
ENSURE_BYTES; c = *i_ptr++ ^ invert;
|
||||||
for (i = 0x01; i & 0xFF; i <<= 1) {
|
for (i = 0x01; i & 0xFF; i <<= 1) {
|
||||||
if (c & i) {
|
if (c & i) {
|
||||||
/* literal */
|
/* literal */
|
||||||
ENSURE_BYTES; window[pos] = *i_ptr++;
|
ENSURE_BYTES; window[pos] = *i_ptr++;
|
||||||
WRITE_BYTE;
|
WRITE_BYTE;
|
||||||
pos++; pos &= LZSS_WINDOW_SIZE - 1;
|
pos++; pos &= LZSS_WINDOW_SIZE - 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* match */
|
/* match */
|
||||||
ENSURE_BYTES; mpos = *i_ptr++;
|
ENSURE_BYTES; mpos = *i_ptr++;
|
||||||
ENSURE_BYTES; mpos |= (*i_ptr & 0xF0) << 4;
|
ENSURE_BYTES; mpos |= (*i_ptr & 0xF0) << 4;
|
||||||
len = (*i_ptr++ & 0x0F) + 3;
|
len = (*i_ptr++ & 0x0F) + 3;
|
||||||
while (len--) {
|
while (len--) {
|
||||||
window[pos] = window[mpos];
|
window[pos] = window[mpos];
|
||||||
WRITE_BYTE;
|
WRITE_BYTE;
|
||||||
pos++; pos &= LZSS_WINDOW_SIZE - 1;
|
pos++; pos &= LZSS_WINDOW_SIZE - 1;
|
||||||
mpos++; mpos &= LZSS_WINDOW_SIZE - 1;
|
mpos++; mpos &= LZSS_WINDOW_SIZE - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* not reached */
|
/* not reached */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of libmspack.
|
/* 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
|
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||||
* by Microsoft Corporation.
|
* by Microsoft Corporation.
|
||||||
|
|
@ -35,7 +35,7 @@ extern "C" {
|
||||||
/* LZX huffman defines: tweak tablebits as desired */
|
/* LZX huffman defines: tweak tablebits as desired */
|
||||||
#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
|
#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
|
||||||
#define LZX_PRETREE_TABLEBITS (6)
|
#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_MAINTREE_TABLEBITS (12)
|
||||||
#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
|
#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
|
||||||
#define LZX_LENGTH_TABLEBITS (12)
|
#define LZX_LENGTH_TABLEBITS (12)
|
||||||
|
|
@ -55,6 +55,8 @@ struct lzxd_stream {
|
||||||
|
|
||||||
unsigned char *window; /* decoding window */
|
unsigned char *window; /* decoding window */
|
||||||
unsigned int window_size; /* window size */
|
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 window_posn; /* decompression offset within window */
|
||||||
unsigned int frame_posn; /* current frame offset within in window */
|
unsigned int frame_posn; /* current frame offset within in window */
|
||||||
unsigned int frame; /* the number of 32kb frames processed */
|
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 intel_started; /* has intel E8 decoding started? */
|
||||||
unsigned char block_type; /* type of the current block */
|
unsigned char block_type; /* type of the current block */
|
||||||
unsigned char header_read; /* have we started decoding at all yet? */
|
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 input_end; /* have we reached the end of input? */
|
||||||
|
unsigned char is_delta; /* does stream follow LZX DELTA spec? */
|
||||||
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
|
@ -87,13 +89,13 @@ struct lzxd_stream {
|
||||||
|
|
||||||
/* huffman decoding tables */
|
/* huffman decoding tables */
|
||||||
unsigned short PRETREE_table [(1 << LZX_PRETREE_TABLEBITS) +
|
unsigned short PRETREE_table [(1 << LZX_PRETREE_TABLEBITS) +
|
||||||
(LZX_PRETREE_MAXSYMBOLS * 2)];
|
(LZX_PRETREE_MAXSYMBOLS * 2)];
|
||||||
unsigned short MAINTREE_table[(1 << LZX_MAINTREE_TABLEBITS) +
|
unsigned short MAINTREE_table[(1 << LZX_MAINTREE_TABLEBITS) +
|
||||||
(LZX_MAINTREE_MAXSYMBOLS * 2)];
|
(LZX_MAINTREE_MAXSYMBOLS * 2)];
|
||||||
unsigned short LENGTH_table [(1 << LZX_LENGTH_TABLEBITS) +
|
unsigned short LENGTH_table [(1 << LZX_LENGTH_TABLEBITS) +
|
||||||
(LZX_LENGTH_MAXSYMBOLS * 2)];
|
(LZX_LENGTH_MAXSYMBOLS * 2)];
|
||||||
unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) +
|
unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) +
|
||||||
(LZX_ALIGNED_MAXSYMBOLS * 2)];
|
(LZX_ALIGNED_MAXSYMBOLS * 2)];
|
||||||
unsigned char LENGTH_empty;
|
unsigned char LENGTH_empty;
|
||||||
|
|
||||||
/* this is used purely for doing the intel E8 transform */
|
/* 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 input an input stream with the LZX data.
|
||||||
* @param output an output stream to write the decoded data to.
|
* @param output an output stream to write the decoded data to.
|
||||||
* @param window_bits the size of the decoding window, which must be
|
* @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
|
* @param reset_interval the interval at which the LZX bitstream is
|
||||||
* reset, in multiples of LZX frames (32678
|
* reset, in multiples of LZX frames (32678
|
||||||
* bytes), e.g. a value of 2 indicates the input
|
* bytes), e.g. a value of 2 indicates the input
|
||||||
* stream resets after every 65536 output bytes.
|
* 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.
|
* resets, such as in CAB LZX streams.
|
||||||
* @param input_buffer_size the number of bytes to use as an input
|
* @param input_buffer_size the number of bytes to use as an input
|
||||||
* bitstream buffer.
|
* bitstream buffer.
|
||||||
|
|
@ -135,26 +139,49 @@ struct lzxd_stream {
|
||||||
* lzxd_set_output_length() once it is
|
* lzxd_set_output_length() once it is
|
||||||
* known. If never set, 4 of the final 6 bytes
|
* known. If never set, 4 of the final 6 bytes
|
||||||
* of the output stream may be incorrect.
|
* 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
|
* @return a pointer to an initialised lzxd_stream structure, or NULL if
|
||||||
* there was not enough memory or parameters to the function were wrong.
|
* there was not enough memory or parameters to the function were wrong.
|
||||||
*/
|
*/
|
||||||
extern struct lzxd_stream *lzxd_init(struct mspack_system *system,
|
extern struct lzxd_stream *lzxd_init(struct mspack_system *system,
|
||||||
struct mspack_file *input,
|
struct mspack_file *input,
|
||||||
struct mspack_file *output,
|
struct mspack_file *output,
|
||||||
int window_bits,
|
int window_bits,
|
||||||
int reset_interval,
|
int reset_interval,
|
||||||
int input_buffer_size,
|
int input_buffer_size,
|
||||||
off_t output_length);
|
off_t output_length,
|
||||||
|
char is_delta);
|
||||||
|
|
||||||
/* see description of output_length in lzxd_init() */
|
/* see description of output_length in lzxd_init() */
|
||||||
extern void lzxd_set_output_length(struct lzxd_stream *lzx,
|
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.
|
* Decompresses entire or partial LZX streams.
|
||||||
*
|
*
|
||||||
* The number of bytes of data that should be decompressed is given as the
|
* 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.
|
* will be kept over for a later invocation.
|
||||||
*
|
*
|
||||||
* The output bytes will be passed to the system->write() function given in
|
* The output bytes will be passed to the system->write() function given in
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of libmspack.
|
/* 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
|
* The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
|
||||||
* by Microsoft Corporation.
|
* by Microsoft Corporation.
|
||||||
|
|
@ -70,6 +70,10 @@
|
||||||
* The maximum window size has increased from 2MB to 32MB. This also
|
* The maximum window size has increased from 2MB to 32MB. This also
|
||||||
* increases the maximum number of position slots, etc.
|
* 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.
|
* The format now allows for "reference data", supplied by the caller.
|
||||||
* If match offsets go further back than the number of bytes
|
* If match offsets go further back than the number of bytes
|
||||||
* decompressed so far, that is them accessing the reference data.
|
* decompressed so far, that is them accessing the reference data.
|
||||||
|
|
@ -79,11 +83,11 @@
|
||||||
#define BITS_TYPE struct lzxd_stream
|
#define BITS_TYPE struct lzxd_stream
|
||||||
#define BITS_VAR lzx
|
#define BITS_VAR lzx
|
||||||
#define BITS_ORDER_MSB
|
#define BITS_ORDER_MSB
|
||||||
#define READ_BYTES do { \
|
#define READ_BYTES do { \
|
||||||
unsigned char b0, b1; \
|
unsigned char b0, b1; \
|
||||||
READ_IF_NEEDED; b0 = *i_ptr++; \
|
READ_IF_NEEDED; b0 = *i_ptr++; \
|
||||||
READ_IF_NEEDED; b1 = *i_ptr++; \
|
READ_IF_NEEDED; b1 = *i_ptr++; \
|
||||||
INJECT_BITS((b1 << 8) | b0, 16); \
|
INJECT_BITS((b1 << 8) | b0, 16); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#include "readbits.h"
|
#include "readbits.h"
|
||||||
|
|
||||||
|
|
@ -96,43 +100,43 @@
|
||||||
#include "readhuff.h"
|
#include "readhuff.h"
|
||||||
|
|
||||||
/* BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */
|
/* BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */
|
||||||
#define BUILD_TABLE(tbl) \
|
#define BUILD_TABLE(tbl) \
|
||||||
if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
|
if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
|
||||||
&HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
|
&HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
|
||||||
{ \
|
{ \
|
||||||
D(("failed to build %s table", #tbl)) \
|
D(("failed to build %s table", #tbl)) \
|
||||||
return lzx->error = MSPACK_ERR_DECRUNCH; \
|
return lzx->error = MSPACK_ERR_DECRUNCH; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BUILD_TABLE_MAYBE_EMPTY(tbl) do { \
|
#define BUILD_TABLE_MAYBE_EMPTY(tbl) do { \
|
||||||
lzx->tbl##_empty = 0; \
|
lzx->tbl##_empty = 0; \
|
||||||
if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
|
if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
|
||||||
&HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
|
&HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
|
||||||
{ \
|
{ \
|
||||||
for (i = 0; i < MAXSYMBOLS(tbl); i++) { \
|
for (i = 0; i < MAXSYMBOLS(tbl); i++) { \
|
||||||
if (HUFF_LEN(tbl, i) > 0) { \
|
if (HUFF_LEN(tbl, i) > 0) { \
|
||||||
D(("failed to build %s table", #tbl)) \
|
D(("failed to build %s table", #tbl)) \
|
||||||
return lzx->error = MSPACK_ERR_DECRUNCH; \
|
return lzx->error = MSPACK_ERR_DECRUNCH; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
/* empty tree - allow it, but don't decode symbols with it */ \
|
/* empty tree - allow it, but don't decode symbols with it */ \
|
||||||
lzx->tbl##_empty = 1; \
|
lzx->tbl##_empty = 1; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols
|
/* 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
|
* first to last in the given table. The code lengths are stored in their
|
||||||
* own special LZX way.
|
* own special LZX way.
|
||||||
*/
|
*/
|
||||||
#define READ_LENGTHS(tbl, first, last) do { \
|
#define READ_LENGTHS(tbl, first, last) do { \
|
||||||
STORE_BITS; \
|
STORE_BITS; \
|
||||||
if (lzxd_read_lens(lzx, &HUFF_LEN(tbl, 0), (first), \
|
if (lzxd_read_lens(lzx, &HUFF_LEN(tbl, 0), (first), \
|
||||||
(unsigned int)(last))) return lzx->error; \
|
(unsigned int)(last))) return lzx->error; \
|
||||||
RESTORE_BITS; \
|
RESTORE_BITS; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens,
|
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 */
|
/* bit buffer and huffman symbol decode variables */
|
||||||
register unsigned int bit_buffer;
|
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
|
* a small 'position slot' number and a small offset from that slot are
|
||||||
* encoded instead of one large offset.
|
* 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
|
* position_base[] is an index to the position slot bases
|
||||||
*
|
*
|
||||||
* extra_bits[] states how many bits of offset-from-base data is needed.
|
* extra_bits[] states how many bits of offset-from-base data is needed.
|
||||||
*
|
*
|
||||||
* They are generated like so:
|
* They are calculated as follows:
|
||||||
* for (i = 0; i < 4; i++) extra_bits[i] = 0;
|
* extra_bits[i] = 0 where i < 4
|
||||||
* for (i = 4, j = 0; i < 36; i+=2) extra_bits[i] = extra_bits[i+1] = j++;
|
* extra_bits[i] = floor(i/2)-1 where i >= 4 && i < 36
|
||||||
* for (i = 36; i < 51; i++) extra_bits[i] = 17;
|
* extra_bits[i] = 17 where i >= 36
|
||||||
* for (i = 0, j = 0; i < 51; j += 1 << extra_bits[i++]) position_base[i] = j;
|
* position_base[0] = 0
|
||||||
|
* position_base[i] = position_base[i-1] + (1 << extra_bits[i-1])
|
||||||
*/
|
*/
|
||||||
static const unsigned int position_base[51] = {
|
static const unsigned int position_slots[11] = {
|
||||||
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256,
|
30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
|
||||||
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 char extra_bits[51] = {
|
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,
|
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,
|
9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16
|
||||||
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
|
};
|
||||||
|
static const unsigned int position_base[290] = {
|
||||||
|
0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512,
|
||||||
|
768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768,
|
||||||
|
49152, 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360,
|
||||||
|
786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
|
||||||
|
1835008, 1966080, 2097152, 2228224, 2359296, 2490368, 2621440, 2752512,
|
||||||
|
2883584, 3014656, 3145728, 3276800, 3407872, 3538944, 3670016, 3801088,
|
||||||
|
3932160, 4063232, 4194304, 4325376, 4456448, 4587520, 4718592, 4849664,
|
||||||
|
4980736, 5111808, 5242880, 5373952, 5505024, 5636096, 5767168, 5898240,
|
||||||
|
6029312, 6160384, 6291456, 6422528, 6553600, 6684672, 6815744, 6946816,
|
||||||
|
7077888, 7208960, 7340032, 7471104, 7602176, 7733248, 7864320, 7995392,
|
||||||
|
8126464, 8257536, 8388608, 8519680, 8650752, 8781824, 8912896, 9043968,
|
||||||
|
9175040, 9306112, 9437184, 9568256, 9699328, 9830400, 9961472, 10092544,
|
||||||
|
10223616, 10354688, 10485760, 10616832, 10747904, 10878976, 11010048,
|
||||||
|
11141120, 11272192, 11403264, 11534336, 11665408, 11796480, 11927552,
|
||||||
|
12058624, 12189696, 12320768, 12451840, 12582912, 12713984, 12845056,
|
||||||
|
12976128, 13107200, 13238272, 13369344, 13500416, 13631488, 13762560,
|
||||||
|
13893632, 14024704, 14155776, 14286848, 14417920, 14548992, 14680064,
|
||||||
|
14811136, 14942208, 15073280, 15204352, 15335424, 15466496, 15597568,
|
||||||
|
15728640, 15859712, 15990784, 16121856, 16252928, 16384000, 16515072,
|
||||||
|
16646144, 16777216, 16908288, 17039360, 17170432, 17301504, 17432576,
|
||||||
|
17563648, 17694720, 17825792, 17956864, 18087936, 18219008, 18350080,
|
||||||
|
18481152, 18612224, 18743296, 18874368, 19005440, 19136512, 19267584,
|
||||||
|
19398656, 19529728, 19660800, 19791872, 19922944, 20054016, 20185088,
|
||||||
|
20316160, 20447232, 20578304, 20709376, 20840448, 20971520, 21102592,
|
||||||
|
21233664, 21364736, 21495808, 21626880, 21757952, 21889024, 22020096,
|
||||||
|
22151168, 22282240, 22413312, 22544384, 22675456, 22806528, 22937600,
|
||||||
|
23068672, 23199744, 23330816, 23461888, 23592960, 23724032, 23855104,
|
||||||
|
23986176, 24117248, 24248320, 24379392, 24510464, 24641536, 24772608,
|
||||||
|
24903680, 25034752, 25165824, 25296896, 25427968, 25559040, 25690112,
|
||||||
|
25821184, 25952256, 26083328, 26214400, 26345472, 26476544, 26607616,
|
||||||
|
26738688, 26869760, 27000832, 27131904, 27262976, 27394048, 27525120,
|
||||||
|
27656192, 27787264, 27918336, 28049408, 28180480, 28311552, 28442624,
|
||||||
|
28573696, 28704768, 28835840, 28966912, 29097984, 29229056, 29360128,
|
||||||
|
29491200, 29622272, 29753344, 29884416, 30015488, 30146560, 30277632,
|
||||||
|
30408704, 30539776, 30670848, 30801920, 30932992, 31064064, 31195136,
|
||||||
|
31326208, 31457280, 31588352, 31719424, 31850496, 31981568, 32112640,
|
||||||
|
32243712, 32374784, 32505856, 32636928, 32768000, 32899072, 33030144,
|
||||||
|
33161216, 33292288, 33423360
|
||||||
};
|
};
|
||||||
|
|
||||||
static void lzxd_reset_state(struct lzxd_stream *lzx) {
|
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 --------*/
|
/*-------- main LZX code --------*/
|
||||||
|
|
||||||
struct lzxd_stream *lzxd_init(struct mspack_system *system,
|
struct lzxd_stream *lzxd_init(struct mspack_system *system,
|
||||||
struct mspack_file *input,
|
struct mspack_file *input,
|
||||||
struct mspack_file *output,
|
struct mspack_file *output,
|
||||||
int window_bits,
|
int window_bits,
|
||||||
int reset_interval,
|
int reset_interval,
|
||||||
int input_buffer_size,
|
int input_buffer_size,
|
||||||
off_t output_length)
|
off_t output_length,
|
||||||
|
char is_delta)
|
||||||
{
|
{
|
||||||
unsigned int window_size = 1 << window_bits;
|
unsigned int window_size = 1 << window_bits;
|
||||||
struct lzxd_stream *lzx;
|
struct lzxd_stream *lzx;
|
||||||
|
|
||||||
if (!system) return NULL;
|
if (!system) return NULL;
|
||||||
|
|
||||||
/* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */
|
/* LZX DELTA window sizes are between 2^17 (128KiB) and 2^25 (32MiB),
|
||||||
if (window_bits < 15 || window_bits > 21) return NULL;
|
* 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;
|
input_buffer_size = (input_buffer_size + 1) & -2;
|
||||||
if (!input_buffer_size) return NULL;
|
if (input_buffer_size < 2) return NULL;
|
||||||
|
|
||||||
/* allocate decompression state */
|
/* allocate decompression state */
|
||||||
if (!(lzx = (struct lzxd_stream *) system->alloc(system, sizeof(struct lzxd_stream)))) {
|
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->inbuf_size = input_buffer_size;
|
||||||
lzx->window_size = 1 << window_bits;
|
lzx->window_size = 1 << window_bits;
|
||||||
|
lzx->ref_data_size = 0;
|
||||||
lzx->window_posn = 0;
|
lzx->window_posn = 0;
|
||||||
lzx->frame_posn = 0;
|
lzx->frame_posn = 0;
|
||||||
lzx->frame = 0;
|
lzx->frame = 0;
|
||||||
|
|
@ -280,11 +342,8 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system,
|
||||||
lzx->intel_curpos = 0;
|
lzx->intel_curpos = 0;
|
||||||
lzx->intel_started = 0;
|
lzx->intel_started = 0;
|
||||||
lzx->error = MSPACK_ERR_OK;
|
lzx->error = MSPACK_ERR_OK;
|
||||||
|
lzx->num_offsets = position_slots[window_bits - 15] << 3;
|
||||||
/* window bits: 15 16 17 18 19 20 21
|
lzx->is_delta = is_delta;
|
||||||
* position slots: 30 32 34 36 38 42 50 */
|
|
||||||
lzx->posn_slots = ((window_bits == 21) ? 50 :
|
|
||||||
((window_bits == 20) ? 42 : (window_bits << 1)));
|
|
||||||
|
|
||||||
lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0];
|
lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0];
|
||||||
lzxd_reset_state(lzx);
|
lzxd_reset_state(lzx);
|
||||||
|
|
@ -292,8 +351,44 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system,
|
||||||
return lzx;
|
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) {
|
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) {
|
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;
|
register unsigned short sym;
|
||||||
|
|
||||||
int match_length, length_footer, extra, verbatim_bits, bytes_todo;
|
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 char *window, *runsrc, *rundest, buf[12];
|
||||||
unsigned int frame_size=0, end_frame, match_offset, window_posn;
|
unsigned int frame_size=0, end_frame, match_offset, window_posn;
|
||||||
unsigned int R0, R1, R2;
|
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?) */
|
/* have we reached the reset interval? (if there is one?) */
|
||||||
if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) {
|
if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) {
|
||||||
if (lzx->block_remaining) {
|
if (lzx->block_remaining) {
|
||||||
D(("%d bytes remaining at reset interval", lzx->block_remaining))
|
/* this is a file format error, we can make a best effort to extract what we can */
|
||||||
return lzx->error = MSPACK_ERR_DECRUNCH;
|
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 */
|
/* 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;
|
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 */
|
/* read header if necessary */
|
||||||
if (!lzx->header_read) {
|
if (!lzx->header_read) {
|
||||||
/* read 1 bit. if bit=0, intel filesize = 0.
|
/* 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) {
|
while (bytes_todo > 0) {
|
||||||
/* initialise new block, if one is needed */
|
/* initialise new block, if one is needed */
|
||||||
if (lzx->block_remaining == 0) {
|
if (lzx->block_remaining == 0) {
|
||||||
/* realign if previous block was an odd-sized UNCOMPRESSED block */
|
/* realign if previous block was an odd-sized UNCOMPRESSED block */
|
||||||
if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) &&
|
if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) &&
|
||||||
(lzx->block_length & 1))
|
(lzx->block_length & 1))
|
||||||
{
|
{
|
||||||
READ_IF_NEEDED;
|
READ_IF_NEEDED;
|
||||||
i_ptr++;
|
i_ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read block type (3 bits) and block length (24 bits) */
|
/* read block type (3 bits) and block length (24 bits) */
|
||||||
READ_BITS(lzx->block_type, 3);
|
READ_BITS(lzx->block_type, 3);
|
||||||
READ_BITS(i, 16); READ_BITS(j, 8);
|
READ_BITS(i, 16); READ_BITS(j, 8);
|
||||||
lzx->block_remaining = lzx->block_length = (i << 8) | j;
|
lzx->block_remaining = lzx->block_length = (i << 8) | j;
|
||||||
/*D(("new block t%d len %u", lzx->block_type, lzx->block_length))*/
|
/*D(("new block t%d len %u", lzx->block_type, lzx->block_length))*/
|
||||||
|
|
||||||
/* read individual block headers */
|
/* read individual block headers */
|
||||||
switch (lzx->block_type) {
|
switch (lzx->block_type) {
|
||||||
case LZX_BLOCKTYPE_ALIGNED:
|
case LZX_BLOCKTYPE_ALIGNED:
|
||||||
/* read lengths of and build aligned huffman decoding tree */
|
/* read lengths of and build aligned huffman decoding tree */
|
||||||
for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; }
|
for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; }
|
||||||
BUILD_TABLE(ALIGNED);
|
BUILD_TABLE(ALIGNED);
|
||||||
/* no break -- rest of aligned header is same as verbatim */
|
/* rest of aligned header is same as verbatim */ /*@fallthrough@*/
|
||||||
case LZX_BLOCKTYPE_VERBATIM:
|
case LZX_BLOCKTYPE_VERBATIM:
|
||||||
/* read lengths of and build main huffman decoding tree */
|
/* read lengths of and build main huffman decoding tree */
|
||||||
READ_LENGTHS(MAINTREE, 0, 256);
|
READ_LENGTHS(MAINTREE, 0, 256);
|
||||||
READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + (lzx->posn_slots << 3));
|
READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx->num_offsets);
|
||||||
BUILD_TABLE(MAINTREE);
|
BUILD_TABLE(MAINTREE);
|
||||||
/* if the literal 0xE8 is anywhere in the block... */
|
/* if the literal 0xE8 is anywhere in the block... */
|
||||||
if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1;
|
if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1;
|
||||||
/* read lengths of and build lengths huffman decoding tree */
|
/* read lengths of and build lengths huffman decoding tree */
|
||||||
READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
|
READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
|
||||||
BUILD_TABLE_MAYBE_EMPTY(LENGTH);
|
BUILD_TABLE_MAYBE_EMPTY(LENGTH);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LZX_BLOCKTYPE_UNCOMPRESSED:
|
case LZX_BLOCKTYPE_UNCOMPRESSED:
|
||||||
/* because we can't assume otherwise */
|
/* because we can't assume otherwise */
|
||||||
lzx->intel_started = 1;
|
lzx->intel_started = 1;
|
||||||
|
|
||||||
/* read 1-16 (not 0-15) bits to align to bytes */
|
/* read 1-16 (not 0-15) bits to align to bytes */
|
||||||
ENSURE_BITS(16);
|
if (bits_left == 0) ENSURE_BITS(16);
|
||||||
if (bits_left > 16) i_ptr -= 2;
|
bits_left = 0; bit_buffer = 0;
|
||||||
bits_left = 0; bit_buffer = 0;
|
|
||||||
|
|
||||||
/* read 12 bytes of stored R0 / R1 / R2 values */
|
/* read 12 bytes of stored R0 / R1 / R2 values */
|
||||||
for (rundest = &buf[0], i = 0; i < 12; i++) {
|
for (rundest = &buf[0], i = 0; i < 12; i++) {
|
||||||
READ_IF_NEEDED;
|
READ_IF_NEEDED;
|
||||||
*rundest++ = *i_ptr++;
|
*rundest++ = *i_ptr++;
|
||||||
}
|
}
|
||||||
R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||||
R1 = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 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);
|
R2 = buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
D(("bad block type"))
|
D(("bad block type"))
|
||||||
return lzx->error = MSPACK_ERR_DECRUNCH;
|
return lzx->error = MSPACK_ERR_DECRUNCH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* decode more of the block:
|
/* 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 */
|
/* decode at least this_run bytes */
|
||||||
switch (lzx->block_type) {
|
switch (lzx->block_type) {
|
||||||
case LZX_BLOCKTYPE_VERBATIM:
|
case LZX_BLOCKTYPE_VERBATIM:
|
||||||
while (this_run > 0) {
|
while (this_run > 0) {
|
||||||
READ_HUFFSYM(MAINTREE, main_element);
|
READ_HUFFSYM(MAINTREE, main_element);
|
||||||
if (main_element < LZX_NUM_CHARS) {
|
if (main_element < LZX_NUM_CHARS) {
|
||||||
/* literal: 0 to LZX_NUM_CHARS-1 */
|
/* literal: 0 to LZX_NUM_CHARS-1 */
|
||||||
window[window_posn++] = main_element;
|
window[window_posn++] = main_element;
|
||||||
this_run--;
|
this_run--;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
|
/* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
|
||||||
main_element -= LZX_NUM_CHARS;
|
main_element -= LZX_NUM_CHARS;
|
||||||
|
|
||||||
/* get match length */
|
/* get match length */
|
||||||
match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
|
match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
|
||||||
if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
|
if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
|
||||||
if (lzx->LENGTH_empty) {
|
if (lzx->LENGTH_empty) {
|
||||||
D(("LENGTH symbol needed but tree is empty"))
|
D(("LENGTH symbol needed but tree is empty"))
|
||||||
return lzx->error = MSPACK_ERR_DECRUNCH;
|
return lzx->error = MSPACK_ERR_DECRUNCH;
|
||||||
}
|
}
|
||||||
READ_HUFFSYM(LENGTH, length_footer);
|
READ_HUFFSYM(LENGTH, length_footer);
|
||||||
match_length += length_footer;
|
match_length += length_footer;
|
||||||
}
|
}
|
||||||
match_length += LZX_MIN_MATCH;
|
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) {
|
/* get match offset */
|
||||||
D(("match ran over window wrap"))
|
switch ((match_offset = (main_element >> 3))) {
|
||||||
return lzx->error = MSPACK_ERR_DECRUNCH;
|
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;
|
||||||
/* copy match */
|
case 3: match_offset = 1; R2=R1; R1=R0; R0 = match_offset; break;
|
||||||
rundest = &window[window_posn];
|
default:
|
||||||
i = match_length;
|
extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
|
||||||
/* does match offset wrap the window? */
|
READ_BITS(verbatim_bits, extra);
|
||||||
if (match_offset > window_posn) {
|
match_offset = position_base[match_offset] - 2 + verbatim_bits;
|
||||||
/* j = length from match offset to end of window */
|
R2 = R1; R1 = R0; R0 = match_offset;
|
||||||
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;
|
/* LZX DELTA uses max match length to signal even longer match */
|
||||||
window_posn += match_length;
|
if (match_length == LZX_MAX_MATCH && lzx->is_delta) {
|
||||||
}
|
int extra_len = 0;
|
||||||
} /* while (this_run > 0) */
|
ENSURE_BITS(3); /* 4 entry huffman tree */
|
||||||
break;
|
if (PEEK_BITS(1) == 0) {
|
||||||
|
REMOVE_BITS(1); /* '0' -> 8 extra length bits */
|
||||||
|
READ_BITS(extra_len, 8);
|
||||||
|
}
|
||||||
|
else if (PEEK_BITS(2) == 2) {
|
||||||
|
REMOVE_BITS(2); /* '10' -> 10 extra length bits + 0x100 */
|
||||||
|
READ_BITS(extra_len, 10);
|
||||||
|
extra_len += 0x100;
|
||||||
|
}
|
||||||
|
else if (PEEK_BITS(3) == 6) {
|
||||||
|
REMOVE_BITS(3); /* '110' -> 12 extra length bits + 0x500 */
|
||||||
|
READ_BITS(extra_len, 12);
|
||||||
|
extra_len += 0x500;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
REMOVE_BITS(3); /* '111' -> 15 extra length bits */
|
||||||
|
READ_BITS(extra_len, 15);
|
||||||
|
}
|
||||||
|
match_length += extra_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((window_posn + match_length) > lzx->window_size) {
|
||||||
|
D(("match ran over window wrap"))
|
||||||
|
return lzx->error = MSPACK_ERR_DECRUNCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy match */
|
||||||
|
rundest = &window[window_posn];
|
||||||
|
i = match_length;
|
||||||
|
/* does match offset wrap the window? */
|
||||||
|
if (match_offset > window_posn) {
|
||||||
|
if (match_offset > lzx->offset &&
|
||||||
|
(match_offset - window_posn) > lzx->ref_data_size)
|
||||||
|
{
|
||||||
|
D(("match offset beyond LZX stream"))
|
||||||
|
return lzx->error = MSPACK_ERR_DECRUNCH;
|
||||||
|
}
|
||||||
|
/* j = length from match offset to end of window */
|
||||||
|
j = match_offset - window_posn;
|
||||||
|
if (j > (int) lzx->window_size) {
|
||||||
|
D(("match offset beyond window boundaries"))
|
||||||
|
return lzx->error = MSPACK_ERR_DECRUNCH;
|
||||||
|
}
|
||||||
|
runsrc = &window[lzx->window_size - j];
|
||||||
|
if (j < i) {
|
||||||
|
/* if match goes over the window edge, do two copy runs */
|
||||||
|
i -= j; while (j-- > 0) *rundest++ = *runsrc++;
|
||||||
|
runsrc = window;
|
||||||
|
}
|
||||||
|
while (i-- > 0) *rundest++ = *runsrc++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
runsrc = rundest - match_offset;
|
||||||
|
while (i-- > 0) *rundest++ = *runsrc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
this_run -= match_length;
|
||||||
|
window_posn += match_length;
|
||||||
|
}
|
||||||
|
} /* while (this_run > 0) */
|
||||||
|
break;
|
||||||
|
|
||||||
case LZX_BLOCKTYPE_ALIGNED:
|
case LZX_BLOCKTYPE_ALIGNED:
|
||||||
while (this_run > 0) {
|
while (this_run > 0) {
|
||||||
READ_HUFFSYM(MAINTREE, main_element);
|
READ_HUFFSYM(MAINTREE, main_element);
|
||||||
if (main_element < LZX_NUM_CHARS) {
|
if (main_element < LZX_NUM_CHARS) {
|
||||||
/* literal: 0 to LZX_NUM_CHARS-1 */
|
/* literal: 0 to LZX_NUM_CHARS-1 */
|
||||||
window[window_posn++] = main_element;
|
window[window_posn++] = main_element;
|
||||||
this_run--;
|
this_run--;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
|
/* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
|
||||||
main_element -= LZX_NUM_CHARS;
|
main_element -= LZX_NUM_CHARS;
|
||||||
|
|
||||||
/* get match length */
|
/* get match length */
|
||||||
match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
|
match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
|
||||||
if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
|
if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
|
||||||
if (lzx->LENGTH_empty) {
|
if (lzx->LENGTH_empty) {
|
||||||
D(("LENGTH symbol needed but tree is empty"))
|
D(("LENGTH symbol needed but tree is empty"))
|
||||||
return lzx->error = MSPACK_ERR_DECRUNCH;
|
return lzx->error = MSPACK_ERR_DECRUNCH;
|
||||||
}
|
}
|
||||||
READ_HUFFSYM(LENGTH, length_footer);
|
READ_HUFFSYM(LENGTH, length_footer);
|
||||||
match_length += length_footer;
|
match_length += length_footer;
|
||||||
}
|
}
|
||||||
match_length += LZX_MIN_MATCH;
|
match_length += LZX_MIN_MATCH;
|
||||||
|
|
||||||
/* get match offset */
|
/* get match offset */
|
||||||
switch ((match_offset = (main_element >> 3))) {
|
switch ((match_offset = (main_element >> 3))) {
|
||||||
case 0: match_offset = R0; break;
|
case 0: match_offset = R0; break;
|
||||||
case 1: match_offset = R1; R1 = R0; R0 = match_offset; break;
|
case 1: match_offset = R1; R1 = R0; R0 = match_offset; break;
|
||||||
case 2: match_offset = R2; R2 = R0; R0 = match_offset; break;
|
case 2: match_offset = R2; R2 = R0; R0 = match_offset; break;
|
||||||
default:
|
default:
|
||||||
extra = extra_bits[match_offset];
|
extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
|
||||||
match_offset = position_base[match_offset] - 2;
|
match_offset = position_base[match_offset] - 2;
|
||||||
if (extra > 3) {
|
if (extra > 3) {
|
||||||
/* verbatim and aligned bits */
|
/* verbatim and aligned bits */
|
||||||
extra -= 3;
|
extra -= 3;
|
||||||
READ_BITS(verbatim_bits, extra);
|
READ_BITS(verbatim_bits, extra);
|
||||||
match_offset += (verbatim_bits << 3);
|
match_offset += (verbatim_bits << 3);
|
||||||
READ_HUFFSYM(ALIGNED, aligned_bits);
|
READ_HUFFSYM(ALIGNED, aligned_bits);
|
||||||
match_offset += aligned_bits;
|
match_offset += aligned_bits;
|
||||||
}
|
}
|
||||||
else if (extra == 3) {
|
else if (extra == 3) {
|
||||||
/* aligned bits only */
|
/* aligned bits only */
|
||||||
READ_HUFFSYM(ALIGNED, aligned_bits);
|
READ_HUFFSYM(ALIGNED, aligned_bits);
|
||||||
match_offset += aligned_bits;
|
match_offset += aligned_bits;
|
||||||
}
|
}
|
||||||
else if (extra > 0) { /* extra==1, extra==2 */
|
else if (extra > 0) { /* extra==1, extra==2 */
|
||||||
/* verbatim bits only */
|
/* verbatim bits only */
|
||||||
READ_BITS(verbatim_bits, extra);
|
READ_BITS(verbatim_bits, extra);
|
||||||
match_offset += verbatim_bits;
|
match_offset += verbatim_bits;
|
||||||
}
|
}
|
||||||
else /* extra == 0 */ {
|
else /* extra == 0 */ {
|
||||||
/* ??? not defined in LZX specification! */
|
/* ??? not defined in LZX specification! */
|
||||||
match_offset = 1;
|
match_offset = 1;
|
||||||
}
|
}
|
||||||
/* update repeated offset LRU queue */
|
/* update repeated offset LRU queue */
|
||||||
R2 = R1; R1 = R0; R0 = match_offset;
|
R2 = R1; R1 = R0; R0 = match_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((window_posn + match_length) > lzx->window_size) {
|
/* LZX DELTA uses max match length to signal even longer match */
|
||||||
D(("match ran over window wrap"))
|
if (match_length == LZX_MAX_MATCH && lzx->is_delta) {
|
||||||
return lzx->error = MSPACK_ERR_DECRUNCH;
|
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 */
|
if ((window_posn + match_length) > lzx->window_size) {
|
||||||
rundest = &window[window_posn];
|
D(("match ran over window wrap"))
|
||||||
i = match_length;
|
return lzx->error = MSPACK_ERR_DECRUNCH;
|
||||||
/* 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;
|
/* copy match */
|
||||||
window_posn += match_length;
|
rundest = &window[window_posn];
|
||||||
}
|
i = match_length;
|
||||||
} /* while (this_run > 0) */
|
/* does match offset wrap the window? */
|
||||||
break;
|
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:
|
case LZX_BLOCKTYPE_UNCOMPRESSED:
|
||||||
/* as this_run is limited not to wrap a frame, this also means it
|
/* 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) */
|
* won't wrap the window (as the window is a multiple of 32k) */
|
||||||
rundest = &window[window_posn];
|
rundest = &window[window_posn];
|
||||||
window_posn += this_run;
|
window_posn += this_run;
|
||||||
while (this_run > 0) {
|
while (this_run > 0) {
|
||||||
if ((i = i_end - i_ptr) == 0) {
|
if ((i = i_end - i_ptr) == 0) {
|
||||||
READ_IF_NEEDED;
|
READ_IF_NEEDED;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (i > this_run) i = this_run;
|
if (i > this_run) i = this_run;
|
||||||
lzx->sys->copy(i_ptr, rundest, (size_t) i);
|
lzx->sys->copy(i_ptr, rundest, (size_t) i);
|
||||||
rundest += i;
|
rundest += i;
|
||||||
i_ptr += i;
|
i_ptr += i;
|
||||||
this_run -= i;
|
this_run -= i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
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? */
|
/* did the final match overrun our desired this_run length? */
|
||||||
if (this_run < 0) {
|
if (this_run < 0) {
|
||||||
if ((unsigned int)(-this_run) > lzx->block_remaining) {
|
if ((unsigned int)(-this_run) > lzx->block_remaining) {
|
||||||
D(("overrun went past end of block by %d (%d remaining)",
|
D(("overrun went past end of block by %d (%d remaining)",
|
||||||
-this_run, lzx->block_remaining ))
|
-this_run, lzx->block_remaining ))
|
||||||
return lzx->error = MSPACK_ERR_DECRUNCH;
|
return lzx->error = MSPACK_ERR_DECRUNCH;
|
||||||
}
|
}
|
||||||
lzx->block_remaining -= -this_run;
|
lzx->block_remaining -= -this_run;
|
||||||
}
|
}
|
||||||
} /* while (bytes_todo > 0) */
|
} /* while (bytes_todo > 0) */
|
||||||
|
|
||||||
/* streams don't extend over frame boundaries */
|
/* streams don't extend over frame boundaries */
|
||||||
if ((window_posn - lzx->frame_posn) != frame_size) {
|
if ((window_posn - lzx->frame_posn) != frame_size) {
|
||||||
D(("decode beyond output frame limits! %d != %d",
|
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;
|
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 */
|
/* check that we've used all of the previous frame first */
|
||||||
if (lzx->o_ptr != lzx->o_end) {
|
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;
|
return lzx->error = MSPACK_ERR_DECRUNCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* does this intel block _really_ need decoding? */
|
/* does this intel block _really_ need decoding? */
|
||||||
if (lzx->intel_started && lzx->intel_filesize &&
|
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 *data = &lzx->e8_buf[0];
|
||||||
unsigned char *dataend = &lzx->e8_buf[frame_size - 10];
|
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);
|
lzx->sys->copy(&lzx->window[lzx->frame_posn], data, frame_size);
|
||||||
|
|
||||||
while (data < dataend) {
|
while (data < dataend) {
|
||||||
if (*data++ != 0xE8) { curpos++; continue; }
|
if (*data++ != 0xE8) { curpos++; continue; }
|
||||||
abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
|
abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
|
||||||
if ((abs_off >= -curpos) && (abs_off < filesize)) {
|
if ((abs_off >= -curpos) && (abs_off < filesize)) {
|
||||||
rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
|
rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
|
||||||
data[0] = (unsigned char) rel_off;
|
data[0] = (unsigned char) rel_off;
|
||||||
data[1] = (unsigned char) (rel_off >> 8);
|
data[1] = (unsigned char) (rel_off >> 8);
|
||||||
data[2] = (unsigned char) (rel_off >> 16);
|
data[2] = (unsigned char) (rel_off >> 16);
|
||||||
data[3] = (unsigned char) (rel_off >> 24);
|
data[3] = (unsigned char) (rel_off >> 24);
|
||||||
}
|
}
|
||||||
data += 4;
|
data += 4;
|
||||||
curpos += 5;
|
curpos += 5;
|
||||||
}
|
}
|
||||||
lzx->intel_curpos += frame_size;
|
lzx->intel_curpos += frame_size;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/* libmspack -- a library for working with Microsoft compression formats.
|
/* 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
|
* 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
|
* 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
|
* - .CAB (MS Cabinet) files, which use deflate, LZX or Quantum compression
|
||||||
* - .CHM (HTML Help) files, which use LZX compression
|
* - .CHM (HTML Help) files, which use LZX compression
|
||||||
* - .LIT (MS EBook) files, which use LZX compression and DES encryption
|
* - .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
|
* To determine the capabilities of the library, and the binary
|
||||||
* compatibility version of any particular compressor or decompressor, use
|
* compatibility version of any particular compressor or decompressor, use
|
||||||
|
|
@ -60,6 +61,7 @@
|
||||||
* - mspack_create_hlp_compressor() creates a mshlp_compressor
|
* - mspack_create_hlp_compressor() creates a mshlp_compressor
|
||||||
* - mspack_create_szdd_compressor() creates a msszdd_compressor
|
* - mspack_create_szdd_compressor() creates a msszdd_compressor
|
||||||
* - mspack_create_kwaj_compressor() creates a mskwaj_compressor
|
* - mspack_create_kwaj_compressor() creates a mskwaj_compressor
|
||||||
|
* - mspack_create_oab_compressor() creates a msoab_compressor
|
||||||
*
|
*
|
||||||
* For decompression:
|
* For decompression:
|
||||||
* - mspack_create_cab_decompressor() creates a mscab_decompressor
|
* - mspack_create_cab_decompressor() creates a mscab_decompressor
|
||||||
|
|
@ -68,6 +70,7 @@
|
||||||
* - mspack_create_hlp_decompressor() creates a mshlp_decompressor
|
* - mspack_create_hlp_decompressor() creates a mshlp_decompressor
|
||||||
* - mspack_create_szdd_decompressor() creates a msszdd_decompressor
|
* - mspack_create_szdd_decompressor() creates a msszdd_decompressor
|
||||||
* - mspack_create_kwaj_decompressor() creates a mskwaj_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
|
* Once finished working with a format, each kind of
|
||||||
* compressor/decompressor has its own specific destructor:
|
* compressor/decompressor has its own specific destructor:
|
||||||
|
|
@ -83,6 +86,8 @@
|
||||||
* - mspack_destroy_szdd_decompressor()
|
* - mspack_destroy_szdd_decompressor()
|
||||||
* - mspack_destroy_kwaj_compressor()
|
* - mspack_destroy_kwaj_compressor()
|
||||||
* - mspack_destroy_kwaj_decompressor()
|
* - mspack_destroy_kwaj_decompressor()
|
||||||
|
* - mspack_destroy_oab_compressor()
|
||||||
|
* - mspack_destroy_oab_decompressor()
|
||||||
*
|
*
|
||||||
* Destroying a compressor or decompressor does not destroy any objects,
|
* Destroying a compressor or decompressor does not destroy any objects,
|
||||||
* structures or handles that have been created using that compressor or
|
* 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_MSSZDDC: the msszdd_compressor interface
|
||||||
* - #MSPACK_VER_MSKWAJD: the mskwaj_decompressor interface
|
* - #MSPACK_VER_MSKWAJD: the mskwaj_decompressor interface
|
||||||
* - #MSPACK_VER_MSKWAJC: the mskwaj_compressor 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:
|
* The result of the function should be interpreted as follows:
|
||||||
* - -1: this interface is completely unknown to the library
|
* - -1: this interface is completely unknown to the library
|
||||||
|
|
@ -249,6 +256,10 @@ extern int mspack_version(int entity);
|
||||||
#define MSPACK_VER_MSKWAJD (12)
|
#define MSPACK_VER_MSKWAJD (12)
|
||||||
/** Pass to mspack_version() to get the mskwaj_compressor version */
|
/** Pass to mspack_version() to get the mskwaj_compressor version */
|
||||||
#define MSPACK_VER_MSKWAJC (13)
|
#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 ------------------------------------------------ */
|
/* --- file I/O abstraction ------------------------------------------------ */
|
||||||
|
|
||||||
|
|
@ -297,8 +308,8 @@ struct mspack_system {
|
||||||
* @see close(), read(), write(), seek(), tell(), message()
|
* @see close(), read(), write(), seek(), tell(), message()
|
||||||
*/
|
*/
|
||||||
struct mspack_file * (*open)(struct mspack_system *self,
|
struct mspack_file * (*open)(struct mspack_system *self,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
int mode);
|
int mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes a previously opened file. If any memory was allocated for this
|
* 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.
|
* @param bytes the number of bytes to read from the file.
|
||||||
* @return the number of bytes successfully read (this can be less than
|
* @return the number of bytes successfully read (this can be less than
|
||||||
* the number requested), zero to mark the end of file, or less
|
* 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()
|
* @see open(), write()
|
||||||
*/
|
*/
|
||||||
int (*read)(struct mspack_file *file,
|
int (*read)(struct mspack_file *file,
|
||||||
void *buffer,
|
void *buffer,
|
||||||
int bytes);
|
int bytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes a given number of bytes to an open file.
|
* Writes a given number of bytes to an open file.
|
||||||
|
|
@ -338,8 +351,8 @@ struct mspack_system {
|
||||||
* @see open(), read()
|
* @see open(), read()
|
||||||
*/
|
*/
|
||||||
int (*write)(struct mspack_file *file,
|
int (*write)(struct mspack_file *file,
|
||||||
void *buffer,
|
void *buffer,
|
||||||
int bytes);
|
int bytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Seeks to a specific file offset within an open file.
|
* Seeks to a specific file offset within an open file.
|
||||||
|
|
@ -365,8 +378,8 @@ struct mspack_system {
|
||||||
* @see open(), tell()
|
* @see open(), tell()
|
||||||
*/
|
*/
|
||||||
int (*seek)(struct mspack_file *file,
|
int (*seek)(struct mspack_file *file,
|
||||||
off_t offset,
|
off_t offset,
|
||||||
int mode);
|
int mode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current file position (in bytes) of the given file.
|
* Returns the current file position (in bytes) of the given file.
|
||||||
|
|
@ -392,8 +405,8 @@ struct mspack_system {
|
||||||
* @see open()
|
* @see open()
|
||||||
*/
|
*/
|
||||||
void (*message)(struct mspack_file *file,
|
void (*message)(struct mspack_file *file,
|
||||||
const char *format,
|
const char *format,
|
||||||
...);
|
...);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates memory.
|
* Allocates memory.
|
||||||
|
|
@ -406,12 +419,12 @@ struct mspack_system {
|
||||||
* @see free()
|
* @see free()
|
||||||
*/
|
*/
|
||||||
void * (*alloc)(struct mspack_system *self,
|
void * (*alloc)(struct mspack_system *self,
|
||||||
size_t bytes);
|
size_t bytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Frees memory.
|
* Frees memory.
|
||||||
*
|
*
|
||||||
* @param ptr the memory to be freed.
|
* @param ptr the memory to be freed. NULL is accepted and ignored.
|
||||||
* @see alloc()
|
* @see alloc()
|
||||||
*/
|
*/
|
||||||
void (*free)(void *ptr);
|
void (*free)(void *ptr);
|
||||||
|
|
@ -429,8 +442,8 @@ struct mspack_system {
|
||||||
* @param bytes the size of the memory region, in bytes
|
* @param bytes the size of the memory region, in bytes
|
||||||
*/
|
*/
|
||||||
void (*copy)(void *src,
|
void (*copy)(void *src,
|
||||||
void *dest,
|
void *dest,
|
||||||
size_t bytes);
|
size_t bytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A null pointer to mark the end of mspack_system. It must equal NULL.
|
* 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);
|
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 --------------------------- */
|
/* --- support for .CAB (MS Cabinet) file format --------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -896,6 +934,13 @@ struct mscabd_file {
|
||||||
#define MSCABD_PARAM_FIXMSZIP (1)
|
#define MSCABD_PARAM_FIXMSZIP (1)
|
||||||
/** mscab_decompressor::set_param() parameter: size of decompression buffer */
|
/** mscab_decompressor::set_param() parameter: size of decompression buffer */
|
||||||
#define MSCABD_PARAM_DECOMPBUF (2)
|
#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 */
|
/** TODO */
|
||||||
struct mscab_compressor {
|
struct mscab_compressor {
|
||||||
|
|
@ -931,7 +976,7 @@ struct mscab_decompressor {
|
||||||
* @see close(), search(), last_error()
|
* @see close(), search(), last_error()
|
||||||
*/
|
*/
|
||||||
struct mscabd_cabinet * (*open) (struct mscab_decompressor *self,
|
struct mscabd_cabinet * (*open) (struct mscab_decompressor *self,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes a previously opened cabinet or cabinet set.
|
* Closes a previously opened cabinet or cabinet set.
|
||||||
|
|
@ -963,7 +1008,7 @@ struct mscab_decompressor {
|
||||||
* @see open(), search(), append(), prepend()
|
* @see open(), search(), append(), prepend()
|
||||||
*/
|
*/
|
||||||
void (*close)(struct mscab_decompressor *self,
|
void (*close)(struct mscab_decompressor *self,
|
||||||
struct mscabd_cabinet *cab);
|
struct mscabd_cabinet *cab);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches a regular file for embedded cabinets.
|
* Searches a regular file for embedded cabinets.
|
||||||
|
|
@ -1000,7 +1045,7 @@ struct mscab_decompressor {
|
||||||
* @see close(), open(), last_error()
|
* @see close(), open(), last_error()
|
||||||
*/
|
*/
|
||||||
struct mscabd_cabinet * (*search) (struct mscab_decompressor *self,
|
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
|
* Appends one mscabd_cabinet to another, forming or extending a cabinet
|
||||||
|
|
@ -1043,8 +1088,8 @@ struct mscab_decompressor {
|
||||||
* @see prepend(), open(), close()
|
* @see prepend(), open(), close()
|
||||||
*/
|
*/
|
||||||
int (*append) (struct mscab_decompressor *self,
|
int (*append) (struct mscab_decompressor *self,
|
||||||
struct mscabd_cabinet *cab,
|
struct mscabd_cabinet *cab,
|
||||||
struct mscabd_cabinet *nextcab);
|
struct mscabd_cabinet *nextcab);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepends one mscabd_cabinet to another, forming or extending a
|
* Prepends one mscabd_cabinet to another, forming or extending a
|
||||||
|
|
@ -1065,8 +1110,8 @@ struct mscab_decompressor {
|
||||||
* @see append(), open(), close()
|
* @see append(), open(), close()
|
||||||
*/
|
*/
|
||||||
int (*prepend) (struct mscab_decompressor *self,
|
int (*prepend) (struct mscab_decompressor *self,
|
||||||
struct mscabd_cabinet *cab,
|
struct mscabd_cabinet *cab,
|
||||||
struct mscabd_cabinet *prevcab);
|
struct mscabd_cabinet *prevcab);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts a file from a cabinet or cabinet set.
|
* 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
|
* @return an error code, or MSPACK_ERR_OK if successful
|
||||||
*/
|
*/
|
||||||
int (*extract)(struct mscab_decompressor *self,
|
int (*extract)(struct mscab_decompressor *self,
|
||||||
struct mscabd_file *file,
|
struct mscabd_file *file,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a CAB decompression engine parameter.
|
* Sets a CAB decompression engine parameter.
|
||||||
|
|
@ -1117,8 +1162,8 @@ struct mscab_decompressor {
|
||||||
* @see search(), extract()
|
* @see search(), extract()
|
||||||
*/
|
*/
|
||||||
int (*set_param)(struct mscab_decompressor *self,
|
int (*set_param)(struct mscab_decompressor *self,
|
||||||
int param,
|
int param,
|
||||||
int value);
|
int value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the error code set by the most recently called method.
|
* Returns the error code set by the most recently called method.
|
||||||
|
|
@ -1403,8 +1448,8 @@ struct mschm_compressor {
|
||||||
* @see use_temporary_file() set_param()
|
* @see use_temporary_file() set_param()
|
||||||
*/
|
*/
|
||||||
int (*generate)(struct mschm_compressor *self,
|
int (*generate)(struct mschm_compressor *self,
|
||||||
struct mschmc_file file_list[],
|
struct mschmc_file file_list[],
|
||||||
const char *output_file);
|
const char *output_file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies whether a temporary file is used during CHM generation.
|
* Specifies whether a temporary file is used during CHM generation.
|
||||||
|
|
@ -1460,8 +1505,8 @@ struct mschm_compressor {
|
||||||
* @see generate()
|
* @see generate()
|
||||||
*/
|
*/
|
||||||
int (*use_temporary_file)(struct mschm_compressor *self,
|
int (*use_temporary_file)(struct mschm_compressor *self,
|
||||||
int use_temp_file,
|
int use_temp_file,
|
||||||
const char *temp_file);
|
const char *temp_file);
|
||||||
/**
|
/**
|
||||||
* Sets a CHM compression engine parameter.
|
* Sets a CHM compression engine parameter.
|
||||||
*
|
*
|
||||||
|
|
@ -1508,8 +1553,8 @@ struct mschm_compressor {
|
||||||
* @see generate()
|
* @see generate()
|
||||||
*/
|
*/
|
||||||
int (*set_param)(struct mschm_compressor *self,
|
int (*set_param)(struct mschm_compressor *self,
|
||||||
int param,
|
int param,
|
||||||
unsigned int value);
|
int value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the error code set by the most recently called method.
|
* Returns the error code set by the most recently called method.
|
||||||
|
|
@ -1551,7 +1596,7 @@ struct mschm_decompressor {
|
||||||
* @see close()
|
* @see close()
|
||||||
*/
|
*/
|
||||||
struct mschmd_header *(*open)(struct mschm_decompressor *self,
|
struct mschmd_header *(*open)(struct mschm_decompressor *self,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes a previously opened CHM helpfile.
|
* Closes a previously opened CHM helpfile.
|
||||||
|
|
@ -1571,7 +1616,7 @@ struct mschm_decompressor {
|
||||||
* @see open(), fast_open()
|
* @see open(), fast_open()
|
||||||
*/
|
*/
|
||||||
void (*close)(struct mschm_decompressor *self,
|
void (*close)(struct mschm_decompressor *self,
|
||||||
struct mschmd_header *chm);
|
struct mschmd_header *chm);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts a file from a CHM helpfile.
|
* Extracts a file from a CHM helpfile.
|
||||||
|
|
@ -1592,8 +1637,8 @@ struct mschm_decompressor {
|
||||||
* @return an error code, or MSPACK_ERR_OK if successful
|
* @return an error code, or MSPACK_ERR_OK if successful
|
||||||
*/
|
*/
|
||||||
int (*extract)(struct mschm_decompressor *self,
|
int (*extract)(struct mschm_decompressor *self,
|
||||||
struct mschmd_file *file,
|
struct mschmd_file *file,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the error code set by the most recently called method.
|
* Returns the error code set by the most recently called method.
|
||||||
|
|
@ -1631,7 +1676,7 @@ struct mschm_decompressor {
|
||||||
* @see open(), close(), fast_find(), extract()
|
* @see open(), close(), fast_find(), extract()
|
||||||
*/
|
*/
|
||||||
struct mschmd_header *(*fast_open)(struct mschm_decompressor *self,
|
struct mschmd_header *(*fast_open)(struct mschm_decompressor *self,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds file details quickly.
|
* Finds file details quickly.
|
||||||
|
|
@ -1672,10 +1717,10 @@ struct mschm_decompressor {
|
||||||
* @see open(), close(), fast_find(), extract()
|
* @see open(), close(), fast_find(), extract()
|
||||||
*/
|
*/
|
||||||
int (*fast_find)(struct mschm_decompressor *self,
|
int (*fast_find)(struct mschm_decompressor *self,
|
||||||
struct mschmd_header *chm,
|
struct mschmd_header *chm,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
struct mschmd_file *f_ptr,
|
struct mschmd_file *f_ptr,
|
||||||
int f_size);
|
int f_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* --- support for .LIT (EBook) file format -------------------------------- */
|
/* --- support for .LIT (EBook) file format -------------------------------- */
|
||||||
|
|
@ -1781,9 +1826,9 @@ struct msszdd_compressor {
|
||||||
* @see set_param()
|
* @see set_param()
|
||||||
*/
|
*/
|
||||||
int (*compress)(struct msszdd_compressor *self,
|
int (*compress)(struct msszdd_compressor *self,
|
||||||
const char *input,
|
const char *input,
|
||||||
const char *output,
|
const char *output,
|
||||||
off_t length);
|
off_t length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an SZDD compression engine parameter.
|
* Sets an SZDD compression engine parameter.
|
||||||
|
|
@ -1807,8 +1852,8 @@ struct msszdd_compressor {
|
||||||
* @see compress()
|
* @see compress()
|
||||||
*/
|
*/
|
||||||
int (*set_param)(struct msszdd_compressor *self,
|
int (*set_param)(struct msszdd_compressor *self,
|
||||||
int param,
|
int param,
|
||||||
unsigned int value);
|
int value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the error code set by the most recently called method.
|
* Returns the error code set by the most recently called method.
|
||||||
|
|
@ -1849,7 +1894,7 @@ struct msszdd_decompressor {
|
||||||
* @see close()
|
* @see close()
|
||||||
*/
|
*/
|
||||||
struct msszddd_header *(*open)(struct msszdd_decompressor *self,
|
struct msszddd_header *(*open)(struct msszdd_decompressor *self,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes a previously opened SZDD file.
|
* Closes a previously opened SZDD file.
|
||||||
|
|
@ -1865,7 +1910,7 @@ struct msszdd_decompressor {
|
||||||
* @see open()
|
* @see open()
|
||||||
*/
|
*/
|
||||||
void (*close)(struct msszdd_decompressor *self,
|
void (*close)(struct msszdd_decompressor *self,
|
||||||
struct msszddd_header *szdd);
|
struct msszddd_header *szdd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the compressed data from a SZDD file.
|
* 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
|
* @return an error code, or MSPACK_ERR_OK if successful
|
||||||
*/
|
*/
|
||||||
int (*extract)(struct msszdd_decompressor *self,
|
int (*extract)(struct msszdd_decompressor *self,
|
||||||
struct msszddd_header *szdd,
|
struct msszddd_header *szdd,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decompresses an SZDD file to an output file in one step.
|
* 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
|
* @return an error code, or MSPACK_ERR_OK if successful
|
||||||
*/
|
*/
|
||||||
int (*decompress)(struct msszdd_decompressor *self,
|
int (*decompress)(struct msszdd_decompressor *self,
|
||||||
const char *input,
|
const char *input,
|
||||||
const char *output);
|
const char *output);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the error code set by the most recently called method.
|
* Returns the error code set by the most recently called method.
|
||||||
|
|
@ -1937,6 +1982,8 @@ struct msszdd_decompressor {
|
||||||
#define MSKWAJ_COMP_SZDD (2)
|
#define MSKWAJ_COMP_SZDD (2)
|
||||||
/** KWAJ compression type: LZ+Huffman compression */
|
/** KWAJ compression type: LZ+Huffman compression */
|
||||||
#define MSKWAJ_COMP_LZH (3)
|
#define MSKWAJ_COMP_LZH (3)
|
||||||
|
/** KWAJ compression type: MSZIP */
|
||||||
|
#define MSKWAJ_COMP_MSZIP (4)
|
||||||
|
|
||||||
/** KWAJ optional header flag: decompressed file length is included */
|
/** KWAJ optional header flag: decompressed file length is included */
|
||||||
#define MSKWAJ_HDR_HASLENGTH (0x01)
|
#define MSKWAJ_HDR_HASLENGTH (0x01)
|
||||||
|
|
@ -2015,9 +2062,9 @@ struct mskwaj_compressor {
|
||||||
* @see set_param()
|
* @see set_param()
|
||||||
*/
|
*/
|
||||||
int (*compress)(struct mskwaj_compressor *self,
|
int (*compress)(struct mskwaj_compressor *self,
|
||||||
const char *input,
|
const char *input,
|
||||||
const char *output,
|
const char *output,
|
||||||
off_t length);
|
off_t length);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an KWAJ compression engine parameter.
|
* Sets an KWAJ compression engine parameter.
|
||||||
|
|
@ -2043,8 +2090,8 @@ struct mskwaj_compressor {
|
||||||
* @see generate()
|
* @see generate()
|
||||||
*/
|
*/
|
||||||
int (*set_param)(struct mskwaj_compressor *self,
|
int (*set_param)(struct mskwaj_compressor *self,
|
||||||
int param,
|
int param,
|
||||||
unsigned int value);
|
int value);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2065,7 +2112,7 @@ struct mskwaj_compressor {
|
||||||
* filename is too long
|
* filename is too long
|
||||||
*/
|
*/
|
||||||
int (*set_filename)(struct mskwaj_compressor *self,
|
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
|
* Sets arbitrary data that will be stored in the header of the
|
||||||
|
|
@ -2085,8 +2132,8 @@ struct mskwaj_compressor {
|
||||||
* is too long
|
* is too long
|
||||||
*/
|
*/
|
||||||
int (*set_extra_data)(struct mskwaj_compressor *self,
|
int (*set_extra_data)(struct mskwaj_compressor *self,
|
||||||
void *data,
|
void *data,
|
||||||
size_t bytes);
|
size_t bytes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the error code set by the most recently called method.
|
* Returns the error code set by the most recently called method.
|
||||||
|
|
@ -2127,7 +2174,7 @@ struct mskwaj_decompressor {
|
||||||
* @see close()
|
* @see close()
|
||||||
*/
|
*/
|
||||||
struct mskwajd_header *(*open)(struct mskwaj_decompressor *self,
|
struct mskwajd_header *(*open)(struct mskwaj_decompressor *self,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes a previously opened KWAJ file.
|
* Closes a previously opened KWAJ file.
|
||||||
|
|
@ -2142,7 +2189,7 @@ struct mskwaj_decompressor {
|
||||||
* @see open()
|
* @see open()
|
||||||
*/
|
*/
|
||||||
void (*close)(struct mskwaj_decompressor *self,
|
void (*close)(struct mskwaj_decompressor *self,
|
||||||
struct mskwajd_header *kwaj);
|
struct mskwajd_header *kwaj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the compressed data from a KWAJ file.
|
* 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
|
* @return an error code, or MSPACK_ERR_OK if successful
|
||||||
*/
|
*/
|
||||||
int (*extract)(struct mskwaj_decompressor *self,
|
int (*extract)(struct mskwaj_decompressor *self,
|
||||||
struct mskwajd_header *kwaj,
|
struct mskwajd_header *kwaj,
|
||||||
const char *filename);
|
const char *filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decompresses an KWAJ file to an output file in one step.
|
* 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
|
* @return an error code, or MSPACK_ERR_OK if successful
|
||||||
*/
|
*/
|
||||||
int (*decompress)(struct mskwaj_decompressor *self,
|
int (*decompress)(struct mskwaj_decompressor *self,
|
||||||
const char *input,
|
const char *input,
|
||||||
const char *output);
|
const char *output);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the error code set by the most recently called method.
|
* 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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -32,14 +32,14 @@ extern "C" {
|
||||||
# define MSZIP_LITERAL_TABLESIZE (MSZIP_LITERAL_MAXSYMBOLS * 4)
|
# define MSZIP_LITERAL_TABLESIZE (MSZIP_LITERAL_MAXSYMBOLS * 4)
|
||||||
#else
|
#else
|
||||||
# define MSZIP_LITERAL_TABLESIZE ((1 << MSZIP_LITERAL_TABLEBITS) + \
|
# define MSZIP_LITERAL_TABLESIZE ((1 << MSZIP_LITERAL_TABLEBITS) + \
|
||||||
(MSZIP_LITERAL_MAXSYMBOLS * 2))
|
(MSZIP_LITERAL_MAXSYMBOLS * 2))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2)
|
#if (1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2)
|
||||||
# define MSZIP_DISTANCE_TABLESIZE (MSZIP_DISTANCE_MAXSYMBOLS * 4)
|
# define MSZIP_DISTANCE_TABLESIZE (MSZIP_DISTANCE_MAXSYMBOLS * 4)
|
||||||
#else
|
#else
|
||||||
# define MSZIP_DISTANCE_TABLESIZE ((1 << MSZIP_DISTANCE_TABLEBITS) + \
|
# define MSZIP_DISTANCE_TABLESIZE ((1 << MSZIP_DISTANCE_TABLEBITS) + \
|
||||||
(MSZIP_DISTANCE_MAXSYMBOLS * 2))
|
(MSZIP_DISTANCE_MAXSYMBOLS * 2))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct mszipd_stream {
|
struct mszipd_stream {
|
||||||
|
|
@ -83,10 +83,10 @@ struct mszipd_stream {
|
||||||
* a partial recovery of erroneous data.
|
* a partial recovery of erroneous data.
|
||||||
*/
|
*/
|
||||||
extern struct mszipd_stream *mszipd_init(struct mspack_system *system,
|
extern struct mszipd_stream *mszipd_init(struct mspack_system *system,
|
||||||
struct mspack_file *input,
|
struct mspack_file *input,
|
||||||
struct mspack_file *output,
|
struct mspack_file *output,
|
||||||
int input_buffer_size,
|
int input_buffer_size,
|
||||||
int repair_mode);
|
int repair_mode);
|
||||||
|
|
||||||
/* decompresses, or decompresses more of, an MS-ZIP stream.
|
/* 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);
|
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
|
/* frees all stream associated with an MS-ZIP data stream
|
||||||
*
|
*
|
||||||
* - calls system->free() using the system pointer given in mszipd_init()
|
* - calls system->free() using the system pointer given in mszipd_init()
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@
|
||||||
#define BITS_VAR zip
|
#define BITS_VAR zip
|
||||||
#define BITS_ORDER_LSB
|
#define BITS_ORDER_LSB
|
||||||
#define BITS_LSB_TABLE
|
#define BITS_LSB_TABLE
|
||||||
#define READ_BYTES do { \
|
#define READ_BYTES do { \
|
||||||
READ_IF_NEEDED; \
|
READ_IF_NEEDED; \
|
||||||
INJECT_BITS(*i_ptr++, 8); \
|
INJECT_BITS(*i_ptr++, 8); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#include "readbits.h"
|
#include "readbits.h"
|
||||||
|
|
||||||
|
|
@ -34,13 +34,13 @@
|
||||||
#define HUFF_ERROR return INF_ERR_HUFFSYM
|
#define HUFF_ERROR return INF_ERR_HUFFSYM
|
||||||
#include "readhuff.h"
|
#include "readhuff.h"
|
||||||
|
|
||||||
#define FLUSH_IF_NEEDED do { \
|
#define FLUSH_IF_NEEDED do { \
|
||||||
if (zip->window_posn == MSZIP_FRAME_SIZE) { \
|
if (zip->window_posn == MSZIP_FRAME_SIZE) { \
|
||||||
if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) { \
|
if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) { \
|
||||||
return INF_ERR_FLUSH; \
|
return INF_ERR_FLUSH; \
|
||||||
} \
|
} \
|
||||||
zip->window_posn = 0; \
|
zip->window_posn = 0; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* match lengths for literal codes 257.. 285 */
|
/* 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 */
|
/* read 4 bytes of data, emptying the bit-buffer if necessary */
|
||||||
for (i = 0; (bits_left >= 8); i++) {
|
for (i = 0; (bits_left >= 8); i++) {
|
||||||
if (i == 4) return INF_ERR_BITBUF;
|
if (i == 4) return INF_ERR_BITBUF;
|
||||||
lens_buf[i] = PEEK_BITS(8);
|
lens_buf[i] = PEEK_BITS(8);
|
||||||
REMOVE_BITS(8);
|
REMOVE_BITS(8);
|
||||||
}
|
}
|
||||||
if (bits_left != 0) return INF_ERR_BITBUF;
|
if (bits_left != 0) return INF_ERR_BITBUF;
|
||||||
while (i < 4) {
|
while (i < 4) {
|
||||||
READ_IF_NEEDED;
|
READ_IF_NEEDED;
|
||||||
lens_buf[i++] = *i_ptr++;
|
lens_buf[i++] = *i_ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get the length and its complement */
|
/* 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 */
|
/* read and copy the uncompressed data into the window */
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
READ_IF_NEEDED;
|
READ_IF_NEEDED;
|
||||||
|
|
||||||
this_run = length;
|
this_run = length;
|
||||||
if (this_run > (unsigned int)(i_end - i_ptr)) this_run = i_end - i_ptr;
|
if (this_run > (unsigned int)(i_end - i_ptr)) this_run = i_end - i_ptr;
|
||||||
if (this_run > (MSZIP_FRAME_SIZE - zip->window_posn))
|
if (this_run > (MSZIP_FRAME_SIZE - zip->window_posn))
|
||||||
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->sys->copy(i_ptr, &zip->window[zip->window_posn], this_run);
|
||||||
zip->window_posn += this_run;
|
zip->window_posn += this_run;
|
||||||
i_ptr += this_run;
|
i_ptr += this_run;
|
||||||
length -= this_run;
|
length -= this_run;
|
||||||
FLUSH_IF_NEEDED;
|
FLUSH_IF_NEEDED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((block_type == 1) || (block_type == 2)) {
|
else if ((block_type == 1) || (block_type == 2)) {
|
||||||
|
|
@ -217,92 +217,92 @@ static int inflate(struct mszipd_stream *zip) {
|
||||||
unsigned int match_posn, code;
|
unsigned int match_posn, code;
|
||||||
|
|
||||||
if (block_type == 1) {
|
if (block_type == 1) {
|
||||||
/* block with fixed Huffman codes */
|
/* block with fixed Huffman codes */
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < 144) zip->LITERAL_len[i++] = 8;
|
while (i < 144) zip->LITERAL_len[i++] = 8;
|
||||||
while (i < 256) zip->LITERAL_len[i++] = 9;
|
while (i < 256) zip->LITERAL_len[i++] = 9;
|
||||||
while (i < 280) zip->LITERAL_len[i++] = 7;
|
while (i < 280) zip->LITERAL_len[i++] = 7;
|
||||||
while (i < 288) zip->LITERAL_len[i++] = 8;
|
while (i < 288) zip->LITERAL_len[i++] = 8;
|
||||||
for (i = 0; i < 32; i++) zip->DISTANCE_len[i] = 5;
|
for (i = 0; i < 32; i++) zip->DISTANCE_len[i] = 5;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* block with dynamic Huffman codes */
|
/* block with dynamic Huffman codes */
|
||||||
STORE_BITS;
|
STORE_BITS;
|
||||||
if ((i = zip_read_lens(zip))) return i;
|
if ((i = zip_read_lens(zip))) return i;
|
||||||
RESTORE_BITS;
|
RESTORE_BITS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now huffman lengths are read for either kind of block,
|
/* now huffman lengths are read for either kind of block,
|
||||||
* create huffman decoding tables */
|
* create huffman decoding tables */
|
||||||
if (make_decode_table(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS,
|
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,
|
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 */
|
/* decode forever until end of block code */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
READ_HUFFSYM(LITERAL, code);
|
READ_HUFFSYM(LITERAL, code);
|
||||||
if (code < 256) {
|
if (code < 256) {
|
||||||
zip->window[zip->window_posn++] = (unsigned char) code;
|
zip->window[zip->window_posn++] = (unsigned char) code;
|
||||||
FLUSH_IF_NEEDED;
|
FLUSH_IF_NEEDED;
|
||||||
}
|
}
|
||||||
else if (code == 256) {
|
else if (code == 256) {
|
||||||
/* END OF BLOCK CODE: loop break point */
|
/* END OF BLOCK CODE: loop break point */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
code -= 257; /* codes 257-285 are matches */
|
code -= 257; /* codes 257-285 are matches */
|
||||||
if (code >= 29) return INF_ERR_LITCODE; /* codes 286-287 are illegal */
|
if (code >= 29) return INF_ERR_LITCODE; /* codes 286-287 are illegal */
|
||||||
READ_BITS_T(length, lit_extrabits[code]);
|
READ_BITS_T(length, lit_extrabits[code]);
|
||||||
length += lit_lengths[code];
|
length += lit_lengths[code];
|
||||||
|
|
||||||
READ_HUFFSYM(DISTANCE, code);
|
READ_HUFFSYM(DISTANCE, code);
|
||||||
if (code > 30) return INF_ERR_DISTCODE;
|
if (code >= 30) return INF_ERR_DISTCODE;
|
||||||
READ_BITS_T(distance, dist_extrabits[code]);
|
READ_BITS_T(distance, dist_extrabits[code]);
|
||||||
distance += dist_offsets[code];
|
distance += dist_offsets[code];
|
||||||
|
|
||||||
/* match position is window position minus distance. If distance
|
/* match position is window position minus distance. If distance
|
||||||
* is more than window position numerically, it must 'wrap
|
* is more than window position numerically, it must 'wrap
|
||||||
* around' the frame size. */
|
* around' the frame size. */
|
||||||
match_posn = ((distance > zip->window_posn) ? MSZIP_FRAME_SIZE : 0)
|
match_posn = ((distance > zip->window_posn) ? MSZIP_FRAME_SIZE : 0)
|
||||||
+ zip->window_posn - distance;
|
+ zip->window_posn - distance;
|
||||||
|
|
||||||
/* copy match */
|
/* copy match */
|
||||||
if (length < 12) {
|
if (length < 12) {
|
||||||
/* short match, use slower loop but no loop setup code */
|
/* short match, use slower loop but no loop setup code */
|
||||||
while (length--) {
|
while (length--) {
|
||||||
zip->window[zip->window_posn++] = zip->window[match_posn++];
|
zip->window[zip->window_posn++] = zip->window[match_posn++];
|
||||||
match_posn &= MSZIP_FRAME_SIZE - 1;
|
match_posn &= MSZIP_FRAME_SIZE - 1;
|
||||||
FLUSH_IF_NEEDED;
|
FLUSH_IF_NEEDED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* longer match, use faster loop but with setup expense */
|
/* longer match, use faster loop but with setup expense */
|
||||||
unsigned char *runsrc, *rundest;
|
unsigned char *runsrc, *rundest;
|
||||||
do {
|
do {
|
||||||
this_run = length;
|
this_run = length;
|
||||||
if ((match_posn + this_run) > MSZIP_FRAME_SIZE)
|
if ((match_posn + this_run) > MSZIP_FRAME_SIZE)
|
||||||
this_run = MSZIP_FRAME_SIZE - match_posn;
|
this_run = MSZIP_FRAME_SIZE - match_posn;
|
||||||
if ((zip->window_posn + this_run) > MSZIP_FRAME_SIZE)
|
if ((zip->window_posn + this_run) > MSZIP_FRAME_SIZE)
|
||||||
this_run = MSZIP_FRAME_SIZE - zip->window_posn;
|
this_run = MSZIP_FRAME_SIZE - zip->window_posn;
|
||||||
|
|
||||||
rundest = &zip->window[zip->window_posn]; zip->window_posn += this_run;
|
rundest = &zip->window[zip->window_posn]; zip->window_posn += this_run;
|
||||||
runsrc = &zip->window[match_posn]; match_posn += this_run;
|
runsrc = &zip->window[match_posn]; match_posn += this_run;
|
||||||
length -= this_run;
|
length -= this_run;
|
||||||
while (this_run--) *rundest++ = *runsrc++;
|
while (this_run--) *rundest++ = *runsrc++;
|
||||||
if (match_posn == MSZIP_FRAME_SIZE) match_posn = 0;
|
if (match_posn == MSZIP_FRAME_SIZE) match_posn = 0;
|
||||||
FLUSH_IF_NEEDED;
|
FLUSH_IF_NEEDED;
|
||||||
} while (length > 0);
|
} while (length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* else (code >= 257) */
|
} /* else (code >= 257) */
|
||||||
|
|
||||||
} /* for(;;) -- break point at 'code == 256' */
|
} /* for(;;) -- break point at 'code == 256' */
|
||||||
}
|
}
|
||||||
|
|
@ -328,7 +328,7 @@ static int inflate(struct mszipd_stream *zip) {
|
||||||
* is flushed, an error is raised.
|
* is flushed, an error is raised.
|
||||||
*/
|
*/
|
||||||
static int mszipd_flush_window(struct mszipd_stream *zip,
|
static int mszipd_flush_window(struct mszipd_stream *zip,
|
||||||
unsigned int data_flushed)
|
unsigned int data_flushed)
|
||||||
{
|
{
|
||||||
zip->bytes_output += data_flushed;
|
zip->bytes_output += data_flushed;
|
||||||
if (zip->bytes_output > MSZIP_FRAME_SIZE) {
|
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 mszipd_stream *mszipd_init(struct mspack_system *system,
|
||||||
struct mspack_file *input,
|
struct mspack_file *input,
|
||||||
struct mspack_file *output,
|
struct mspack_file *output,
|
||||||
int input_buffer_size,
|
int input_buffer_size,
|
||||||
int repair_mode)
|
int repair_mode)
|
||||||
{
|
{
|
||||||
struct mszipd_stream *zip;
|
struct mszipd_stream *zip;
|
||||||
|
|
||||||
if (!system) return NULL;
|
if (!system) return NULL;
|
||||||
|
|
||||||
|
/* round up input buffer size to multiple of two */
|
||||||
input_buffer_size = (input_buffer_size + 1) & -2;
|
input_buffer_size = (input_buffer_size + 1) & -2;
|
||||||
if (!input_buffer_size) return NULL;
|
if (input_buffer_size < 2) return NULL;
|
||||||
|
|
||||||
/* allocate decompression state */
|
/* allocate decompression state */
|
||||||
if (!(zip = (struct mszipd_stream *) system->alloc(system, sizeof(struct mszipd_stream)))) {
|
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))) {
|
if ((error = inflate(zip))) {
|
||||||
D(("inflate error %d", error))
|
D(("inflate error %d", error))
|
||||||
if (zip->repair_mode) {
|
if (zip->repair_mode) {
|
||||||
/* recover partially-inflated buffers */
|
/* recover partially-inflated buffers */
|
||||||
if (zip->bytes_output == 0 && zip->window_posn > 0) {
|
if (zip->bytes_output == 0 && zip->window_posn > 0) {
|
||||||
zip->flush_window(zip, zip->window_posn);
|
zip->flush_window(zip, zip->window_posn);
|
||||||
}
|
}
|
||||||
zip->sys->message(NULL, "MSZIP error, %u bytes of data lost.",
|
zip->sys->message(NULL, "MSZIP error, %u bytes of data lost.",
|
||||||
MSZIP_FRAME_SIZE - zip->bytes_output);
|
MSZIP_FRAME_SIZE - zip->bytes_output);
|
||||||
for (i = zip->bytes_output; i < MSZIP_FRAME_SIZE; i++) {
|
for (i = zip->bytes_output; i < MSZIP_FRAME_SIZE; i++) {
|
||||||
zip->window[i] = '\0';
|
zip->window[i] = '\0';
|
||||||
}
|
}
|
||||||
zip->bytes_output = MSZIP_FRAME_SIZE;
|
zip->bytes_output = MSZIP_FRAME_SIZE;
|
||||||
}
|
}
|
||||||
else {
|
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];
|
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;
|
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) {
|
void mszipd_free(struct mszipd_stream *zip) {
|
||||||
struct mspack_system *sys;
|
struct mspack_system *sys;
|
||||||
if (zip) {
|
if (zip) {
|
||||||
|
|
|
||||||
|
|
@ -90,10 +90,10 @@ struct qtmd_stream {
|
||||||
* - input_buffer_size is the number of bytes to use to store bitstream data.
|
* - input_buffer_size is the number of bytes to use to store bitstream data.
|
||||||
*/
|
*/
|
||||||
extern struct qtmd_stream *qtmd_init(struct mspack_system *system,
|
extern struct qtmd_stream *qtmd_init(struct mspack_system *system,
|
||||||
struct mspack_file *input,
|
struct mspack_file *input,
|
||||||
struct mspack_file *output,
|
struct mspack_file *output,
|
||||||
int window_bits,
|
int window_bits,
|
||||||
int input_buffer_size);
|
int input_buffer_size);
|
||||||
|
|
||||||
/* decompresses, or decompresses more of, a Quantum stream.
|
/* decompresses, or decompresses more of, a Quantum stream.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,11 @@
|
||||||
#define BITS_TYPE struct qtmd_stream
|
#define BITS_TYPE struct qtmd_stream
|
||||||
#define BITS_VAR qtm
|
#define BITS_VAR qtm
|
||||||
#define BITS_ORDER_MSB
|
#define BITS_ORDER_MSB
|
||||||
#define READ_BYTES do { \
|
#define READ_BYTES do { \
|
||||||
unsigned char b0, b1; \
|
unsigned char b0, b1; \
|
||||||
READ_IF_NEEDED; b0 = *i_ptr++; \
|
READ_IF_NEEDED; b0 = *i_ptr++; \
|
||||||
READ_IF_NEEDED; b1 = *i_ptr++; \
|
READ_IF_NEEDED; b1 = *i_ptr++; \
|
||||||
INJECT_BITS((b0 << 8) | b1, 16); \
|
INJECT_BITS((b0 << 8) | b1, 16); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#include "readbits.h"
|
#include "readbits.h"
|
||||||
|
|
||||||
|
|
@ -115,7 +115,7 @@ static const unsigned char length_extra[27] = {
|
||||||
else break; \
|
else break; \
|
||||||
} \
|
} \
|
||||||
L <<= 1; H = (H << 1) | 1; \
|
L <<= 1; H = (H << 1) | 1; \
|
||||||
ENSURE_BITS(1); \
|
ENSURE_BITS(1); \
|
||||||
C = (C << 1) | PEEK_BITS(1); \
|
C = (C << 1) | PEEK_BITS(1); \
|
||||||
REMOVE_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 */
|
/* -1, not -2; the 0 entry saves this */
|
||||||
model->syms[i].cumfreq >>= 1;
|
model->syms[i].cumfreq >>= 1;
|
||||||
if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) {
|
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 */
|
* characteristics */
|
||||||
for (i = 0; i < model->entries - 1; i++) {
|
for (i = 0; i < model->entries - 1; i++) {
|
||||||
for (j = i + 1; j < model->entries; j++) {
|
for (j = i + 1; j < model->entries; j++) {
|
||||||
if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
|
if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
|
||||||
tmp = model->syms[i];
|
tmp = model->syms[i];
|
||||||
model->syms[i] = model->syms[j];
|
model->syms[i] = model->syms[j];
|
||||||
model->syms[j] = tmp;
|
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 */
|
/* Initialises a model to decode symbols from [start] to [start]+[len]-1 */
|
||||||
static void qtmd_init_model(struct qtmd_model *model,
|
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;
|
int i;
|
||||||
|
|
||||||
|
|
@ -184,9 +184,9 @@ static void qtmd_init_model(struct qtmd_model *model,
|
||||||
/*-------- main Quantum code --------*/
|
/*-------- main Quantum code --------*/
|
||||||
|
|
||||||
struct qtmd_stream *qtmd_init(struct mspack_system *system,
|
struct qtmd_stream *qtmd_init(struct mspack_system *system,
|
||||||
struct mspack_file *input,
|
struct mspack_file *input,
|
||||||
struct mspack_file *output,
|
struct mspack_file *output,
|
||||||
int window_bits, int input_buffer_size)
|
int window_bits, int input_buffer_size)
|
||||||
{
|
{
|
||||||
unsigned int window_size = 1 << window_bits;
|
unsigned int window_size = 1 << window_bits;
|
||||||
struct qtmd_stream *qtm;
|
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) */
|
/* Quantum supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */
|
||||||
if (window_bits < 10 || window_bits > 21) return NULL;
|
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;
|
input_buffer_size = (input_buffer_size + 1) & -2;
|
||||||
if (input_buffer_size < 2) return NULL;
|
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) {
|
while (window_posn < frame_end) {
|
||||||
GET_SYMBOL(qtm->model7, selector);
|
GET_SYMBOL(qtm->model7, selector);
|
||||||
if (selector < 4) {
|
if (selector < 4) {
|
||||||
/* literal byte */
|
/* literal byte */
|
||||||
struct qtmd_model *mdl = (selector == 0) ? &qtm->model0 :
|
struct qtmd_model *mdl = (selector == 0) ? &qtm->model0 :
|
||||||
((selector == 1) ? &qtm->model1 :
|
((selector == 1) ? &qtm->model1 :
|
||||||
((selector == 2) ? &qtm->model2 :
|
((selector == 2) ? &qtm->model2 :
|
||||||
&qtm->model3));
|
&qtm->model3));
|
||||||
GET_SYMBOL((*mdl), sym);
|
GET_SYMBOL((*mdl), sym);
|
||||||
window[window_posn++] = sym;
|
window[window_posn++] = sym;
|
||||||
frame_todo--;
|
frame_todo--;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* match repeated string */
|
/* match repeated string */
|
||||||
switch (selector) {
|
switch (selector) {
|
||||||
case 4: /* selector 4 = fixed length match (3 bytes) */
|
case 4: /* selector 4 = fixed length match (3 bytes) */
|
||||||
GET_SYMBOL(qtm->model4, sym);
|
GET_SYMBOL(qtm->model4, sym);
|
||||||
READ_MANY_BITS(extra, extra_bits[sym]);
|
READ_MANY_BITS(extra, extra_bits[sym]);
|
||||||
match_offset = position_base[sym] + extra + 1;
|
match_offset = position_base[sym] + extra + 1;
|
||||||
match_length = 3;
|
match_length = 3;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5: /* selector 5 = fixed length match (4 bytes) */
|
case 5: /* selector 5 = fixed length match (4 bytes) */
|
||||||
GET_SYMBOL(qtm->model5, sym);
|
GET_SYMBOL(qtm->model5, sym);
|
||||||
READ_MANY_BITS(extra, extra_bits[sym]);
|
READ_MANY_BITS(extra, extra_bits[sym]);
|
||||||
match_offset = position_base[sym] + extra + 1;
|
match_offset = position_base[sym] + extra + 1;
|
||||||
match_length = 4;
|
match_length = 4;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6: /* selector 6 = variable length match */
|
case 6: /* selector 6 = variable length match */
|
||||||
GET_SYMBOL(qtm->model6len, sym);
|
GET_SYMBOL(qtm->model6len, sym);
|
||||||
READ_MANY_BITS(extra, length_extra[sym]);
|
READ_MANY_BITS(extra, length_extra[sym]);
|
||||||
match_length = length_base[sym] + extra + 5;
|
match_length = length_base[sym] + extra + 5;
|
||||||
|
|
||||||
GET_SYMBOL(qtm->model6, sym);
|
GET_SYMBOL(qtm->model6, sym);
|
||||||
READ_MANY_BITS(extra, extra_bits[sym]);
|
READ_MANY_BITS(extra, extra_bits[sym]);
|
||||||
match_offset = position_base[sym] + extra + 1;
|
match_offset = position_base[sym] + extra + 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* should be impossible, model7 can only return 0-6 */
|
/* should be impossible, model7 can only return 0-6 */
|
||||||
D(("got %d from selector", selector))
|
D(("got %d from selector", selector))
|
||||||
return qtm->error = MSPACK_ERR_DECRUNCH;
|
return qtm->error = MSPACK_ERR_DECRUNCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
rundest = &window[window_posn];
|
rundest = &window[window_posn];
|
||||||
frame_todo -= match_length;
|
frame_todo -= match_length;
|
||||||
|
|
||||||
/* does match destination wrap the window? This situation is possible
|
/* does match destination wrap the window? This situation is possible
|
||||||
* where the window size is less than the 32k frame size, but matches
|
* where the window size is less than the 32k frame size, but matches
|
||||||
* must not go beyond a frame boundary */
|
* must not go beyond a frame boundary */
|
||||||
if ((window_posn + match_length) > qtm->window_size) {
|
if ((window_posn + match_length) > qtm->window_size) {
|
||||||
/* copy first part of match, before window end */
|
/* copy first part of match, before window end */
|
||||||
i = qtm->window_size - window_posn;
|
i = qtm->window_size - window_posn;
|
||||||
j = window_posn - match_offset;
|
j = window_posn - match_offset;
|
||||||
while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
|
while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
|
||||||
|
|
||||||
/* flush currently stored data */
|
/* flush currently stored data */
|
||||||
i = (&window[qtm->window_size] - qtm->o_ptr);
|
i = (&window[qtm->window_size] - qtm->o_ptr);
|
||||||
|
|
||||||
/* this should not happen, but if it does then this code
|
/* this should not happen, but if it does then this code
|
||||||
* can't handle the situation (can't flush up to the end of
|
* 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
|
* the window, but can't break out either because we haven't
|
||||||
* finished writing the match). bail out in this case */
|
* finished writing the match). bail out in this case */
|
||||||
if (i > out_bytes) {
|
if (i > out_bytes) {
|
||||||
D(("during window-wrap match; %d bytes to flush but only need %d",
|
D(("during window-wrap match; %d bytes to flush but only need %d",
|
||||||
i, (int) out_bytes))
|
i, (int) out_bytes))
|
||||||
return qtm->error = MSPACK_ERR_DECRUNCH;
|
return qtm->error = MSPACK_ERR_DECRUNCH;
|
||||||
}
|
}
|
||||||
if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
|
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;
|
out_bytes -= i;
|
||||||
qtm->o_ptr = &window[0];
|
qtm->o_ptr = &window[0];
|
||||||
qtm->o_end = &window[0];
|
qtm->o_end = &window[0];
|
||||||
|
|
||||||
/* copy second part of match, after window wrap */
|
/* copy second part of match, after window wrap */
|
||||||
rundest = &window[0];
|
rundest = &window[0];
|
||||||
i = match_length - (qtm->window_size - window_posn);
|
i = match_length - (qtm->window_size - window_posn);
|
||||||
while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
|
while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
|
||||||
window_posn = window_posn + match_length - qtm->window_size;
|
window_posn = window_posn + match_length - qtm->window_size;
|
||||||
|
|
||||||
break; /* because "window_posn < frame_end" has now failed */
|
break; /* because "window_posn < frame_end" has now failed */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* normal match - output won't wrap window or frame end */
|
/* normal match - output won't wrap window or frame end */
|
||||||
i = match_length;
|
i = match_length;
|
||||||
|
|
||||||
/* does match _offset_ wrap the window? */
|
/* does match _offset_ wrap the window? */
|
||||||
if (match_offset > window_posn) {
|
if (match_offset > window_posn) {
|
||||||
/* j = length from match offset to end of window */
|
/* j = length from match offset to end of window */
|
||||||
j = match_offset - window_posn;
|
j = match_offset - window_posn;
|
||||||
if (j > (int) qtm->window_size) {
|
if (j > (int) qtm->window_size) {
|
||||||
D(("match offset beyond window boundaries"))
|
D(("match offset beyond window boundaries"))
|
||||||
return qtm->error = MSPACK_ERR_DECRUNCH;
|
return qtm->error = MSPACK_ERR_DECRUNCH;
|
||||||
}
|
}
|
||||||
runsrc = &window[qtm->window_size - j];
|
runsrc = &window[qtm->window_size - j];
|
||||||
if (j < i) {
|
if (j < i) {
|
||||||
/* if match goes over the window edge, do two copy runs */
|
/* if match goes over the window edge, do two copy runs */
|
||||||
i -= j; while (j-- > 0) *rundest++ = *runsrc++;
|
i -= j; while (j-- > 0) *rundest++ = *runsrc++;
|
||||||
runsrc = window;
|
runsrc = window;
|
||||||
}
|
}
|
||||||
while (i-- > 0) *rundest++ = *runsrc++;
|
while (i-- > 0) *rundest++ = *runsrc++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
runsrc = rundest - match_offset;
|
runsrc = rundest - match_offset;
|
||||||
while (i-- > 0) *rundest++ = *runsrc++;
|
while (i-- > 0) *rundest++ = *runsrc++;
|
||||||
}
|
}
|
||||||
window_posn += match_length;
|
window_posn += match_length;
|
||||||
}
|
}
|
||||||
} /* if (window_posn+match_length > frame_end) */
|
} /* if (window_posn+match_length > frame_end) */
|
||||||
} /* while (window_posn < 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 */
|
/* break out if we have more than enough to finish this request */
|
||||||
if (i >= out_bytes) break;
|
if (i >= out_bytes) break;
|
||||||
if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
|
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;
|
out_bytes -= i;
|
||||||
qtm->o_ptr = &window[0];
|
qtm->o_ptr = &window[0];
|
||||||
|
|
|
||||||
|
|
@ -100,48 +100,48 @@
|
||||||
#endif
|
#endif
|
||||||
#define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT)
|
#define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT)
|
||||||
|
|
||||||
#define INIT_BITS do { \
|
#define INIT_BITS do { \
|
||||||
BITS_VAR->i_ptr = &BITS_VAR->inbuf[0]; \
|
BITS_VAR->i_ptr = &BITS_VAR->inbuf[0]; \
|
||||||
BITS_VAR->i_end = &BITS_VAR->inbuf[0]; \
|
BITS_VAR->i_end = &BITS_VAR->inbuf[0]; \
|
||||||
BITS_VAR->bit_buffer = 0; \
|
BITS_VAR->bit_buffer = 0; \
|
||||||
BITS_VAR->bits_left = 0; \
|
BITS_VAR->bits_left = 0; \
|
||||||
BITS_VAR->input_end = 0; \
|
BITS_VAR->input_end = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define STORE_BITS do { \
|
#define STORE_BITS do { \
|
||||||
BITS_VAR->i_ptr = i_ptr; \
|
BITS_VAR->i_ptr = i_ptr; \
|
||||||
BITS_VAR->i_end = i_end; \
|
BITS_VAR->i_end = i_end; \
|
||||||
BITS_VAR->bit_buffer = bit_buffer; \
|
BITS_VAR->bit_buffer = bit_buffer; \
|
||||||
BITS_VAR->bits_left = bits_left; \
|
BITS_VAR->bits_left = bits_left; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define RESTORE_BITS do { \
|
#define RESTORE_BITS do { \
|
||||||
i_ptr = BITS_VAR->i_ptr; \
|
i_ptr = BITS_VAR->i_ptr; \
|
||||||
i_end = BITS_VAR->i_end; \
|
i_end = BITS_VAR->i_end; \
|
||||||
bit_buffer = BITS_VAR->bit_buffer; \
|
bit_buffer = BITS_VAR->bit_buffer; \
|
||||||
bits_left = BITS_VAR->bits_left; \
|
bits_left = BITS_VAR->bits_left; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ENSURE_BITS(nbits) do { \
|
#define ENSURE_BITS(nbits) do { \
|
||||||
while (bits_left < (nbits)) READ_BYTES; \
|
while (bits_left < (nbits)) READ_BYTES; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define READ_BITS(val, nbits) do { \
|
#define READ_BITS(val, nbits) do { \
|
||||||
ENSURE_BITS(nbits); \
|
ENSURE_BITS(nbits); \
|
||||||
(val) = PEEK_BITS(nbits); \
|
(val) = PEEK_BITS(nbits); \
|
||||||
REMOVE_BITS(nbits); \
|
REMOVE_BITS(nbits); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define READ_MANY_BITS(val, bits) do { \
|
#define READ_MANY_BITS(val, bits) do { \
|
||||||
unsigned char needed = (bits), bitrun; \
|
unsigned char needed = (bits), bitrun; \
|
||||||
(val) = 0; \
|
(val) = 0; \
|
||||||
while (needed > 0) { \
|
while (needed > 0) { \
|
||||||
if (bits_left <= (BITBUF_WIDTH - 16)) READ_BYTES; \
|
if (bits_left <= (BITBUF_WIDTH - 16)) READ_BYTES; \
|
||||||
bitrun = (bits_left < needed) ? bits_left : needed; \
|
bitrun = (bits_left < needed) ? bits_left : needed; \
|
||||||
(val) = ((val) << bitrun) | PEEK_BITS(bitrun); \
|
(val) = ((val) << bitrun) | PEEK_BITS(bitrun); \
|
||||||
REMOVE_BITS(bitrun); \
|
REMOVE_BITS(bitrun); \
|
||||||
needed -= bitrun; \
|
needed -= bitrun; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#ifdef BITS_ORDER_MSB
|
#ifdef BITS_ORDER_MSB
|
||||||
|
|
@ -163,21 +163,21 @@ static const unsigned short lsb_bit_mask[17] = {
|
||||||
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
|
0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
|
||||||
};
|
};
|
||||||
# define PEEK_BITS_T(nbits) (bit_buffer & lsb_bit_mask[(nbits)])
|
# define PEEK_BITS_T(nbits) (bit_buffer & lsb_bit_mask[(nbits)])
|
||||||
# define READ_BITS_T(val, nbits) do { \
|
# define READ_BITS_T(val, nbits) do { \
|
||||||
ENSURE_BITS(nbits); \
|
ENSURE_BITS(nbits); \
|
||||||
(val) = PEEK_BITS_T(nbits); \
|
(val) = PEEK_BITS_T(nbits); \
|
||||||
REMOVE_BITS(nbits); \
|
REMOVE_BITS(nbits); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef BITS_NO_READ_INPUT
|
#ifndef BITS_NO_READ_INPUT
|
||||||
# define READ_IF_NEEDED do { \
|
# define READ_IF_NEEDED do { \
|
||||||
if (i_ptr >= i_end) { \
|
if (i_ptr >= i_end) { \
|
||||||
if (read_input(BITS_VAR)) \
|
if (read_input(BITS_VAR)) \
|
||||||
return BITS_VAR->error; \
|
return BITS_VAR->error; \
|
||||||
i_ptr = BITS_VAR->i_ptr; \
|
i_ptr = BITS_VAR->i_ptr; \
|
||||||
i_end = BITS_VAR->i_end; \
|
i_end = BITS_VAR->i_end; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static int read_input(BITS_TYPE *p) {
|
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,
|
/* we might overrun the input stream by asking for bits we don't use,
|
||||||
* so fake 2 more bytes at the end of input */
|
* so fake 2 more bytes at the end of input */
|
||||||
if (read == 0) {
|
if (read == 0) {
|
||||||
if (p->input_end) {
|
if (p->input_end) {
|
||||||
D(("out of input bytes"))
|
D(("out of input bytes"))
|
||||||
return p->error = MSPACK_ERR_READ;
|
return p->error = MSPACK_ERR_READ;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
read = 2;
|
read = 2;
|
||||||
p->inbuf[0] = p->inbuf[1] = 0;
|
p->inbuf[0] = p->inbuf[1] = 0;
|
||||||
p->input_end = 1;
|
p->input_end = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* update i_ptr and i_end */
|
/* update i_ptr and i_end */
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/* This file is part of libmspack.
|
/* 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
|
* 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
|
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
||||||
|
|
@ -10,8 +10,7 @@
|
||||||
#ifndef MSPACK_READHUFF_H
|
#ifndef MSPACK_READHUFF_H
|
||||||
#define MSPACK_READHUFF_H 1
|
#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))
|
#if !(defined(BITS_ORDER_MSB) || defined(BITS_ORDER_LSB))
|
||||||
# error "readhuff.h is used in conjunction with readbits.h, include that first"
|
# 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.
|
/* Decodes the next huffman symbol from the input bitstream into var.
|
||||||
* Do not use this macro on a table unless build_decode_table() succeeded.
|
* Do not use this macro on a table unless build_decode_table() succeeded.
|
||||||
*/
|
*/
|
||||||
#define READ_HUFFSYM(tbl, var) do { \
|
#define READ_HUFFSYM(tbl, var) do { \
|
||||||
ENSURE_BITS(HUFF_MAXBITS); \
|
ENSURE_BITS(HUFF_MAXBITS); \
|
||||||
sym = HUFF_TABLE(tbl, PEEK_BITS(TABLEBITS(tbl))); \
|
sym = HUFF_TABLE(tbl, PEEK_BITS(TABLEBITS(tbl))); \
|
||||||
if (sym >= MAXSYMBOLS(tbl)) HUFF_TRAVERSE(tbl); \
|
if (sym >= MAXSYMBOLS(tbl)) HUFF_TRAVERSE(tbl); \
|
||||||
(var) = sym; \
|
(var) = sym; \
|
||||||
i = HUFF_LEN(tbl, sym); \
|
i = HUFF_LEN(tbl, sym); \
|
||||||
REMOVE_BITS(i); \
|
REMOVE_BITS(i); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#ifdef BITS_ORDER_LSB
|
#ifdef BITS_ORDER_LSB
|
||||||
# define HUFF_TRAVERSE(tbl) do { \
|
# define HUFF_TRAVERSE(tbl) do { \
|
||||||
i = TABLEBITS(tbl) - 1; \
|
i = TABLEBITS(tbl) - 1; \
|
||||||
do { \
|
do { \
|
||||||
if (i++ > HUFF_MAXBITS) HUFF_ERROR; \
|
if (i++ > HUFF_MAXBITS) HUFF_ERROR; \
|
||||||
sym = HUFF_TABLE(tbl, \
|
sym = HUFF_TABLE(tbl, \
|
||||||
(sym << 1) | ((bit_buffer >> i) & 1)); \
|
(sym << 1) | ((bit_buffer >> i) & 1)); \
|
||||||
} while (sym >= MAXSYMBOLS(tbl)); \
|
} while (sym >= MAXSYMBOLS(tbl)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define HUFF_TRAVERSE(tbl) do { \
|
#define HUFF_TRAVERSE(tbl) do { \
|
||||||
i = 1 << (BITBUF_WIDTH - TABLEBITS(tbl)); \
|
i = 1 << (BITBUF_WIDTH - TABLEBITS(tbl)); \
|
||||||
do { \
|
do { \
|
||||||
if ((i >>= 1) == 0) HUFF_ERROR; \
|
if ((i >>= 1) == 0) HUFF_ERROR; \
|
||||||
sym = HUFF_TABLE(tbl, \
|
sym = HUFF_TABLE(tbl, \
|
||||||
(sym << 1) | ((bit_buffer & i) ? 1 : 0)); \
|
(sym << 1) | ((bit_buffer & i) ? 1 : 0)); \
|
||||||
} while (sym >= MAXSYMBOLS(tbl)); \
|
} while (sym >= MAXSYMBOLS(tbl)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -77,7 +76,7 @@
|
||||||
* Returns 0 for OK or 1 for error
|
* Returns 0 for OK or 1 for error
|
||||||
*/
|
*/
|
||||||
static int make_decode_table(unsigned int nsyms, unsigned int nbits,
|
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 short sym, next_symbol;
|
||||||
register unsigned int leaf, fill;
|
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 */
|
/* fill entries for codes short enough for a direct mapping */
|
||||||
for (bit_num = 1; bit_num <= nbits; bit_num++) {
|
for (bit_num = 1; bit_num <= nbits; bit_num++) {
|
||||||
for (sym = 0; sym < nsyms; sym++) {
|
for (sym = 0; sym < nsyms; sym++) {
|
||||||
if (length[sym] != bit_num) continue;
|
if (length[sym] != bit_num) continue;
|
||||||
#ifdef BITS_ORDER_MSB
|
#ifdef BITS_ORDER_MSB
|
||||||
leaf = pos;
|
leaf = pos;
|
||||||
#else
|
#else
|
||||||
/* reverse the significant bits */
|
/* reverse the significant bits */
|
||||||
fill = length[sym]; reverse = pos >> (nbits - fill); leaf = 0;
|
fill = length[sym]; reverse = pos >> (nbits - fill); leaf = 0;
|
||||||
do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
|
do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
|
||||||
#endif
|
#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
|
#ifdef BITS_ORDER_MSB
|
||||||
for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym;
|
for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym;
|
||||||
#else
|
#else
|
||||||
fill = bit_mask; next_symbol = 1 << bit_num;
|
fill = bit_mask; next_symbol = 1 << bit_num;
|
||||||
do { table[leaf] = sym; leaf += next_symbol; } while (--fill);
|
do { table[leaf] = sym; leaf += next_symbol; } while (--fill);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
bit_mask >>= 1;
|
bit_mask >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* exit with success if table is now complete */
|
/* 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 */
|
/* mark all remaining table entries as unused */
|
||||||
for (sym = pos; sym < table_mask; sym++) {
|
for (sym = pos; sym < table_mask; sym++) {
|
||||||
#ifdef BITS_ORDER_MSB
|
#ifdef BITS_ORDER_MSB
|
||||||
table[sym] = 0xFFFF;
|
table[sym] = 0xFFFF;
|
||||||
#else
|
#else
|
||||||
reverse = sym; leaf = 0; fill = nbits;
|
reverse = sym; leaf = 0; fill = nbits;
|
||||||
do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill);
|
do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill);
|
||||||
table[leaf] = 0xFFFF;
|
table[leaf] = 0xFFFF;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,33 +137,33 @@ static int make_decode_table(unsigned int nsyms, unsigned int nbits,
|
||||||
bit_mask = 1 << 15;
|
bit_mask = 1 << 15;
|
||||||
|
|
||||||
for (bit_num = nbits+1; bit_num <= HUFF_MAXBITS; bit_num++) {
|
for (bit_num = nbits+1; bit_num <= HUFF_MAXBITS; bit_num++) {
|
||||||
for (sym = 0; sym < nsyms; sym++) {
|
for (sym = 0; sym < nsyms; sym++) {
|
||||||
if (length[sym] != bit_num) continue;
|
if (length[sym] != bit_num) continue;
|
||||||
|
if (pos >= table_mask) return 1; /* table overflow */
|
||||||
|
|
||||||
#ifdef BITS_ORDER_MSB
|
#ifdef BITS_ORDER_MSB
|
||||||
leaf = pos >> 16;
|
leaf = pos >> 16;
|
||||||
#else
|
#else
|
||||||
/* leaf = the first nbits of the code, reversed */
|
/* leaf = the first nbits of the code, reversed */
|
||||||
reverse = pos >> 16; leaf = 0; fill = nbits;
|
reverse = pos >> 16; leaf = 0; fill = nbits;
|
||||||
do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
|
do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
|
||||||
#endif
|
#endif
|
||||||
for (fill = 0; fill < (bit_num - nbits); fill++) {
|
for (fill = 0; fill < (bit_num - nbits); fill++) {
|
||||||
/* if this path hasn't been taken yet, 'allocate' two entries */
|
/* if this path hasn't been taken yet, 'allocate' two entries */
|
||||||
if (table[leaf] == 0xFFFF) {
|
if (table[leaf] == 0xFFFF) {
|
||||||
table[(next_symbol << 1) ] = 0xFFFF;
|
table[(next_symbol << 1) ] = 0xFFFF;
|
||||||
table[(next_symbol << 1) + 1 ] = 0xFFFF;
|
table[(next_symbol << 1) + 1 ] = 0xFFFF;
|
||||||
table[leaf] = next_symbol++;
|
table[leaf] = next_symbol++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* follow the path and select either left or right for next bit */
|
/* follow the path and select either left or right for next bit */
|
||||||
leaf = table[leaf] << 1;
|
leaf = table[leaf] << 1;
|
||||||
if ((pos >> (15-fill)) & 1) leaf++;
|
if ((pos >> (15-fill)) & 1) leaf++;
|
||||||
}
|
}
|
||||||
table[leaf] = sym;
|
table[leaf] = sym;
|
||||||
|
pos += bit_mask;
|
||||||
if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
|
}
|
||||||
}
|
bit_mask >>= 1;
|
||||||
bit_mask >>= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* full table? */
|
/* full table? */
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
# include <config.h>
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "system-mspack.h"
|
#include "system-mspack.h"
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ extern "C" {
|
||||||
|
|
||||||
/* ensure config.h is read before mspack.h */
|
/* ensure config.h is read before mspack.h */
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
# include <config.h>
|
# include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "mspack.h"
|
#include "mspack.h"
|
||||||
|
|
@ -61,7 +61,7 @@ extern "C" {
|
||||||
(defined(FILESIZEBITS) && FILESIZEBITS >= 64) || \
|
(defined(FILESIZEBITS) && FILESIZEBITS >= 64) || \
|
||||||
(defined(SIZEOF_OFF_T) && SIZEOF_OFF_T >= 8) || \
|
(defined(SIZEOF_OFF_T) && SIZEOF_OFF_T >= 8) || \
|
||||||
defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE))
|
defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE))
|
||||||
# define LARGEFILE_SUPPORT
|
# define LARGEFILE_SUPPORT 1
|
||||||
# define LD "lld"
|
# define LD "lld"
|
||||||
# define LU "llu"
|
# define LU "llu"
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,8 @@ void mspack_destroy_szdd_decompressor(struct msszdd_decompressor *base)
|
||||||
{
|
{
|
||||||
struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
|
struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
|
||||||
if (self) {
|
if (self) {
|
||||||
struct mspack_system *sys = self->system;
|
struct mspack_system *sys = self->system;
|
||||||
sys->free(self);
|
sys->free(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,7 +77,7 @@ void mspack_destroy_szdd_decompressor(struct msszdd_decompressor *base)
|
||||||
* opens an SZDD file without decompressing, reads header
|
* opens an SZDD file without decompressing, reads header
|
||||||
*/
|
*/
|
||||||
static struct msszddd_header *szddd_open(struct msszdd_decompressor *base,
|
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 msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
|
||||||
struct msszddd_header *hdr;
|
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);
|
fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
|
||||||
hdr = (struct msszddd_header *) sys->alloc(sys, sizeof(struct msszddd_header_p));
|
hdr = (struct msszddd_header *) sys->alloc(sys, sizeof(struct msszddd_header_p));
|
||||||
if (fh && hdr) {
|
if (fh && hdr) {
|
||||||
((struct msszddd_header_p *) hdr)->fh = fh;
|
((struct msszddd_header_p *) hdr)->fh = fh;
|
||||||
self->error = szddd_read_headers(sys, fh, hdr);
|
self->error = szddd_read_headers(sys, fh, hdr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!fh) self->error = MSPACK_ERR_OPEN;
|
if (!fh) self->error = MSPACK_ERR_OPEN;
|
||||||
if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
|
if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self->error) {
|
if (self->error) {
|
||||||
if (fh) sys->close(fh);
|
if (fh) sys->close(fh);
|
||||||
if (hdr) sys->free(hdr);
|
sys->free(hdr);
|
||||||
hdr = NULL;
|
hdr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hdr;
|
return hdr;
|
||||||
|
|
@ -113,7 +113,7 @@ static struct msszddd_header *szddd_open(struct msszdd_decompressor *base,
|
||||||
* closes an SZDD file
|
* closes an SZDD file
|
||||||
*/
|
*/
|
||||||
static void szddd_close(struct msszdd_decompressor *base,
|
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 msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
|
||||||
struct msszddd_header_p *hdr_p = (struct msszddd_header_p *) hdr;
|
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,
|
static int szddd_read_headers(struct mspack_system *sys,
|
||||||
struct mspack_file *fh,
|
struct mspack_file *fh,
|
||||||
struct msszddd_header *hdr)
|
struct msszddd_header *hdr)
|
||||||
{
|
{
|
||||||
unsigned char buf[8];
|
unsigned char buf[8];
|
||||||
|
|
||||||
/* read and check signature */
|
/* read and check signature */
|
||||||
if (sys->read(fh, buf, 8) != 8) return MSPACK_ERR_READ;
|
if (sys->read(fh, buf, 8) != 8) return MSPACK_ERR_READ;
|
||||||
|
|
||||||
if ((mspack_memcmp(buf, szdd_signature_expand, 8) == 0)) {
|
if ((memcmp(buf, szdd_signature_expand, 8) == 0)) {
|
||||||
/* common SZDD */
|
/* common SZDD */
|
||||||
hdr->format = MSSZDD_FMT_NORMAL;
|
hdr->format = MSSZDD_FMT_NORMAL;
|
||||||
|
|
||||||
/* read the rest of the header */
|
/* read the rest of the header */
|
||||||
if (sys->read(fh, buf, 6) != 6) return MSPACK_ERR_READ;
|
if (sys->read(fh, buf, 6) != 6) return MSPACK_ERR_READ;
|
||||||
if (buf[0] != 0x41) return MSPACK_ERR_DATAFORMAT;
|
if (buf[0] != 0x41) return MSPACK_ERR_DATAFORMAT;
|
||||||
hdr->missing_char = buf[1];
|
hdr->missing_char = buf[1];
|
||||||
hdr->length = EndGetI32(&buf[2]);
|
hdr->length = EndGetI32(&buf[2]);
|
||||||
}
|
}
|
||||||
else if ((mspack_memcmp(buf, szdd_signature_qbasic, 8) == 0)) {
|
else if ((memcmp(buf, szdd_signature_qbasic, 8) == 0)) {
|
||||||
/* special QBasic SZDD */
|
/* special QBasic SZDD */
|
||||||
hdr->format = MSSZDD_FMT_QBASIC;
|
hdr->format = MSSZDD_FMT_QBASIC;
|
||||||
if (sys->read(fh, buf, 4) != 4) return MSPACK_ERR_READ;
|
if (sys->read(fh, buf, 4) != 4) return MSPACK_ERR_READ;
|
||||||
hdr->missing_char = '\0';
|
hdr->missing_char = '\0';
|
||||||
hdr->length = EndGetI32(buf);
|
hdr->length = EndGetI32(buf);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return MSPACK_ERR_SIGNATURE;
|
return MSPACK_ERR_SIGNATURE;
|
||||||
}
|
}
|
||||||
return MSPACK_ERR_OK;
|
return MSPACK_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -179,7 +179,7 @@ static int szddd_read_headers(struct mspack_system *sys,
|
||||||
* decompresses an SZDD file
|
* decompresses an SZDD file
|
||||||
*/
|
*/
|
||||||
static int szddd_extract(struct msszdd_decompressor *base,
|
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 msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
|
||||||
struct mspack_file *fh, *outfh;
|
struct mspack_file *fh, *outfh;
|
||||||
|
|
@ -195,19 +195,19 @@ static int szddd_extract(struct msszdd_decompressor *base,
|
||||||
/* seek to the compressed data */
|
/* seek to the compressed data */
|
||||||
data_offset = (hdr->format == MSSZDD_FMT_NORMAL) ? 14 : 12;
|
data_offset = (hdr->format == MSSZDD_FMT_NORMAL) ? 14 : 12;
|
||||||
if (sys->seek(fh, data_offset, MSPACK_SYS_SEEK_START)) {
|
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 */
|
/* open file for output */
|
||||||
if (!(outfh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
|
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 */
|
/* decompress the data */
|
||||||
self->error = lzss_decompress(sys, fh, outfh, SZDD_INPUT_SIZE,
|
self->error = lzss_decompress(sys, fh, outfh, SZDD_INPUT_SIZE,
|
||||||
hdr->format == MSSZDD_FMT_NORMAL
|
hdr->format == MSSZDD_FMT_NORMAL
|
||||||
? LZSS_MODE_EXPAND
|
? LZSS_MODE_EXPAND
|
||||||
: LZSS_MODE_QBASIC);
|
: LZSS_MODE_QBASIC);
|
||||||
|
|
||||||
/* close output file */
|
/* close output file */
|
||||||
sys->close(outfh);
|
sys->close(outfh);
|
||||||
|
|
@ -221,7 +221,7 @@ static int szddd_extract(struct msszdd_decompressor *base,
|
||||||
* unpacks directly from input to output
|
* unpacks directly from input to output
|
||||||
*/
|
*/
|
||||||
static int szddd_decompress(struct msszdd_decompressor *base,
|
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 msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
|
||||||
struct msszddd_header *hdr;
|
struct msszddd_header *hdr;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue