summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rbutil/rbutilqt/mspack/README.ROCKBOX4
-rw-r--r--rbutil/rbutilqt/mspack/cab.h27
-rw-r--r--rbutil/rbutilqt/mspack/cabd.c541
-rw-r--r--rbutil/rbutilqt/mspack/chmd.c667
-rw-r--r--rbutil/rbutilqt/mspack/kwajd.c365
-rw-r--r--rbutil/rbutilqt/mspack/lzss.h8
-rw-r--r--rbutil/rbutilqt/mspack/lzssd.c84
-rw-r--r--rbutil/rbutilqt/mspack/lzx.h61
-rw-r--r--rbutil/rbutilqt/mspack/lzxd.c793
-rw-r--r--rbutil/rbutilqt/mspack/mspack.h316
-rw-r--r--rbutil/rbutilqt/mspack/mszip.h17
-rw-r--r--rbutil/rbutilqt/mspack/mszipd.c268
-rw-r--r--rbutil/rbutilqt/mspack/qtm.h8
-rw-r--r--rbutil/rbutilqt/mspack/qtmd.c235
-rw-r--r--rbutil/rbutilqt/mspack/readbits.h104
-rw-r--r--rbutil/rbutilqt/mspack/readhuff.h129
-rw-r--r--rbutil/rbutilqt/mspack/system-mspack.c2
-rw-r--r--rbutil/rbutilqt/mspack/system-mspack.h4
-rw-r--r--rbutil/rbutilqt/mspack/szddd.c70
19 files changed, 2121 insertions, 1582 deletions
diff --git a/rbutil/rbutilqt/mspack/README.ROCKBOX b/rbutil/rbutilqt/mspack/README.ROCKBOX
index db5ba7f482..220691af2c 100644
--- a/rbutil/rbutilqt/mspack/README.ROCKBOX
+++ b/rbutil/rbutilqt/mspack/README.ROCKBOX
@@ -1,6 +1,6 @@
1This folder contains the mspack project for MS files compression/decompression. 1This folder contains the mspack project for MS files compression/decompression.
2These files are distributed under the LGPL. 2These files are distributed under the LGPL.
3The source files have been last synced with libmspack-0.3alpha
4http://sourceforge.net/projects/libmspack/on January 28, 2013
5 3
4The source files have been last synced with libmspack-0.10.1alpha
5https://www.cabextract.org.uk/libmspack/ on June 8, 2020
6 6
diff --git a/rbutil/rbutilqt/mspack/cab.h b/rbutil/rbutilqt/mspack/cab.h
index 78ec8e60db..79d9951252 100644
--- a/rbutil/rbutilqt/mspack/cab.h
+++ b/rbutil/rbutilqt/mspack/cab.h
@@ -1,5 +1,5 @@
1/* This file is part of libmspack. 1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie. 2 * (C) 2003-2018 Stuart Caie.
3 * 3 *
4 * libmspack is free software; you can redistribute it and/or modify it under 4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1 5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
@@ -10,10 +10,6 @@
10#ifndef MSPACK_CAB_H 10#ifndef MSPACK_CAB_H
11#define MSPACK_CAB_H 1 11#define MSPACK_CAB_H 1
12 12
13#include "mszip.h"
14#include "qtm.h"
15#include "lzx.h"
16
17/* generic CAB definitions */ 13/* generic CAB definitions */
18 14
19/* structure offsets */ 15/* structure offsets */
@@ -70,6 +66,22 @@
70#define CAB_BLOCKMAX (32768) 66#define CAB_BLOCKMAX (32768)
71#define CAB_INPUTMAX (CAB_BLOCKMAX+6144) 67#define CAB_INPUTMAX (CAB_BLOCKMAX+6144)
72 68
69/* input buffer needs to be CAB_INPUTMAX + 1 byte to allow for max-sized block
70 * plus 1 trailer byte added by cabd_sys_read_block() for Quantum alignment.
71 *
72 * When MSCABD_PARAM_SALVAGE is set, block size is not checked so can be
73 * up to 65535 bytes, so max input buffer size needed is 65535 + 1
74 */
75#define CAB_INPUTMAX_SALVAGE (65535)
76#define CAB_INPUTBUF (CAB_INPUTMAX_SALVAGE + 1)
77
78/* There are no more than 65535 data blocks per folder, so a folder cannot
79 * be more than 32768*65535 bytes in length. As files cannot span more than
80 * one folder, this is also their max offset, length and offset+length limit.
81 */
82#define CAB_FOLDERMAX (65535)
83#define CAB_LENGTHMAX (CAB_BLOCKMAX * CAB_FOLDERMAX)
84
73/* CAB compression definitions */ 85/* CAB compression definitions */
74 86
75struct mscab_compressor_p { 87struct mscab_compressor_p {
@@ -85,6 +97,7 @@ struct mscabd_decompress_state {
85 struct mscabd_folder_data *data; /* current folder split we're in */ 97 struct mscabd_folder_data *data; /* current folder split we're in */
86 unsigned int offset; /* uncompressed offset within folder */ 98 unsigned int offset; /* uncompressed offset within folder */
87 unsigned int block; /* which block are we decompressing? */ 99 unsigned int block; /* which block are we decompressing? */
100 off_t outlen; /* cumulative sum of block output sizes */
88 struct mspack_system sys; /* special I/O code for decompressor */ 101 struct mspack_system sys; /* special I/O code for decompressor */
89 int comp_type; /* type of compression used by folder */ 102 int comp_type; /* type of compression used by folder */
90 int (*decompress)(void *, off_t); /* decompressor code */ 103 int (*decompress)(void *, off_t); /* decompressor code */
@@ -93,14 +106,14 @@ struct mscabd_decompress_state {
93 struct mspack_file *infh; /* input file handle */ 106 struct mspack_file *infh; /* input file handle */
94 struct mspack_file *outfh; /* output file handle */ 107 struct mspack_file *outfh; /* output file handle */
95 unsigned char *i_ptr, *i_end; /* input data consumed, end */ 108 unsigned char *i_ptr, *i_end; /* input data consumed, end */
96 unsigned char input[CAB_INPUTMAX]; /* one input block of data */ 109 unsigned char input[CAB_INPUTBUF]; /* one input block of data */
97}; 110};
98 111
99struct mscab_decompressor_p { 112struct mscab_decompressor_p {
100 struct mscab_decompressor base; 113 struct mscab_decompressor base;
101 struct mscabd_decompress_state *d; 114 struct mscabd_decompress_state *d;
102 struct mspack_system *system; 115 struct mspack_system *system;
103 int param[3]; /* !!! MATCH THIS TO NUM OF PARAMS IN MSPACK.H !!! */ 116 int buf_size, searchbuf_size, fix_mszip, salvage; /* params */
104 int error, read_error; 117 int error, read_error;
105}; 118};
106 119
diff --git a/rbutil/rbutilqt/mspack/cabd.c b/rbutil/rbutilqt/mspack/cabd.c
index 6549d7b8cf..ae66769b24 100644
--- a/rbutil/rbutilqt/mspack/cabd.c
+++ b/rbutil/rbutilqt/mspack/cabd.c
@@ -1,5 +1,5 @@
1/* This file is part of libmspack. 1/* This file is part of libmspack.
2 * (C) 2003-2011 Stuart Caie. 2 * (C) 2003-2018 Stuart Caie.
3 * 3 *
4 * libmspack is free software; you can redistribute it and/or modify it under 4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1 5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
@@ -23,7 +23,9 @@
23 23
24#include "system-mspack.h" 24#include "system-mspack.h"
25#include "cab.h" 25#include "cab.h"
26#include <assert.h> 26#include "mszip.h"
27#include "lzx.h"
28#include "qtm.h"
27 29
28/* Notes on compliance with cabinet specification: 30/* Notes on compliance with cabinet specification:
29 * 31 *
@@ -72,10 +74,9 @@ static void cabd_close(
72 struct mscab_decompressor *base, struct mscabd_cabinet *origcab); 74 struct mscab_decompressor *base, struct mscabd_cabinet *origcab);
73static int cabd_read_headers( 75static int cabd_read_headers(
74 struct mspack_system *sys, struct mspack_file *fh, 76 struct mspack_system *sys, struct mspack_file *fh,
75 struct mscabd_cabinet_p *cab, off_t offset, int quiet); 77 struct mscabd_cabinet_p *cab, off_t offset, int salvage, int quiet);
76static char *cabd_read_string( 78static char *cabd_read_string(
77 struct mspack_system *sys, struct mspack_file *fh, 79 struct mspack_system *sys, struct mspack_file *fh, int *error);
78 struct mscabd_cabinet_p *cab, int *error);
79 80
80static struct mscabd_cabinet *cabd_search( 81static struct mscabd_cabinet *cabd_search(
81 struct mscab_decompressor *base, const char *filename); 82 struct mscab_decompressor *base, const char *filename);
@@ -110,7 +111,7 @@ static int cabd_sys_write(
110 struct mspack_file *file, void *buffer, int bytes); 111 struct mspack_file *file, void *buffer, int bytes);
111static int cabd_sys_read_block( 112static int cabd_sys_read_block(
112 struct mspack_system *sys, struct mscabd_decompress_state *d, int *out, 113 struct mspack_system *sys, struct mscabd_decompress_state *d, int *out,
113 int ignore_cksum); 114 int ignore_cksum, int ignore_blocksize);
114static unsigned int cabd_checksum( 115static unsigned int cabd_checksum(
115 unsigned char *data, unsigned int bytes, unsigned int cksum); 116 unsigned char *data, unsigned int bytes, unsigned int cksum);
116static struct noned_state *noned_init( 117static struct noned_state *noned_init(
@@ -155,9 +156,10 @@ struct mscab_decompressor *
155 self->d = NULL; 156 self->d = NULL;
156 self->error = MSPACK_ERR_OK; 157 self->error = MSPACK_ERR_OK;
157 158
158 self->param[MSCABD_PARAM_SEARCHBUF] = 32768; 159 self->searchbuf_size = 32768;
159 self->param[MSCABD_PARAM_FIXMSZIP] = 0; 160 self->fix_mszip = 0;
160 self->param[MSCABD_PARAM_DECOMPBUF] = 4096; 161 self->buf_size = 4096;
162 self->salvage = 0;
161 } 163 }
162 return (struct mscab_decompressor *) self; 164 return (struct mscab_decompressor *) self;
163} 165}
@@ -171,9 +173,9 @@ void mspack_destroy_cab_decompressor(struct mscab_decompressor *base) {
171 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base; 173 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
172 if (self) { 174 if (self) {
173 struct mspack_system *sys = self->system; 175 struct mspack_system *sys = self->system;
174 cabd_free_decomp(self);
175 if (self->d) { 176 if (self->d) {
176 if (self->d->infh) sys->close(self->d->infh); 177 if (self->d->infh) sys->close(self->d->infh);
178 cabd_free_decomp(self);
177 sys->free(self->d); 179 sys->free(self->d);
178 } 180 }
179 sys->free(self); 181 sys->free(self);
@@ -187,7 +189,7 @@ void mspack_destroy_cab_decompressor(struct mscab_decompressor *base) {
187 * opens a file and tries to read it as a cabinet file 189 * opens a file and tries to read it as a cabinet file
188 */ 190 */
189static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base, 191static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
190 const char *filename) 192 const char *filename)
191{ 193{
192 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base; 194 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
193 struct mscabd_cabinet_p *cab = NULL; 195 struct mscabd_cabinet_p *cab = NULL;
@@ -201,10 +203,10 @@ static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
201 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) { 203 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
202 if ((cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) { 204 if ((cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
203 cab->base.filename = filename; 205 cab->base.filename = filename;
204 error = cabd_read_headers(sys, fh, cab, (off_t) 0, 0); 206 error = cabd_read_headers(sys, fh, cab, (off_t) 0, self->salvage, 0);
205 if (error) { 207 if (error) {
206 cabd_close(base, (struct mscabd_cabinet *) cab); 208 cabd_close(base, (struct mscabd_cabinet *) cab);
207 cab = NULL; 209 cab = NULL;
208 } 210 }
209 self->error = error; 211 self->error = error;
210 } 212 }
@@ -225,7 +227,7 @@ static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
225 * frees all memory associated with a given mscabd_cabinet. 227 * frees all memory associated with a given mscabd_cabinet.
226 */ 228 */
227static void cabd_close(struct mscab_decompressor *base, 229static void cabd_close(struct mscab_decompressor *base,
228 struct mscabd_cabinet *origcab) 230 struct mscabd_cabinet *origcab)
229{ 231{
230 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base; 232 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
231 struct mscabd_folder_data *dat, *ndat; 233 struct mscabd_folder_data *dat, *ndat;
@@ -253,16 +255,16 @@ static void cabd_close(struct mscab_decompressor *base,
253 255
254 /* free folder decompression state if it has been decompressed */ 256 /* free folder decompression state if it has been decompressed */
255 if (self->d && (self->d->folder == (struct mscabd_folder_p *) fol)) { 257 if (self->d && (self->d->folder == (struct mscabd_folder_p *) fol)) {
256 if (self->d->infh) sys->close(self->d->infh); 258 if (self->d->infh) sys->close(self->d->infh);
257 cabd_free_decomp(self); 259 cabd_free_decomp(self);
258 sys->free(self->d); 260 sys->free(self->d);
259 self->d = NULL; 261 self->d = NULL;
260 } 262 }
261 263
262 /* free folder data segments */ 264 /* free folder data segments */
263 for (dat = ((struct mscabd_folder_p *)fol)->data.next; dat; dat = ndat) { 265 for (dat = ((struct mscabd_folder_p *)fol)->data.next; dat; dat = ndat) {
264 ndat = dat->next; 266 ndat = dat->next;
265 sys->free(dat); 267 sys->free(dat);
266 } 268 }
267 sys->free(fol); 269 sys->free(fol);
268 } 270 }
@@ -304,11 +306,11 @@ static void cabd_close(struct mscab_decompressor *base,
304 * for folders and files as necessary 306 * for folders and files as necessary
305 */ 307 */
306static int cabd_read_headers(struct mspack_system *sys, 308static int cabd_read_headers(struct mspack_system *sys,
307 struct mspack_file *fh, 309 struct mspack_file *fh,
308 struct mscabd_cabinet_p *cab, 310 struct mscabd_cabinet_p *cab,
309 off_t offset, int quiet) 311 off_t offset, int salvage, int quiet)
310{ 312{
311 int num_folders, num_files, folder_resv, i, x; 313 int num_folders, num_files, folder_resv, i, x, err, fidx;
312 struct mscabd_folder_p *fol, *linkfol = NULL; 314 struct mscabd_folder_p *fol, *linkfol = NULL;
313 struct mscabd_file *file, *linkfile = NULL; 315 struct mscabd_file *file, *linkfile = NULL;
314 unsigned char buf[64]; 316 unsigned char buf[64];
@@ -364,6 +366,7 @@ static int cabd_read_headers(struct mspack_system *sys,
364 366
365 /* read the reserved-sizes part of header, if present */ 367 /* read the reserved-sizes part of header, if present */
366 cab->base.flags = EndGetI16(&buf[cfhead_Flags]); 368 cab->base.flags = EndGetI16(&buf[cfhead_Flags]);
369
367 if (cab->base.flags & cfheadRESERVE_PRESENT) { 370 if (cab->base.flags & cfheadRESERVE_PRESENT) {
368 if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) { 371 if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) {
369 return MSPACK_ERR_READ; 372 return MSPACK_ERR_READ;
@@ -379,7 +382,7 @@ static int cabd_read_headers(struct mspack_system *sys,
379 /* skip the reserved header */ 382 /* skip the reserved header */
380 if (cab->base.header_resv) { 383 if (cab->base.header_resv) {
381 if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) { 384 if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) {
382 return MSPACK_ERR_SEEK; 385 return MSPACK_ERR_SEEK;
383 } 386 }
384 } 387 }
385 } 388 }
@@ -391,14 +394,18 @@ static int cabd_read_headers(struct mspack_system *sys,
391 394
392 /* read name and info of preceeding cabinet in set, if present */ 395 /* read name and info of preceeding cabinet in set, if present */
393 if (cab->base.flags & cfheadPREV_CABINET) { 396 if (cab->base.flags & cfheadPREV_CABINET) {
394 cab->base.prevname = cabd_read_string(sys, fh, cab, &x); if (x) return x; 397 cab->base.prevname = cabd_read_string(sys, fh, &err);
395 cab->base.previnfo = cabd_read_string(sys, fh, cab, &x); if (x) return x; 398 if (err) return err;
399 cab->base.previnfo = cabd_read_string(sys, fh, &err);
400 if (err) return err;
396 } 401 }
397 402
398 /* read name and info of next cabinet in set, if present */ 403 /* read name and info of next cabinet in set, if present */
399 if (cab->base.flags & cfheadNEXT_CABINET) { 404 if (cab->base.flags & cfheadNEXT_CABINET) {
400 cab->base.nextname = cabd_read_string(sys, fh, cab, &x); if (x) return x; 405 cab->base.nextname = cabd_read_string(sys, fh, &err);
401 cab->base.nextinfo = cabd_read_string(sys, fh, cab, &x); if (x) return x; 406 if (err) return err;
407 cab->base.nextinfo = cabd_read_string(sys, fh, &err);
408 if (err) return err;
402 } 409 }
403 410
404 /* read folders */ 411 /* read folders */
@@ -408,7 +415,7 @@ static int cabd_read_headers(struct mspack_system *sys,
408 } 415 }
409 if (folder_resv) { 416 if (folder_resv) {
410 if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) { 417 if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) {
411 return MSPACK_ERR_SEEK; 418 return MSPACK_ERR_SEEK;
412 } 419 }
413 } 420 }
414 421
@@ -447,45 +454,44 @@ static int cabd_read_headers(struct mspack_system *sys,
447 file->offset = EndGetI32(&buf[cffile_FolderOffset]); 454 file->offset = EndGetI32(&buf[cffile_FolderOffset]);
448 455
449 /* set folder pointer */ 456 /* set folder pointer */
450 x = EndGetI16(&buf[cffile_FolderIndex]); 457 fidx = EndGetI16(&buf[cffile_FolderIndex]);
451 if (x < cffileCONTINUED_FROM_PREV) { 458 if (fidx < cffileCONTINUED_FROM_PREV) {
452 /* normal folder index; count up to the correct folder. the folder 459 /* normal folder index; count up to the correct folder */
453 * pointer will be NULL if folder index is invalid */ 460 if (fidx < num_folders) {
454 struct mscabd_folder *ifol = cab->base.folders; 461 struct mscabd_folder *ifol = cab->base.folders;
455 while (x--) if (ifol) ifol = ifol->next; 462 while (fidx--) if (ifol) ifol = ifol->next;
456 file->folder = ifol; 463 file->folder = ifol;
457 464 }
458 if (!ifol) { 465 else {
459 sys->free(file); 466 D(("invalid folder index"))
460 D(("invalid folder index")) 467 file->folder = NULL;
461 return MSPACK_ERR_DATAFORMAT;
462 } 468 }
463 } 469 }
464 else { 470 else {
465 /* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or 471 /* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or
466 * CONTINUED_PREV_AND_NEXT */ 472 * CONTINUED_PREV_AND_NEXT */
467 if ((x == cffileCONTINUED_TO_NEXT) || 473 if ((fidx == cffileCONTINUED_TO_NEXT) ||
468 (x == cffileCONTINUED_PREV_AND_NEXT)) 474 (fidx == cffileCONTINUED_PREV_AND_NEXT))
469 { 475 {
470 /* get last folder */ 476 /* get last folder */
471 struct mscabd_folder *ifol = cab->base.folders; 477 struct mscabd_folder *ifol = cab->base.folders;
472 while (ifol->next) ifol = ifol->next; 478 while (ifol->next) ifol = ifol->next;
473 file->folder = ifol; 479 file->folder = ifol;
474 480
475 /* set "merge next" pointer */ 481 /* set "merge next" pointer */
476 fol = (struct mscabd_folder_p *) ifol; 482 fol = (struct mscabd_folder_p *) ifol;
477 if (!fol->merge_next) fol->merge_next = file; 483 if (!fol->merge_next) fol->merge_next = file;
478 } 484 }
479 485
480 if ((x == cffileCONTINUED_FROM_PREV) || 486 if ((fidx == cffileCONTINUED_FROM_PREV) ||
481 (x == cffileCONTINUED_PREV_AND_NEXT)) 487 (fidx == cffileCONTINUED_PREV_AND_NEXT))
482 { 488 {
483 /* get first folder */ 489 /* get first folder */
484 file->folder = cab->base.folders; 490 file->folder = cab->base.folders;
485 491
486 /* set "merge prev" pointer */ 492 /* set "merge prev" pointer */
487 fol = (struct mscabd_folder_p *) file->folder; 493 fol = (struct mscabd_folder_p *) file->folder;
488 if (!fol->merge_prev) fol->merge_prev = file; 494 if (!fol->merge_prev) fol->merge_prev = file;
489 } 495 }
490 } 496 }
491 497
@@ -502,10 +508,14 @@ static int cabd_read_headers(struct mspack_system *sys,
502 file->date_y = (x >> 9) + 1980; 508 file->date_y = (x >> 9) + 1980;
503 509
504 /* get filename */ 510 /* get filename */
505 file->filename = cabd_read_string(sys, fh, cab, &x); 511 file->filename = cabd_read_string(sys, fh, &err);
506 if (x) { 512
513 /* if folder index or filename are bad, either skip it or fail */
514 if (err || !file->folder) {
515 sys->free(file->filename);
507 sys->free(file); 516 sys->free(file);
508 return x; 517 if (salvage) continue;
518 return err ? err : MSPACK_ERR_DATAFORMAT;
509 } 519 }
510 520
511 /* link file entry into file list */ 521 /* link file entry into file list */
@@ -514,23 +524,34 @@ static int cabd_read_headers(struct mspack_system *sys,
514 linkfile = file; 524 linkfile = file;
515 } 525 }
516 526
527 if (cab->base.files == NULL) {
528 /* We never actually added any files to the file list. Something went wrong.
529 * The file header may have been invalid */
530 D(("No files found, even though header claimed to have %d files", num_files))
531 return MSPACK_ERR_DATAFORMAT;
532 }
533
517 return MSPACK_ERR_OK; 534 return MSPACK_ERR_OK;
518} 535}
519 536
520static char *cabd_read_string(struct mspack_system *sys, 537static char *cabd_read_string(struct mspack_system *sys,
521 struct mspack_file *fh, 538 struct mspack_file *fh, int *error)
522 struct mscabd_cabinet_p *cab, int *error)
523{ 539{
524 off_t base = sys->tell(fh); 540 off_t base = sys->tell(fh);
525 char buf[256], *str; 541 char buf[256], *str;
526 unsigned int len, i, ok; 542 int len, i, ok;
527 (void)cab;
528 543
529 /* read up to 256 bytes */ 544 /* read up to 256 bytes */
530 len = sys->read(fh, &buf[0], 256); 545 if ((len = sys->read(fh, &buf[0], 256)) <= 0) {
546 *error = MSPACK_ERR_READ;
547 return NULL;
548 }
531 549
532 /* search for a null terminator in the buffer */ 550 /* search for a null terminator in the buffer */
533 for (i = 0, ok = 0; i < len; i++) if (!buf[i]) { ok = 1; break; } 551 for (i = 0, ok = 0; i < len; i++) if (!buf[i]) { ok = 1; break; }
552 /* reject empty strings */
553 if (i == 0) ok = 0;
554
534 if (!ok) { 555 if (!ok) {
535 *error = MSPACK_ERR_DATAFORMAT; 556 *error = MSPACK_ERR_DATAFORMAT;
536 return NULL; 557 return NULL;
@@ -566,7 +587,7 @@ static char *cabd_read_string(struct mspack_system *sys,
566 * break out of the loop and be sure that all resources are freed 587 * break out of the loop and be sure that all resources are freed
567 */ 588 */
568static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base, 589static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
569 const char *filename) 590 const char *filename)
570{ 591{
571 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base; 592 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
572 struct mscabd_cabinet_p *cab = NULL; 593 struct mscabd_cabinet_p *cab = NULL;
@@ -579,7 +600,7 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
579 sys = self->system; 600 sys = self->system;
580 601
581 /* allocate a search buffer */ 602 /* allocate a search buffer */
582 search_buf = (unsigned char *) sys->alloc(sys, (size_t) self->param[MSCABD_PARAM_SEARCHBUF]); 603 search_buf = (unsigned char *) sys->alloc(sys, (size_t) self->searchbuf_size);
583 if (!search_buf) { 604 if (!search_buf) {
584 self->error = MSPACK_ERR_NOMEMORY; 605 self->error = MSPACK_ERR_NOMEMORY;
585 return NULL; 606 return NULL;
@@ -589,21 +610,21 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
589 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) { 610 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
590 if (!(self->error = mspack_sys_filelen(sys, fh, &filelen))) { 611 if (!(self->error = mspack_sys_filelen(sys, fh, &filelen))) {
591 self->error = cabd_find(self, search_buf, fh, filename, 612 self->error = cabd_find(self, search_buf, fh, filename,
592 filelen, &firstlen, &cab); 613 filelen, &firstlen, &cab);
593 } 614 }
594 615
595 /* truncated / extraneous data warning: */ 616 /* truncated / extraneous data warning: */
596 if (firstlen && (firstlen != filelen) && 617 if (firstlen && (firstlen != filelen) &&
597 (!cab || (cab->base.base_offset == 0))) 618 (!cab || (cab->base.base_offset == 0)))
598 { 619 {
599 if (firstlen < filelen) { 620 if (firstlen < filelen) {
600 sys->message(fh, "WARNING; possible %" LD 621 sys->message(fh, "WARNING; possible %" LD
601 " extra bytes at end of file.", 622 " extra bytes at end of file.",
602 filelen - firstlen); 623 filelen - firstlen);
603 } 624 }
604 else { 625 else {
605 sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.", 626 sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.",
606 firstlen - filelen); 627 firstlen - filelen);
607 } 628 }
608 } 629 }
609 630
@@ -620,8 +641,8 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
620} 641}
621 642
622static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf, 643static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
623 struct mspack_file *fh, const char *filename, off_t flen, 644 struct mspack_file *fh, const char *filename, off_t flen,
624 off_t *firstlen, struct mscabd_cabinet_p **firstcab) 645 off_t *firstlen, struct mscabd_cabinet_p **firstcab)
625{ 646{
626 struct mscabd_cabinet_p *cab, *link = NULL; 647 struct mscabd_cabinet_p *cab, *link = NULL;
627 off_t caboff, offset, length; 648 off_t caboff, offset, length;
@@ -630,7 +651,7 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
630 unsigned int cablen_u32 = 0, foffset_u32 = 0; 651 unsigned int cablen_u32 = 0, foffset_u32 = 0;
631 int false_cabs = 0; 652 int false_cabs = 0;
632 653
633#ifndef LARGEFILE_SUPPORT 654#if !LARGEFILE_SUPPORT
634 /* detect 32-bit off_t overflow */ 655 /* detect 32-bit off_t overflow */
635 if (flen < 0) { 656 if (flen < 0) {
636 sys->message(fh, largefile_msg); 657 sys->message(fh, largefile_msg);
@@ -643,8 +664,8 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
643 /* search length is either the full length of the search buffer, or the 664 /* search length is either the full length of the search buffer, or the
644 * amount of data remaining to the end of the file, whichever is less. */ 665 * amount of data remaining to the end of the file, whichever is less. */
645 length = flen - offset; 666 length = flen - offset;
646 if (length > self->param[MSCABD_PARAM_SEARCHBUF]) { 667 if (length > self->searchbuf_size) {
647 length = self->param[MSCABD_PARAM_SEARCHBUF]; 668 length = self->searchbuf_size;
648 } 669 }
649 670
650 /* fill the search buffer with data from disk */ 671 /* fill the search buffer with data from disk */
@@ -654,22 +675,21 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
654 675
655 /* FAQ avoidance strategy */ 676 /* FAQ avoidance strategy */
656 if ((offset == 0) && (EndGetI32(&buf[0]) == 0x28635349)) { 677 if ((offset == 0) && (EndGetI32(&buf[0]) == 0x28635349)) {
657 sys->message(fh, "WARNING; found InstallShield header. " 678 sys->message(fh, "WARNING; found InstallShield header. Use unshield "
658 "This is probably an InstallShield file. " 679 "(https://github.com/twogood/unshield) to unpack this file");
659 "Use UNSHIELD from www.synce.org to unpack it.");
660 } 680 }
661 681
662 /* read through the entire buffer. */ 682 /* read through the entire buffer. */
663 for (p = &buf[0], pend = &buf[length]; p < pend; ) { 683 for (p = &buf[0], pend = &buf[length]; p < pend; ) {
664 switch (state) { 684 switch (state) {
665 /* starting state */ 685 /* starting state */
666 case 0: 686 case 0:
667 /* we spend most of our time in this while loop, looking for 687 /* we spend most of our time in this while loop, looking for
668 * a leading 'M' of the 'MSCF' signature */ 688 * a leading 'M' of the 'MSCF' signature */
669 while (p < pend && *p != 0x4D) p++; 689 while (p < pend && *p != 0x4D) p++;
670 /* if we found tht 'M', advance state */ 690 /* if we found tht 'M', advance state */
671 if (p++ < pend) state = 1; 691 if (p++ < pend) state = 1;
672 break; 692 break;
673 693
674 /* verify that the next 3 bytes are 'S', 'C' and 'F' */ 694 /* verify that the next 3 bytes are 'S', 'C' and 'F' */
675 case 1: state = (*p++ == 0x53) ? 2 : 0; break; 695 case 1: state = (*p++ == 0x53) ? 2 : 0; break;
@@ -691,70 +711,71 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
691 case 17: foffset_u32 |= *p++ << 8; state++; break; 711 case 17: foffset_u32 |= *p++ << 8; state++; break;
692 case 18: foffset_u32 |= *p++ << 16; state++; break; 712 case 18: foffset_u32 |= *p++ << 16; state++; break;
693 case 19: foffset_u32 |= *p++ << 24; 713 case 19: foffset_u32 |= *p++ << 24;
694 /* now we have recieved 20 bytes of potential cab header. work out 714 /* now we have recieved 20 bytes of potential cab header. work out
695 * the offset in the file of this potential cabinet */ 715 * the offset in the file of this potential cabinet */
696 caboff = offset + (p - &buf[0]) - 20; 716 caboff = offset + (p - &buf[0]) - 20;
697 717
698 /* should reading cabinet fail, restart search just after 'MSCF' */ 718 /* should reading cabinet fail, restart search just after 'MSCF' */
699 offset = caboff + 4; 719 offset = caboff + 4;
700 720
701 /* capture the "length of cabinet" field if there is a cabinet at 721 /* capture the "length of cabinet" field if there is a cabinet at
702 * offset 0 in the file, regardless of whether the cabinet can be 722 * offset 0 in the file, regardless of whether the cabinet can be
703 * read correctly or not */ 723 * read correctly or not */
704 if (caboff == 0) *firstlen = (off_t) cablen_u32; 724 if (caboff == 0) *firstlen = (off_t) cablen_u32;
705 725
706 /* check that the files offset is less than the alleged length of 726 /* check that the files offset is less than the alleged length of
707 * the cabinet, and that the offset + the alleged length are 727 * the cabinet, and that the offset + the alleged length are
708 * 'roughly' within the end of overall file length */ 728 * 'roughly' within the end of overall file length. In salvage
709 if ((foffset_u32 < cablen_u32) && 729 * mode, don't check the alleged length, allow it to be garbage */
710 ((caboff + (off_t) foffset_u32) < (flen + 32)) && 730 if ((foffset_u32 < cablen_u32) &&
711 ((caboff + (off_t) cablen_u32) < (flen + 32)) ) 731 ((caboff + (off_t) foffset_u32) < (flen + 32)) &&
712 { 732 (((caboff + (off_t) cablen_u32) < (flen + 32)) || self->salvage))
713 /* likely cabinet found -- try reading it */ 733 {
714 if (!(cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) { 734 /* likely cabinet found -- try reading it */
715 return MSPACK_ERR_NOMEMORY; 735 if (!(cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
716 } 736 return MSPACK_ERR_NOMEMORY;
717 cab->base.filename = filename; 737 }
718 if (cabd_read_headers(sys, fh, cab, caboff, 1)) { 738 cab->base.filename = filename;
719 /* destroy the failed cabinet */ 739 if (cabd_read_headers(sys, fh, cab, caboff, self->salvage, 1)) {
720 cabd_close((struct mscab_decompressor *) self, 740 /* destroy the failed cabinet */
721 (struct mscabd_cabinet *) cab); 741 cabd_close((struct mscab_decompressor *) self,
722 false_cabs++; 742 (struct mscabd_cabinet *) cab);
723 } 743 false_cabs++;
724 else { 744 }
725 /* cabinet read correctly! */ 745 else {
726 746 /* cabinet read correctly! */
727 /* link the cab into the list */ 747
728 if (!link) *firstcab = cab; 748 /* link the cab into the list */
729 else link->base.next = (struct mscabd_cabinet *) cab; 749 if (!link) *firstcab = cab;
730 link = cab; 750 else link->base.next = (struct mscabd_cabinet *) cab;
731 751 link = cab;
732 /* cause the search to restart after this cab's data. */ 752
733 offset = caboff + (off_t) cablen_u32; 753 /* cause the search to restart after this cab's data. */
734 754 offset = caboff + (off_t) cablen_u32;
735#ifndef LARGEFILE_SUPPORT 755
736 /* detect 32-bit off_t overflow */ 756#if !LARGEFILE_SUPPORT
737 if (offset < caboff) { 757 /* detect 32-bit off_t overflow */
738 sys->message(fh, largefile_msg); 758 if (offset < caboff) {
739 return MSPACK_ERR_OK; 759 sys->message(fh, largefile_msg);
740 } 760 return MSPACK_ERR_OK;
741#endif 761 }
742 } 762#endif
743 } 763 }
744 764 }
745 /* restart search */ 765
746 if (offset >= flen) return MSPACK_ERR_OK; 766 /* restart search */
747 if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) { 767 if (offset >= flen) return MSPACK_ERR_OK;
748 return MSPACK_ERR_SEEK; 768 if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
749 } 769 return MSPACK_ERR_SEEK;
750 length = 0; 770 }
751 p = pend; 771 length = 0;
752 state = 0; 772 p = pend;
753 break; 773 state = 0;
774 break;
754 775
755 /* for bytes 4-7 and 12-15, just advance state/pointer */ 776 /* for bytes 4-7 and 12-15, just advance state/pointer */
756 default: 777 default:
757 p++, state++; 778 p++, state++;
758 } /* switch(state) */ 779 } /* switch(state) */
759 } /* for (... p < pend ...) */ 780 } /* for (... p < pend ...) */
760 } /* for (... offset < length ...) */ 781 } /* for (... offset < length ...) */
@@ -765,7 +786,7 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
765 786
766 return MSPACK_ERR_OK; 787 return MSPACK_ERR_OK;
767} 788}
768 789
769/*************************************** 790/***************************************
770 * CABD_MERGE, CABD_PREPEND, CABD_APPEND 791 * CABD_MERGE, CABD_PREPEND, CABD_APPEND
771 *************************************** 792 ***************************************
@@ -775,22 +796,22 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
775 * merged folder's data parts list. 796 * merged folder's data parts list.
776 */ 797 */
777static int cabd_prepend(struct mscab_decompressor *base, 798static int cabd_prepend(struct mscab_decompressor *base,
778 struct mscabd_cabinet *cab, 799 struct mscabd_cabinet *cab,
779 struct mscabd_cabinet *prevcab) 800 struct mscabd_cabinet *prevcab)
780{ 801{
781 return cabd_merge(base, prevcab, cab); 802 return cabd_merge(base, prevcab, cab);
782} 803}
783 804
784static int cabd_append(struct mscab_decompressor *base, 805static int cabd_append(struct mscab_decompressor *base,
785 struct mscabd_cabinet *cab, 806 struct mscabd_cabinet *cab,
786 struct mscabd_cabinet *nextcab) 807 struct mscabd_cabinet *nextcab)
787{ 808{
788 return cabd_merge(base, cab, nextcab); 809 return cabd_merge(base, cab, nextcab);
789} 810}
790 811
791static int cabd_merge(struct mscab_decompressor *base, 812static int cabd_merge(struct mscab_decompressor *base,
792 struct mscabd_cabinet *lcab, 813 struct mscabd_cabinet *lcab,
793 struct mscabd_cabinet *rcab) 814 struct mscabd_cabinet *rcab)
794{ 815{
795 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base; 816 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
796 struct mscabd_folder_data *data, *ndata; 817 struct mscabd_folder_data *data, *ndata;
@@ -880,7 +901,7 @@ static int cabd_merge(struct mscab_decompressor *base,
880 * instead */ 901 * instead */
881 lfol->base.num_blocks += rfol->base.num_blocks - 1; 902 lfol->base.num_blocks += rfol->base.num_blocks - 1;
882 if ((rfol->merge_next == NULL) || 903 if ((rfol->merge_next == NULL) ||
883 (rfol->merge_next->folder != (struct mscabd_folder *) rfol)) 904 (rfol->merge_next->folder != (struct mscabd_folder *) rfol))
884 { 905 {
885 lfol->merge_next = rfol->merge_next; 906 lfol->merge_next = rfol->merge_next;
886 } 907 }
@@ -903,9 +924,9 @@ static int cabd_merge(struct mscab_decompressor *base,
903 rfi = fi->next; 924 rfi = fi->next;
904 /* if file's folder matches the merge folder, unlink and free it */ 925 /* if file's folder matches the merge folder, unlink and free it */
905 if (fi->folder == (struct mscabd_folder *) rfol) { 926 if (fi->folder == (struct mscabd_folder *) rfol) {
906 if (lfi) lfi->next = rfi; else lcab->files = rfi; 927 if (lfi) lfi->next = rfi; else lcab->files = rfi;
907 sys->free(fi->filename); 928 sys->free(fi->filename);
908 sys->free(fi); 929 sys->free(fi);
909 } 930 }
910 else lfi = fi; 931 else lfi = fi;
911 } 932 }
@@ -940,6 +961,12 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
940 return 0; 961 return 0;
941 } 962 }
942 963
964 /* check there are not too many data blocks after merging */
965 if ((lfol->base.num_blocks + rfol->base.num_blocks) > CAB_FOLDERMAX) {
966 D(("folder merge: too many data blocks in merged folders"))
967 return 0;
968 }
969
943 if (!(lfi = lfol->merge_next) || !(rfi = rfol->merge_prev)) { 970 if (!(lfi = lfol->merge_next) || !(rfi = rfol->merge_prev)) {
944 D(("folder merge: one cabinet has no files to merge")) 971 D(("folder merge: one cabinet has no files to merge"))
945 return 0; 972 return 0;
@@ -950,10 +977,10 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
950 * should be identical in number and order. to verify this, check the 977 * should be identical in number and order. to verify this, check the
951 * offset and length of each file. */ 978 * offset and length of each file. */
952 for (l=lfi, r=rfi; l; l=l->next, r=r->next) { 979 for (l=lfi, r=rfi; l; l=l->next, r=r->next) {
953 if (!r || (l->offset != r->offset) || (l->length != r->length)) { 980 if (!r || (l->offset != r->offset) || (l->length != r->length)) {
954 matching = 0; 981 matching = 0;
955 break; 982 break;
956 } 983 }
957 } 984 }
958 985
959 if (matching) return 1; 986 if (matching) return 1;
@@ -963,9 +990,9 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
963 * the merge with a warning about missing files. */ 990 * the merge with a warning about missing files. */
964 matching = 0; 991 matching = 0;
965 for (l = lfi; l; l = l->next) { 992 for (l = lfi; l; l = l->next) {
966 for (r = rfi; r; r = r->next) { 993 for (r = rfi; r; r = r->next) {
967 if (l->offset == r->offset && l->length == r->length) break; 994 if (l->offset == r->offset && l->length == r->length) break;
968 } 995 }
969 if (r) matching = 1; else sys->message(NULL, 996 if (r) matching = 1; else sys->message(NULL,
970 "WARNING; merged file %s not listed in both cabinets", l->filename); 997 "WARNING; merged file %s not listed in both cabinets", l->filename);
971 } 998 }
@@ -985,6 +1012,7 @@ static int cabd_extract(struct mscab_decompressor *base,
985 struct mscabd_folder_p *fol; 1012 struct mscabd_folder_p *fol;
986 struct mspack_system *sys; 1013 struct mspack_system *sys;
987 struct mspack_file *fh; 1014 struct mspack_file *fh;
1015 off_t filelen;
988 1016
989 if (!self) return MSPACK_ERR_ARGS; 1017 if (!self) return MSPACK_ERR_ARGS;
990 if (!file) return self->error = MSPACK_ERR_ARGS; 1018 if (!file) return self->error = MSPACK_ERR_ARGS;
@@ -992,15 +1020,43 @@ static int cabd_extract(struct mscab_decompressor *base,
992 sys = self->system; 1020 sys = self->system;
993 fol = (struct mscabd_folder_p *) file->folder; 1021 fol = (struct mscabd_folder_p *) file->folder;
994 1022
995 /* check if file can be extracted */ 1023 /* if offset is beyond 2GB, nothing can be extracted */
996 if ((!fol) || (fol->merge_prev) || 1024 if (file->offset > CAB_LENGTHMAX) {
997 (((file->offset + file->length) / CAB_BLOCKMAX) > fol->base.num_blocks))
998 {
999 sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
1000 "cabinet set is incomplete.", file->filename);
1001 return self->error = MSPACK_ERR_DATAFORMAT; 1025 return self->error = MSPACK_ERR_DATAFORMAT;
1002 } 1026 }
1003 1027
1028 /* if file claims to go beyond 2GB either error out,
1029 * or in salvage mode reduce file length so it fits 2GB limit
1030 */
1031 filelen = file->length;
1032 if (filelen > CAB_LENGTHMAX || (file->offset + filelen) > CAB_LENGTHMAX) {
1033 if (self->salvage) {
1034 filelen = CAB_LENGTHMAX - file->offset;
1035 }
1036 else {
1037 return self->error = MSPACK_ERR_DATAFORMAT;
1038 }
1039 }
1040
1041 /* extraction impossible if no folder, or folder needs predecessor */
1042 if (!fol || fol->merge_prev) {
1043 sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
1044 "cabinet set is incomplete", file->filename);
1045 return self->error = MSPACK_ERR_DECRUNCH;
1046 }
1047
1048 /* if file goes beyond what can be decoded, given an error.
1049 * In salvage mode, don't assume block sizes, just try decoding
1050 */
1051 if (!self->salvage) {
1052 off_t maxlen = fol->base.num_blocks * CAB_BLOCKMAX;
1053 if ((file->offset + filelen) > maxlen) {
1054 sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
1055 "cabinet set is incomplete", file->filename);
1056 return self->error = MSPACK_ERR_DECRUNCH;
1057 }
1058 }
1059
1004 /* allocate generic decompression state */ 1060 /* allocate generic decompression state */
1005 if (!self->d) { 1061 if (!self->d) {
1006 self->d = (struct mscabd_decompress_state *) sys->alloc(sys, sizeof(struct mscabd_decompress_state)); 1062 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,
1016 } 1072 }
1017 1073
1018 /* do we need to change folder or reset the current folder? */ 1074 /* do we need to change folder or reset the current folder? */
1019 if ((self->d->folder != fol) || (self->d->offset > file->offset)) { 1075 if ((self->d->folder != fol) || (self->d->offset > file->offset) ||
1076 !self->d->state)
1077 {
1078 /* free any existing decompressor */
1079 cabd_free_decomp(self);
1080
1020 /* do we need to open a new cab file? */ 1081 /* do we need to open a new cab file? */
1021 if (!self->d->infh || (fol->data.cab != self->d->incab)) { 1082 if (!self->d->infh || (fol->data.cab != self->d->incab)) {
1022 /* close previous file handle if from a different cab */ 1083 /* close previous file handle if from a different cab */
1023 if (self->d->infh) sys->close(self->d->infh); 1084 if (self->d->infh) sys->close(self->d->infh);
1024 self->d->incab = fol->data.cab; 1085 self->d->incab = fol->data.cab;
1025 self->d->infh = sys->open(sys, fol->data.cab->base.filename, 1086 self->d->infh = sys->open(sys, fol->data.cab->base.filename,
1026 MSPACK_SYS_OPEN_READ); 1087 MSPACK_SYS_OPEN_READ);
1027 if (!self->d->infh) return self->error = MSPACK_ERR_OPEN; 1088 if (!self->d->infh) return self->error = MSPACK_ERR_OPEN;
1028 } 1089 }
1029 /* seek to start of data blocks */ 1090 /* seek to start of data blocks */
@@ -1041,6 +1102,7 @@ static int cabd_extract(struct mscab_decompressor *base,
1041 self->d->data = &fol->data; 1102 self->d->data = &fol->data;
1042 self->d->offset = 0; 1103 self->d->offset = 0;
1043 self->d->block = 0; 1104 self->d->block = 0;
1105 self->d->outlen = 0;
1044 self->d->i_ptr = self->d->i_end = &self->d->input[0]; 1106 self->d->i_ptr = self->d->i_end = &self->d->input[0];
1045 1107
1046 /* read_error lasts for the lifetime of a decompressor */ 1108 /* read_error lasts for the lifetime of a decompressor */
@@ -1055,7 +1117,7 @@ static int cabd_extract(struct mscab_decompressor *base,
1055 self->error = MSPACK_ERR_OK; 1117 self->error = MSPACK_ERR_OK;
1056 1118
1057 /* if file has more than 0 bytes */ 1119 /* if file has more than 0 bytes */
1058 if (file->length) { 1120 if (filelen) {
1059 off_t bytes; 1121 off_t bytes;
1060 int error; 1122 int error;
1061 /* get to correct offset. 1123 /* get to correct offset.
@@ -1065,14 +1127,14 @@ static int cabd_extract(struct mscab_decompressor *base,
1065 */ 1127 */
1066 self->d->outfh = NULL; 1128 self->d->outfh = NULL;
1067 if ((bytes = file->offset - self->d->offset)) { 1129 if ((bytes = file->offset - self->d->offset)) {
1068 error = self->d->decompress(self->d->state, bytes); 1130 error = self->d->decompress(self->d->state, bytes);
1069 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error; 1131 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
1070 } 1132 }
1071 1133
1072 /* if getting to the correct offset was error free, unpack file */ 1134 /* if getting to the correct offset was error free, unpack file */
1073 if (!self->error) { 1135 if (!self->error) {
1074 self->d->outfh = fh; 1136 self->d->outfh = fh;
1075 error = self->d->decompress(self->d->state, (off_t) file->length); 1137 error = self->d->decompress(self->d->state, filelen);
1076 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error; 1138 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
1077 } 1139 }
1078 } 1140 }
@@ -1098,34 +1160,27 @@ static int cabd_init_decomp(struct mscab_decompressor_p *self, unsigned int ct)
1098{ 1160{
1099 struct mspack_file *fh = (struct mspack_file *) self; 1161 struct mspack_file *fh = (struct mspack_file *) self;
1100 1162
1101 assert(self && self->d);
1102
1103 /* free any existing decompressor */
1104 cabd_free_decomp(self);
1105
1106 self->d->comp_type = ct; 1163 self->d->comp_type = ct;
1107 1164
1108 switch (ct & cffoldCOMPTYPE_MASK) { 1165 switch (ct & cffoldCOMPTYPE_MASK) {
1109 case cffoldCOMPTYPE_NONE: 1166 case cffoldCOMPTYPE_NONE:
1110 self->d->decompress = (int (*)(void *, off_t)) &noned_decompress; 1167 self->d->decompress = (int (*)(void *, off_t)) &noned_decompress;
1111 self->d->state = noned_init(&self->d->sys, fh, fh, 1168 self->d->state = noned_init(&self->d->sys, fh, fh, self->buf_size);
1112 self->param[MSCABD_PARAM_DECOMPBUF]);
1113 break; 1169 break;
1114 case cffoldCOMPTYPE_MSZIP: 1170 case cffoldCOMPTYPE_MSZIP:
1115 self->d->decompress = (int (*)(void *, off_t)) &mszipd_decompress; 1171 self->d->decompress = (int (*)(void *, off_t)) &mszipd_decompress;
1116 self->d->state = mszipd_init(&self->d->sys, fh, fh, 1172 self->d->state = mszipd_init(&self->d->sys, fh, fh, self->buf_size,
1117 self->param[MSCABD_PARAM_DECOMPBUF], 1173 self->fix_mszip);
1118 self->param[MSCABD_PARAM_FIXMSZIP]);
1119 break; 1174 break;
1120 case cffoldCOMPTYPE_QUANTUM: 1175 case cffoldCOMPTYPE_QUANTUM:
1121 self->d->decompress = (int (*)(void *, off_t)) &qtmd_decompress; 1176 self->d->decompress = (int (*)(void *, off_t)) &qtmd_decompress;
1122 self->d->state = qtmd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f, 1177 self->d->state = qtmd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f,
1123 self->param[MSCABD_PARAM_DECOMPBUF]); 1178 self->buf_size);
1124 break; 1179 break;
1125 case cffoldCOMPTYPE_LZX: 1180 case cffoldCOMPTYPE_LZX:
1126 self->d->decompress = (int (*)(void *, off_t)) &lzxd_decompress; 1181 self->d->decompress = (int (*)(void *, off_t)) &lzxd_decompress;
1127 self->d->state = lzxd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f, 0, 1182 self->d->state = lzxd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f, 0,
1128 self->param[MSCABD_PARAM_DECOMPBUF], (off_t) 0); 1183 self->buf_size, (off_t)0,0);
1129 break; 1184 break;
1130 default: 1185 default:
1131 return self->error = MSPACK_ERR_DATAFORMAT; 1186 return self->error = MSPACK_ERR_DATAFORMAT;
@@ -1134,7 +1189,7 @@ static int cabd_init_decomp(struct mscab_decompressor_p *self, unsigned int ct)
1134} 1189}
1135 1190
1136static void cabd_free_decomp(struct mscab_decompressor_p *self) { 1191static void cabd_free_decomp(struct mscab_decompressor_p *self) {
1137 if (!self || !self->d || !self->d->folder || !self->d->state) return; 1192 if (!self || !self->d || !self->d->state) return;
1138 1193
1139 switch (self->d->comp_type & cffoldCOMPTYPE_MASK) { 1194 switch (self->d->comp_type & cffoldCOMPTYPE_MASK) {
1140 case cffoldCOMPTYPE_NONE: noned_free((struct noned_state *) self->d->state); break; 1195 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) {
1162 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file; 1217 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file;
1163 unsigned char *buf = (unsigned char *) buffer; 1218 unsigned char *buf = (unsigned char *) buffer;
1164 struct mspack_system *sys = self->system; 1219 struct mspack_system *sys = self->system;
1165 int avail, todo, outlen, ignore_cksum; 1220 int avail, todo, outlen, ignore_cksum, ignore_blocksize;
1166 1221
1167 ignore_cksum = self->param[MSCABD_PARAM_FIXMSZIP] && 1222 ignore_cksum = self->salvage ||
1168 ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP); 1223 (self->fix_mszip &&
1224 ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP));
1225 ignore_blocksize = self->salvage;
1169 1226
1170 todo = bytes; 1227 todo = bytes;
1171 while (todo > 0) { 1228 while (todo > 0) {
@@ -1185,37 +1242,35 @@ static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) {
1185 1242
1186 /* check if we're out of input blocks, advance block counter */ 1243 /* check if we're out of input blocks, advance block counter */
1187 if (self->d->block++ >= self->d->folder->base.num_blocks) { 1244 if (self->d->block++ >= self->d->folder->base.num_blocks) {
1188 self->read_error = MSPACK_ERR_DATAFORMAT; 1245 if (!self->salvage) {
1189 break; 1246 self->read_error = MSPACK_ERR_DATAFORMAT;
1247 }
1248 else {
1249 D(("Ran out of CAB input blocks prematurely"))
1250 }
1251 break;
1190 } 1252 }
1191 1253
1192 /* read a block */ 1254 /* read a block */
1193 self->read_error = cabd_sys_read_block(sys, self->d, &outlen, ignore_cksum); 1255 self->read_error = cabd_sys_read_block(sys, self->d, &outlen,
1256 ignore_cksum, ignore_blocksize);
1194 if (self->read_error) return -1; 1257 if (self->read_error) return -1;
1258 self->d->outlen += outlen;
1195 1259
1196 /* special Quantum hack -- trailer byte to allow the decompressor 1260 /* special Quantum hack -- trailer byte to allow the decompressor
1197 * to realign itself. CAB Quantum blocks, unlike LZX blocks, can have 1261 * to realign itself. CAB Quantum blocks, unlike LZX blocks, can have
1198 * anything from 0 to 4 trailing null bytes. */ 1262 * anything from 0 to 4 trailing null bytes. */
1199 if ((self->d->comp_type & cffoldCOMPTYPE_MASK)==cffoldCOMPTYPE_QUANTUM) { 1263 if ((self->d->comp_type & cffoldCOMPTYPE_MASK)==cffoldCOMPTYPE_QUANTUM) {
1200 *self->d->i_end++ = 0xFF; 1264 *self->d->i_end++ = 0xFF;
1201 } 1265 }
1202 1266
1203 /* is this the last block? */ 1267 /* is this the last block? */
1204 if (self->d->block >= self->d->folder->base.num_blocks) { 1268 if (self->d->block >= self->d->folder->base.num_blocks) {
1205 /* last block */ 1269 if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) {
1206 if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) { 1270 /* special LZX hack -- on the last block, inform LZX of the
1207 /* special LZX hack -- on the last block, inform LZX of the 1271 * size of the output data stream. */
1208 * size of the output data stream. */ 1272 lzxd_set_output_length((struct lzxd_stream *) self->d->state, self->d->outlen);
1209 lzxd_set_output_length((struct lzxd_stream *) self->d->state, (off_t) 1273 }
1210 ((self->d->block-1) * CAB_BLOCKMAX + outlen));
1211 }
1212 }
1213 else {
1214 /* not the last block */
1215 if (outlen != CAB_BLOCKMAX) {
1216 self->system->message(self->d->infh,
1217 "WARNING; non-maximal data block");
1218 }
1219 } 1274 }
1220 } /* if (avail) */ 1275 } /* if (avail) */
1221 } /* while (todo > 0) */ 1276 } /* while (todo > 0) */
@@ -1238,12 +1293,13 @@ static int cabd_sys_write(struct mspack_file *file, void *buffer, int bytes) {
1238 * one cab file, if it does then the fragments will be reassembled 1293 * one cab file, if it does then the fragments will be reassembled
1239 */ 1294 */
1240static int cabd_sys_read_block(struct mspack_system *sys, 1295static int cabd_sys_read_block(struct mspack_system *sys,
1241 struct mscabd_decompress_state *d, 1296 struct mscabd_decompress_state *d,
1242 int *out, int ignore_cksum) 1297 int *out, int ignore_cksum,
1298 int ignore_blocksize)
1243{ 1299{
1244 unsigned char hdr[cfdata_SIZEOF]; 1300 unsigned char hdr[cfdata_SIZEOF];
1245 unsigned int cksum; 1301 unsigned int cksum;
1246 int len; 1302 int len, full_len;
1247 1303
1248 /* reset the input block pointer and end of block pointer */ 1304 /* reset the input block pointer and end of block pointer */
1249 d->i_ptr = d->i_end = &d->input[0]; 1305 d->i_ptr = d->i_end = &d->input[0];
@@ -1256,23 +1312,27 @@ static int cabd_sys_read_block(struct mspack_system *sys,
1256 1312
1257 /* skip any reserved block headers */ 1313 /* skip any reserved block headers */
1258 if (d->data->cab->block_resv && 1314 if (d->data->cab->block_resv &&
1259 sys->seek(d->infh, (off_t) d->data->cab->block_resv, 1315 sys->seek(d->infh, (off_t) d->data->cab->block_resv,
1260 MSPACK_SYS_SEEK_CUR)) 1316 MSPACK_SYS_SEEK_CUR))
1261 { 1317 {
1262 return MSPACK_ERR_SEEK; 1318 return MSPACK_ERR_SEEK;
1263 } 1319 }
1264 1320
1265 /* blocks must not be over CAB_INPUTMAX in size */ 1321 /* blocks must not be over CAB_INPUTMAX in size */
1266 len = EndGetI16(&hdr[cfdata_CompressedSize]); 1322 len = EndGetI16(&hdr[cfdata_CompressedSize]);
1267 if (((d->i_end - d->i_ptr) + len) > CAB_INPUTMAX) { 1323 full_len = (d->i_end - d->i_ptr) + len; /* include cab-spanning blocks */
1268 D(("block size > CAB_INPUTMAX (%ld + %d)", d->i_end - d->i_ptr, len)) 1324 if (full_len > CAB_INPUTMAX) {
1269 return MSPACK_ERR_DATAFORMAT; 1325 D(("block size %d > CAB_INPUTMAX", full_len));
1326 /* in salvage mode, blocks can be 65535 bytes but no more than that */
1327 if (!ignore_blocksize || full_len > CAB_INPUTMAX_SALVAGE) {
1328 return MSPACK_ERR_DATAFORMAT;
1329 }
1270 } 1330 }
1271 1331
1272 /* blocks must not expand to more than CAB_BLOCKMAX */ 1332 /* blocks must not expand to more than CAB_BLOCKMAX */
1273 if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) { 1333 if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) {
1274 D(("block size > CAB_BLOCKMAX")) 1334 D(("block size > CAB_BLOCKMAX"))
1275 return MSPACK_ERR_DATAFORMAT; 1335 if (!ignore_blocksize) return MSPACK_ERR_DATAFORMAT;
1276 } 1336 }
1277 1337
1278 /* read the block data */ 1338 /* read the block data */
@@ -1284,8 +1344,8 @@ static int cabd_sys_read_block(struct mspack_system *sys,
1284 if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) { 1344 if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) {
1285 unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0); 1345 unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0);
1286 if (cabd_checksum(&hdr[4], 4, sum2) != cksum) { 1346 if (cabd_checksum(&hdr[4], 4, sum2) != cksum) {
1287 if (!ignore_cksum) return MSPACK_ERR_CHECKSUM; 1347 if (!ignore_cksum) return MSPACK_ERR_CHECKSUM;
1288 sys->message(d->infh, "WARNING; bad block checksum found"); 1348 sys->message(d->infh, "WARNING; bad block checksum found");
1289 } 1349 }
1290 } 1350 }
1291 1351
@@ -1310,14 +1370,14 @@ static int cabd_sys_read_block(struct mspack_system *sys,
1310 1370
1311 /* advance to next member in the cabinet set */ 1371 /* advance to next member in the cabinet set */
1312 if (!(d->data = d->data->next)) { 1372 if (!(d->data = d->data->next)) {
1313 D(("ran out of splits in cabinet set")) 1373 sys->message(d->infh, "WARNING; ran out of cabinets in set. Are any missing?");
1314 return MSPACK_ERR_DATAFORMAT; 1374 return MSPACK_ERR_DATAFORMAT;
1315 } 1375 }
1316 1376
1317 /* open next cab file */ 1377 /* open next cab file */
1318 d->incab = d->data->cab; 1378 d->incab = d->data->cab;
1319 if (!(d->infh = sys->open(sys, d->incab->base.filename, 1379 if (!(d->infh = sys->open(sys, d->incab->base.filename,
1320 MSPACK_SYS_OPEN_READ))) 1380 MSPACK_SYS_OPEN_READ)))
1321 { 1381 {
1322 return MSPACK_ERR_OPEN; 1382 return MSPACK_ERR_OPEN;
1323 } 1383 }
@@ -1333,7 +1393,7 @@ static int cabd_sys_read_block(struct mspack_system *sys,
1333} 1393}
1334 1394
1335static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes, 1395static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
1336 unsigned int cksum) 1396 unsigned int cksum)
1337{ 1397{
1338 unsigned int len, ul = 0; 1398 unsigned int len, ul = 0;
1339 1399
@@ -1342,8 +1402,8 @@ static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
1342 } 1402 }
1343 1403
1344 switch (bytes & 3) { 1404 switch (bytes & 3) {
1345 case 3: ul |= *data++ << 16; 1405 case 3: ul |= *data++ << 16; /*@fallthrough@*/
1346 case 2: ul |= *data++ << 8; 1406 case 2: ul |= *data++ << 8; /*@fallthrough@*/
1347 case 1: ul |= *data; 1407 case 1: ul |= *data;
1348 } 1408 }
1349 cksum ^= ul; 1409 cksum ^= ul;
@@ -1365,9 +1425,9 @@ struct noned_state {
1365}; 1425};
1366 1426
1367static struct noned_state *noned_init(struct mspack_system *sys, 1427static struct noned_state *noned_init(struct mspack_system *sys,
1368 struct mspack_file *in, 1428 struct mspack_file *in,
1369 struct mspack_file *out, 1429 struct mspack_file *out,
1370 int bufsize) 1430 int bufsize)
1371{ 1431{
1372 struct noned_state *state = (struct noned_state *) sys->alloc(sys, sizeof(struct noned_state)); 1432 struct noned_state *state = (struct noned_state *) sys->alloc(sys, sizeof(struct noned_state));
1373 unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) bufsize); 1433 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) {
1419 switch (param) { 1479 switch (param) {
1420 case MSCABD_PARAM_SEARCHBUF: 1480 case MSCABD_PARAM_SEARCHBUF:
1421 if (value < 4) return MSPACK_ERR_ARGS; 1481 if (value < 4) return MSPACK_ERR_ARGS;
1422 self->param[MSCABD_PARAM_SEARCHBUF] = value; 1482 self->searchbuf_size = value;
1423 break; 1483 break;
1424 case MSCABD_PARAM_FIXMSZIP: 1484 case MSCABD_PARAM_FIXMSZIP:
1425 self->param[MSCABD_PARAM_FIXMSZIP] = value; 1485 self->fix_mszip = value;
1426 break; 1486 break;
1427 case MSCABD_PARAM_DECOMPBUF: 1487 case MSCABD_PARAM_DECOMPBUF:
1428 if (value < 4) return MSPACK_ERR_ARGS; 1488 if (value < 4) return MSPACK_ERR_ARGS;
1429 self->param[MSCABD_PARAM_DECOMPBUF] = value; 1489 self->buf_size = value;
1490 break;
1491 case MSCABD_PARAM_SALVAGE:
1492 self->salvage = value;
1430 break; 1493 break;
1431 default: 1494 default:
1432 return MSPACK_ERR_ARGS; 1495 return MSPACK_ERR_ARGS;
diff --git a/rbutil/rbutilqt/mspack/chmd.c b/rbutil/rbutilqt/mspack/chmd.c
index 416156e742..6c8481db14 100644
--- a/rbutil/rbutilqt/mspack/chmd.c
+++ b/rbutil/rbutilqt/mspack/chmd.c
@@ -1,5 +1,5 @@
1/* This file is part of libmspack. 1/* This file is part of libmspack.
2 * (C) 2003-2011 Stuart Caie. 2 * (C) 2003-2018 Stuart Caie.
3 * 3 *
4 * libmspack is free software; you can redistribute it and/or modify it under 4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1 5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
@@ -44,7 +44,7 @@ static int chmd_init_decomp(
44 struct mschm_decompressor_p *self, struct mschmd_file *file); 44 struct mschm_decompressor_p *self, struct mschmd_file *file);
45static int read_reset_table( 45static int read_reset_table(
46 struct mschm_decompressor_p *self, struct mschmd_sec_mscompressed *sec, 46 struct mschm_decompressor_p *self, struct mschmd_sec_mscompressed *sec,
47 int entry, off_t *length_ptr, off_t *offset_ptr); 47 unsigned int entry, off_t *length_ptr, off_t *offset_ptr);
48static int read_spaninfo( 48static int read_spaninfo(
49 struct mschm_decompressor_p *self, struct mschmd_sec_mscompressed *sec, 49 struct mschm_decompressor_p *self, struct mschmd_sec_mscompressed *sec,
50 off_t *length_ptr); 50 off_t *length_ptr);
@@ -121,7 +121,7 @@ void mspack_destroy_chm_decompressor(struct mschm_decompressor *base) {
121 * Calls chmd_real_open() with entire=1. 121 * Calls chmd_real_open() with entire=1.
122 */ 122 */
123static struct mschmd_header *chmd_open(struct mschm_decompressor *base, 123static struct mschmd_header *chmd_open(struct mschm_decompressor *base,
124 const char *filename) 124 const char *filename)
125{ 125{
126 return chmd_real_open(base, filename, 1); 126 return chmd_real_open(base, filename, 1);
127} 127}
@@ -133,7 +133,7 @@ static struct mschmd_header *chmd_open(struct mschm_decompressor *base,
133 * the file headers. Calls chmd_real_open() with entire=0 133 * the file headers. Calls chmd_real_open() with entire=0
134 */ 134 */
135static struct mschmd_header *chmd_fast_open(struct mschm_decompressor *base, 135static struct mschmd_header *chmd_fast_open(struct mschm_decompressor *base,
136 const char *filename) 136 const char *filename)
137{ 137{
138 return chmd_real_open(base, filename, 0); 138 return chmd_real_open(base, filename, 0);
139} 139}
@@ -146,7 +146,7 @@ static struct mschmd_header *chmd_fast_open(struct mschm_decompressor *base,
146 * either read all headers, or a bare mininum. 146 * either read all headers, or a bare mininum.
147 */ 147 */
148static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base, 148static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base,
149 const char *filename, int entire) 149 const char *filename, int entire)
150{ 150{
151 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base; 151 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
152 struct mschmd_header *chm = NULL; 152 struct mschmd_header *chm = NULL;
@@ -162,16 +162,16 @@ static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base,
162 chm->filename = filename; 162 chm->filename = filename;
163 error = chmd_read_headers(sys, fh, chm, entire); 163 error = chmd_read_headers(sys, fh, chm, entire);
164 if (error) { 164 if (error) {
165 /* if the error is DATAFORMAT, and there are some results, return 165 /* if the error is DATAFORMAT, and there are some results, return
166 * partial results with a warning, rather than nothing */ 166 * partial results with a warning, rather than nothing */
167 if (error == MSPACK_ERR_DATAFORMAT && (chm->files || chm->sysfiles)) { 167 if (error == MSPACK_ERR_DATAFORMAT && (chm->files || chm->sysfiles)) {
168 sys->message(fh, "WARNING; contents are corrupt"); 168 sys->message(fh, "WARNING; contents are corrupt");
169 error = MSPACK_ERR_OK; 169 error = MSPACK_ERR_OK;
170 } 170 }
171 else { 171 else {
172 chmd_close(base, chm); 172 chmd_close(base, chm);
173 chm = NULL; 173 chm = NULL;
174 } 174 }
175 } 175 }
176 self->error = error; 176 self->error = error;
177 } 177 }
@@ -192,7 +192,7 @@ static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base,
192 * frees all memory associated with a given mschmd_header 192 * frees all memory associated with a given mschmd_header
193 */ 193 */
194static void chmd_close(struct mschm_decompressor *base, 194static void chmd_close(struct mschm_decompressor *base,
195 struct mschmd_header *chm) 195 struct mschmd_header *chm)
196{ 196{
197 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base; 197 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
198 struct mschmd_file *fi, *nfi; 198 struct mschmd_file *fi, *nfi;
@@ -251,16 +251,16 @@ static const unsigned char guids[32] = {
251 251
252/* reads an encoded integer into a variable; 7 bits of data per byte, 252/* reads an encoded integer into a variable; 7 bits of data per byte,
253 * the high bit is used to indicate that there is another byte */ 253 * the high bit is used to indicate that there is another byte */
254#define READ_ENCINT(var) do { \ 254#define READ_ENCINT(var) do { \
255 (var) = 0; \ 255 (var) = 0; \
256 do { \ 256 do { \
257 if (p > end) goto chunk_end; \ 257 if (p >= end) goto chunk_end; \
258 (var) = ((var) << 7) | (*p & 0x7F); \ 258 (var) = ((var) << 7) | (*p & 0x7F); \
259 } while (*p++ & 0x80); \ 259 } while (*p++ & 0x80); \
260} while (0) 260} while (0)
261 261
262static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh, 262static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
263 struct mschmd_header *chm, int entire) 263 struct mschmd_header *chm, int entire)
264{ 264{
265 unsigned int section, name_len, x, errors, num_chunks; 265 unsigned int section, name_len, x, errors, num_chunks;
266 unsigned char buf[0x54], *chunk = NULL, *name, *p, *end; 266 unsigned char buf[0x54], *chunk = NULL, *name, *p, *end;
@@ -292,7 +292,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
292 } 292 }
293 293
294 /* check both header GUIDs */ 294 /* check both header GUIDs */
295 if (mspack_memcmp(&buf[chmhead_GUID1], &guids[0], 32L) != 0) { 295 if (memcmp(&buf[chmhead_GUID1], &guids[0], 32L) != 0) {
296 D(("incorrect GUIDs")) 296 D(("incorrect GUIDs"))
297 return MSPACK_ERR_SIGNATURE; 297 return MSPACK_ERR_SIGNATURE;
298 } 298 }
@@ -356,8 +356,53 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
356 chm->sec0.offset = chm->dir_offset + (chm->chunk_size * chm->num_chunks); 356 chm->sec0.offset = chm->dir_offset + (chm->chunk_size * chm->num_chunks);
357 } 357 }
358 358
359 /* ensure chunk size is large enough for signature and num_entries */ 359 /* check if content offset or file size is wrong */
360 if (chm->sec0.offset > chm->length) {
361 D(("content section begins after file has ended"))
362 return MSPACK_ERR_DATAFORMAT;
363 }
364
365 /* ensure there are chunks and that chunk size is
366 * large enough for signature and num_entries */
360 if (chm->chunk_size < (pmgl_Entries + 2)) { 367 if (chm->chunk_size < (pmgl_Entries + 2)) {
368 D(("chunk size not large enough"))
369 return MSPACK_ERR_DATAFORMAT;
370 }
371 if (chm->num_chunks == 0) {
372 D(("no chunks"))
373 return MSPACK_ERR_DATAFORMAT;
374 }
375
376 /* The chunk_cache data structure is not great; large values for num_chunks
377 * or num_chunks*chunk_size can exhaust all memory. Until a better chunk
378 * cache is implemented, put arbitrary limits on num_chunks and chunk size.
379 */
380 if (chm->num_chunks > 100000) {
381 D(("more than 100,000 chunks"))
382 return MSPACK_ERR_DATAFORMAT;
383 }
384 if (chm->chunk_size > 8192) {
385 D(("chunk size over 8192 (get in touch if this is valid)"))
386 return MSPACK_ERR_DATAFORMAT;
387 }
388 if ((off_t)chm->chunk_size * (off_t)chm->num_chunks > chm->length) {
389 D(("chunks larger than entire file"))
390 return MSPACK_ERR_DATAFORMAT;
391 }
392
393 /* common sense checks on header section 1 fields */
394 if (chm->chunk_size != 4096) {
395 sys->message(fh, "WARNING; chunk size is not 4096");
396 }
397 if (chm->first_pmgl != 0) {
398 sys->message(fh, "WARNING; first PMGL chunk is not zero");
399 }
400 if (chm->first_pmgl > chm->last_pmgl) {
401 D(("first pmgl chunk is after last pmgl chunk"))
402 return MSPACK_ERR_DATAFORMAT;
403 }
404 if (chm->index_root != 0xFFFFFFFF && chm->index_root >= chm->num_chunks) {
405 D(("index_root outside valid range"))
361 return MSPACK_ERR_DATAFORMAT; 406 return MSPACK_ERR_DATAFORMAT;
362 } 407 }
363 408
@@ -394,7 +439,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
394 sys->message(fh, "WARNING; PMGL quickref area is too small"); 439 sys->message(fh, "WARNING; PMGL quickref area is too small");
395 } 440 }
396 if (EndGetI32(&chunk[pmgl_QuickRefSize]) > 441 if (EndGetI32(&chunk[pmgl_QuickRefSize]) >
397 ((int)chm->chunk_size - pmgl_Entries)) 442 (chm->chunk_size - pmgl_Entries))
398 { 443 {
399 sys->message(fh, "WARNING; PMGL quickref area is too large"); 444 sys->message(fh, "WARNING; PMGL quickref area is too large");
400 } 445 }
@@ -404,60 +449,63 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
404 num_entries = EndGetI16(end); 449 num_entries = EndGetI16(end);
405 450
406 while (num_entries--) { 451 while (num_entries--) {
407 READ_ENCINT(name_len); name = p; p += name_len; 452 READ_ENCINT(name_len);
453 if (name_len > (unsigned int) (end - p)) goto chunk_end;
454 name = p; p += name_len;
408 READ_ENCINT(section); 455 READ_ENCINT(section);
409 READ_ENCINT(offset); 456 READ_ENCINT(offset);
410 READ_ENCINT(length); 457 READ_ENCINT(length);
411 458
459 /* ignore blank or one-char (e.g. "/") filenames we'd return as blank */
460 if (name_len < 2 || !name[0] || !name[1]) continue;
461
412 /* empty files and directory names are stored as a file entry at 462 /* empty files and directory names are stored as a file entry at
413 * offset 0 with length 0. We want to keep empty files, but not 463 * offset 0 with length 0. We want to keep empty files, but not
414 * directory names, which end with a "/" */ 464 * directory names, which end with a "/" */
415 if ((offset == 0) && (length == 0)) { 465 if ((offset == 0) && (length == 0)) {
416 if ((name_len > 0) && (name[name_len-1] == '/')) continue; 466 if ((name_len > 0) && (name[name_len-1] == '/')) continue;
417 } 467 }
418 468
419 if (section > 1) { 469 if (section > 1) {
420 sys->message(fh, "invalid section number '%u'.", section); 470 sys->message(fh, "invalid section number '%u'.", section);
421 continue; 471 continue;
422 } 472 }
423 473
424 if (!(fi = (struct mschmd_file *) sys->alloc(sys, sizeof(struct mschmd_file) + name_len + 1))) { 474 if (!(fi = (struct mschmd_file *) sys->alloc(sys, sizeof(struct mschmd_file) + name_len + 1))) {
425 sys->free(chunk); 475 sys->free(chunk);
426 return MSPACK_ERR_NOMEMORY; 476 return MSPACK_ERR_NOMEMORY;
427 } 477 }
428 478
429 fi->next = NULL; 479 fi->next = NULL;
430 fi->filename = (char *) &fi[1]; 480 fi->filename = (char *) &fi[1];
431 fi->section = ((section == 0) ? (struct mschmd_section *) (&chm->sec0) 481 fi->section = ((section == 0) ? (struct mschmd_section *) (&chm->sec0)
432 : (struct mschmd_section *) (&chm->sec1)); 482 : (struct mschmd_section *) (&chm->sec1));
433 fi->offset = offset; 483 fi->offset = offset;
434 fi->length = length; 484 fi->length = length;
435 sys->copy(name, fi->filename, (size_t) name_len); 485 sys->copy(name, fi->filename, (size_t) name_len);
436 fi->filename[name_len] = '\0'; 486 fi->filename[name_len] = '\0';
437 487
438 if (name[0] == ':' && name[1] == ':') { 488 if (name[0] == ':' && name[1] == ':') {
439 /* system file */ 489 /* system file */
440 if (mspack_memcmp(&name[2], &content_name[2], 31L) == 0) { 490 if (name_len == 40 && memcmp(name, content_name, 40) == 0) {
441 if (mspack_memcmp(&name[33], &content_name[33], 8L) == 0) { 491 chm->sec1.content = fi;
442 chm->sec1.content = fi; 492 }
443 } 493 else if (name_len == 44 && memcmp(name, control_name, 44) == 0) {
444 else if (mspack_memcmp(&name[33], &control_name[33], 11L) == 0) { 494 chm->sec1.control = fi;
445 chm->sec1.control = fi; 495 }
446 } 496 else if (name_len == 41 && memcmp(name, spaninfo_name, 41) == 0) {
447 else if (mspack_memcmp(&name[33], &spaninfo_name[33], 8L) == 0) { 497 chm->sec1.spaninfo = fi;
448 chm->sec1.spaninfo = fi; 498 }
449 } 499 else if (name_len == 105 && memcmp(name, rtable_name, 105) == 0) {
450 else if (mspack_memcmp(&name[33], &rtable_name[33], 72L) == 0) { 500 chm->sec1.rtable = fi;
451 chm->sec1.rtable = fi; 501 }
452 } 502 fi->next = chm->sysfiles;
453 } 503 chm->sysfiles = fi;
454 fi->next = chm->sysfiles;
455 chm->sysfiles = fi;
456 } 504 }
457 else { 505 else {
458 /* normal file */ 506 /* normal file */
459 if (link) link->next = fi; else chm->files = fi; 507 if (link) link->next = fi; else chm->files = fi;
460 link = fi; 508 link = fi;
461 } 509 }
462 } 510 }
463 511
@@ -481,21 +529,24 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
481 * directly from the on-disk index. 529 * directly from the on-disk index.
482 * 530 *
483 * TODO: protect against infinite loops in chunks (where pgml_NextChunk 531 * TODO: protect against infinite loops in chunks (where pgml_NextChunk
484 * or a PGMI index entry point to an already visited chunk) 532 * or a PMGI index entry point to an already visited chunk)
485 */ 533 */
486static int chmd_fast_find(struct mschm_decompressor *base, 534static int chmd_fast_find(struct mschm_decompressor *base,
487 struct mschmd_header *chm, const char *filename, 535 struct mschmd_header *chm, const char *filename,
488 struct mschmd_file *f_ptr, int f_size) 536 struct mschmd_file *f_ptr, int f_size)
489{ 537{
490 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base; 538 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
491 struct mspack_system *sys; 539 struct mspack_system *sys;
492 struct mspack_file *fh; 540 struct mspack_file *fh;
493 const unsigned char *chunk, *p, *end; 541 /* p and end are initialised to prevent MSVC warning about "potentially"
542 * uninitialised usage. This is provably untrue, but MS won't fix:
543 * https://developercommunity.visualstudio.com/content/problem/363489/c4701-false-positive-warning.html */
544 const unsigned char *chunk, *p = NULL, *end = NULL;
494 int err = MSPACK_ERR_OK, result = -1; 545 int err = MSPACK_ERR_OK, result = -1;
495 unsigned int n, sec; 546 unsigned int n, sec;
496 547
497 if (!self || !chm || !f_ptr || (f_size != sizeof(struct mschmd_file))) { 548 if (!self || !chm || !f_ptr || (f_size != sizeof(struct mschmd_file))) {
498 return MSPACK_ERR_ARGS; 549 return MSPACK_ERR_ARGS;
499 } 550 }
500 sys = self->system; 551 sys = self->system;
501 552
@@ -503,54 +554,59 @@ static int chmd_fast_find(struct mschm_decompressor *base,
503 memset(f_ptr, 0, f_size); 554 memset(f_ptr, 0, f_size);
504 555
505 if (!(fh = sys->open(sys, chm->filename, MSPACK_SYS_OPEN_READ))) { 556 if (!(fh = sys->open(sys, chm->filename, MSPACK_SYS_OPEN_READ))) {
506 return MSPACK_ERR_OPEN; 557 return MSPACK_ERR_OPEN;
507 } 558 }
508 559
509 /* go through PMGI chunk hierarchy to reach PMGL chunk */ 560 /* go through PMGI chunk hierarchy to reach PMGL chunk */
510 if (chm->index_root < chm->num_chunks) { 561 if (chm->index_root < chm->num_chunks) {
511 n = chm->index_root; 562 n = chm->index_root;
512 for (;;) { 563 for (;;) {
513 if (!(chunk = read_chunk(self, chm, fh, n))) { 564 if (!(chunk = read_chunk(self, chm, fh, n))) {
514 sys->close(fh); 565 sys->close(fh);
515 return self->error; 566 return self->error;
516 } 567 }
517 568
518 /* search PMGI/PMGL chunk. exit early if no entry found */ 569 /* search PMGI/PMGL chunk. exit early if no entry found */
519 if ((result = search_chunk(chm, chunk, filename, &p, &end)) <= 0) { 570 if ((result = search_chunk(chm, chunk, filename, &p, &end)) <= 0) {
520 break; 571 break;
521 } 572 }
522 573
523 /* found result. loop around for next chunk if this is PMGI */ 574 /* found result. loop around for next chunk if this is PMGI */
524 if (chunk[3] == 0x4C) break; else READ_ENCINT(n); 575 if (chunk[3] == 0x4C) break; else READ_ENCINT(n);
525 } 576 }
526 } 577 }
527 else { 578 else {
528 /* PMGL chunks only, search from first_pmgl to last_pmgl */ 579 /* PMGL chunks only, search from first_pmgl to last_pmgl */
529 for (n = chm->first_pmgl; n <= chm->last_pmgl; 580 for (n = chm->first_pmgl; n <= chm->last_pmgl;
530 n = EndGetI32(&chunk[pmgl_NextChunk])) 581 n = EndGetI32(&chunk[pmgl_NextChunk]))
531 { 582 {
532 if (!(chunk = read_chunk(self, chm, fh, n))) { 583 if (!(chunk = read_chunk(self, chm, fh, n))) {
533 err = self->error; 584 err = self->error;
534 break; 585 break;
535 } 586 }
536 587
537 /* search PMGL chunk. exit if file found */ 588 /* search PMGL chunk. exit if file found */
538 if ((result = search_chunk(chm, chunk, filename, &p, &end)) > 0) { 589 if ((result = search_chunk(chm, chunk, filename, &p, &end)) > 0) {
539 break; 590 break;
540 } 591 }
541 } 592
593 /* stop simple infinite loops: can't visit the same chunk twice */
594 if (n == EndGetI32(&chunk[pmgl_NextChunk])) {
595 break;
596 }
597 }
542 } 598 }
543 599
544 /* if we found a file, read it */ 600 /* if we found a file, read it */
545 if (result > 0) { 601 if (result > 0) {
546 READ_ENCINT(sec); 602 READ_ENCINT(sec);
547 f_ptr->section = (sec == 0) ? (struct mschmd_section *) &chm->sec0 603 f_ptr->section = (sec == 0) ? (struct mschmd_section *) &chm->sec0
548 : (struct mschmd_section *) &chm->sec1; 604 : (struct mschmd_section *) &chm->sec1;
549 READ_ENCINT(f_ptr->offset); 605 READ_ENCINT(f_ptr->offset);
550 READ_ENCINT(f_ptr->length); 606 READ_ENCINT(f_ptr->length);
551 } 607 }
552 else if (result < 0) { 608 else if (result < 0) {
553 err = MSPACK_ERR_DATAFORMAT; 609 err = MSPACK_ERR_DATAFORMAT;
554 } 610 }
555 611
556 sys->close(fh); 612 sys->close(fh);
@@ -566,24 +622,24 @@ static int chmd_fast_find(struct mschm_decompressor *base,
566 * so it doesn't need to be read from disk more than once 622 * so it doesn't need to be read from disk more than once
567 */ 623 */
568static unsigned char *read_chunk(struct mschm_decompressor_p *self, 624static unsigned char *read_chunk(struct mschm_decompressor_p *self,
569 struct mschmd_header *chm, 625 struct mschmd_header *chm,
570 struct mspack_file *fh, 626 struct mspack_file *fh,
571 unsigned int chunk_num) 627 unsigned int chunk_num)
572{ 628{
573 struct mspack_system *sys = self->system; 629 struct mspack_system *sys = self->system;
574 unsigned char *buf; 630 unsigned char *buf;
575 631
576 /* check arguments - most are already checked by chmd_fast_find */ 632 /* check arguments - most are already checked by chmd_fast_find */
577 if (chunk_num > chm->num_chunks) return NULL; 633 if (chunk_num >= chm->num_chunks) return NULL;
578 634
579 /* ensure chunk cache is available */ 635 /* ensure chunk cache is available */
580 if (!chm->chunk_cache) { 636 if (!chm->chunk_cache) {
581 size_t size = sizeof(unsigned char *) * chm->num_chunks; 637 size_t size = sizeof(unsigned char *) * chm->num_chunks;
582 if (!(chm->chunk_cache = (unsigned char **) sys->alloc(sys, size))) { 638 if (!(chm->chunk_cache = (unsigned char **) sys->alloc(sys, size))) {
583 self->error = MSPACK_ERR_NOMEMORY; 639 self->error = MSPACK_ERR_NOMEMORY;
584 return NULL; 640 return NULL;
585 } 641 }
586 memset(chm->chunk_cache, 0, size); 642 memset(chm->chunk_cache, 0, size);
587 } 643 }
588 644
589 /* try to answer out of chunk cache */ 645 /* try to answer out of chunk cache */
@@ -591,31 +647,31 @@ static unsigned char *read_chunk(struct mschm_decompressor_p *self,
591 647
592 /* need to read chunk - allocate memory for it */ 648 /* need to read chunk - allocate memory for it */
593 if (!(buf = (unsigned char *) sys->alloc(sys, chm->chunk_size))) { 649 if (!(buf = (unsigned char *) sys->alloc(sys, chm->chunk_size))) {
594 self->error = MSPACK_ERR_NOMEMORY; 650 self->error = MSPACK_ERR_NOMEMORY;
595 return NULL; 651 return NULL;
596 } 652 }
597 653
598 /* seek to block and read it */ 654 /* seek to block and read it */
599 if (sys->seek(fh, (off_t) (chm->dir_offset + (chunk_num * chm->chunk_size)), 655 if (sys->seek(fh, (off_t) (chm->dir_offset + (chunk_num * chm->chunk_size)),
600 MSPACK_SYS_SEEK_START)) 656 MSPACK_SYS_SEEK_START))
601 { 657 {
602 self->error = MSPACK_ERR_SEEK; 658 self->error = MSPACK_ERR_SEEK;
603 sys->free(buf); 659 sys->free(buf);
604 return NULL; 660 return NULL;
605 } 661 }
606 if (sys->read(fh, buf, (int)chm->chunk_size) != (int)chm->chunk_size) { 662 if (sys->read(fh, buf, (int)chm->chunk_size) != (int)chm->chunk_size) {
607 self->error = MSPACK_ERR_READ; 663 self->error = MSPACK_ERR_READ;
608 sys->free(buf); 664 sys->free(buf);
609 return NULL; 665 return NULL;
610 } 666 }
611 667
612 /* check the signature. Is is PMGL or PMGI? */ 668 /* check the signature. Is is PMGL or PMGI? */
613 if (!((buf[0] == 0x50) && (buf[1] == 0x4D) && (buf[2] == 0x47) && 669 if (!((buf[0] == 0x50) && (buf[1] == 0x4D) && (buf[2] == 0x47) &&
614 ((buf[3] == 0x4C) || (buf[3] == 0x49)))) 670 ((buf[3] == 0x4C) || (buf[3] == 0x49))))
615 { 671 {
616 self->error = MSPACK_ERR_SEEK; 672 self->error = MSPACK_ERR_SEEK;
617 sys->free(buf); 673 sys->free(buf);
618 return NULL; 674 return NULL;
619 } 675 }
620 676
621 /* all OK. Store chunk in cache and return it */ 677 /* all OK. Store chunk in cache and return it */
@@ -633,14 +689,14 @@ static unsigned char *read_chunk(struct mschm_decompressor_p *self,
633 * chunk that may eventually contain that entry has been found. 689 * chunk that may eventually contain that entry has been found.
634 */ 690 */
635static int search_chunk(struct mschmd_header *chm, 691static int search_chunk(struct mschmd_header *chm,
636 const unsigned char *chunk, 692 const unsigned char *chunk,
637 const char *filename, 693 const char *filename,
638 const unsigned char **result, 694 const unsigned char **result,
639 const unsigned char **result_end) 695 const unsigned char **result_end)
640{ 696{
641 const unsigned char *start, *end, *p; 697 const unsigned char *start, *end, *p;
642 unsigned int qr_size, num_entries, qr_entries, qr_density, name_len; 698 unsigned int qr_size, num_entries, qr_entries, qr_density, name_len;
643 unsigned int L, R, M, sec, fname_len, entries_off, is_pmgl; 699 unsigned int L, R, M, fname_len, entries_off, is_pmgl;
644 int cmp; 700 int cmp;
645 701
646 fname_len = strlen(filename); 702 fname_len = strlen(filename);
@@ -648,12 +704,12 @@ static int search_chunk(struct mschmd_header *chm,
648 /* PMGL chunk or PMGI chunk? (note: read_chunk() has already 704 /* PMGL chunk or PMGI chunk? (note: read_chunk() has already
649 * checked the rest of the characters in the chunk signature) */ 705 * checked the rest of the characters in the chunk signature) */
650 if (chunk[3] == 0x4C) { 706 if (chunk[3] == 0x4C) {
651 is_pmgl = 1; 707 is_pmgl = 1;
652 entries_off = pmgl_Entries; 708 entries_off = pmgl_Entries;
653 } 709 }
654 else { 710 else {
655 is_pmgl = 0; 711 is_pmgl = 0;
656 entries_off = pmgi_Entries; 712 entries_off = pmgi_Entries;
657 } 713 }
658 714
659 /* Step 1: binary search first filename of each QR entry 715 /* Step 1: binary search first filename of each QR entry
@@ -674,55 +730,55 @@ static int search_chunk(struct mschmd_header *chm,
674 qr_entries = (num_entries + qr_density-1) / qr_density; 730 qr_entries = (num_entries + qr_density-1) / qr_density;
675 731
676 if (num_entries == 0) { 732 if (num_entries == 0) {
677 D(("chunk has no entries")) 733 D(("chunk has no entries"))
678 return -1; 734 return -1;
679 } 735 }
680 736
681 if (qr_size > chm->chunk_size) { 737 if (qr_size > chm->chunk_size) {
682 D(("quickref size > chunk size")) 738 D(("quickref size > chunk size"))
683 return -1; 739 return -1;
684 } 740 }
685 741
686 *result_end = end; 742 *result_end = end;
687 743
688 if (((int)qr_entries * 2) > (start - end)) { 744 if (((int)qr_entries * 2) > (start - end)) {
689 D(("WARNING; more quickrefs than quickref space")) 745 D(("WARNING; more quickrefs than quickref space"))
690 qr_entries = 0; /* but we can live with it */ 746 qr_entries = 0; /* but we can live with it */
691 } 747 }
692 748
693 if (qr_entries > 0) { 749 if (qr_entries > 0) {
694 L = 0; 750 L = 0;
695 R = qr_entries - 1; 751 R = qr_entries - 1;
696 do { 752 do {
697 /* pick new midpoint */ 753 /* pick new midpoint */
698 M = (L + R) >> 1; 754 M = (L + R) >> 1;
699 755
700 /* compare filename with entry QR points to */ 756 /* compare filename with entry QR points to */
701 p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)]; 757 p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
702 READ_ENCINT(name_len); 758 READ_ENCINT(name_len);
703 if (p + name_len > end) goto chunk_end; 759 if (name_len > (unsigned int) (end - p)) goto chunk_end;
704 cmp = compare(filename, (char *)p, fname_len, name_len); 760 cmp = compare(filename, (char *)p, fname_len, name_len);
705 761
706 if (cmp == 0) break; 762 if (cmp == 0) break;
707 else if (cmp < 0) { if (M) R = M - 1; else return 0; } 763 else if (cmp < 0) { if (M) R = M - 1; else return 0; }
708 else if (cmp > 0) L = M + 1; 764 else if (cmp > 0) L = M + 1;
709 } while (L <= R); 765 } while (L <= R);
710 M = (L + R) >> 1; 766 M = (L + R) >> 1;
711 767
712 if (cmp == 0) { 768 if (cmp == 0) {
713 /* exact match! */ 769 /* exact match! */
714 p += name_len; 770 p += name_len;
715 *result = p; 771 *result = p;
716 return 1; 772 return 1;
717 } 773 }
718 774
719 /* otherwise, read the group of entries for QR entry M */ 775 /* otherwise, read the group of entries for QR entry M */
720 p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)]; 776 p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
721 num_entries -= (M * qr_density); 777 num_entries -= (M * qr_density);
722 if (num_entries > qr_density) num_entries = qr_density; 778 if (num_entries > qr_density) num_entries = qr_density;
723 } 779 }
724 else { 780 else {
725 p = &chunk[entries_off]; 781 p = &chunk[entries_off];
726 } 782 }
727 783
728 /* Step 2: linear search through the set of entries reached in step 1. 784 /* Step 2: linear search through the set of entries reached in step 1.
@@ -736,32 +792,32 @@ static int search_chunk(struct mschmd_header *chm,
736 */ 792 */
737 *result = NULL; 793 *result = NULL;
738 while (num_entries-- > 0) { 794 while (num_entries-- > 0) {
739 READ_ENCINT(name_len); 795 READ_ENCINT(name_len);
740 if (p + name_len > end) goto chunk_end; 796 if (name_len > (unsigned int) (end - p)) goto chunk_end;
741 cmp = compare(filename, (char *)p, fname_len, name_len); 797 cmp = compare(filename, (char *)p, fname_len, name_len);
742 p += name_len; 798 p += name_len;
743 799
744 if (cmp == 0) { 800 if (cmp == 0) {
745 /* entry found */ 801 /* entry found */
746 *result = p; 802 *result = p;
747 return 1; 803 return 1;
748 } 804 }
749 805
750 if (cmp < 0) { 806 if (cmp < 0) {
751 /* entry not found (PMGL) / maybe found (PMGI) */ 807 /* entry not found (PMGL) / maybe found (PMGI) */
752 break; 808 break;
753 } 809 }
754 810
755 /* read and ignore the rest of this entry */ 811 /* read and ignore the rest of this entry */
756 if (is_pmgl) { 812 if (is_pmgl) {
757 READ_ENCINT(R); /* skip section */ 813 READ_ENCINT(R); /* skip section */
758 READ_ENCINT(R); /* skip offset */ 814 READ_ENCINT(R); /* skip offset */
759 READ_ENCINT(R); /* skip length */ 815 READ_ENCINT(R); /* skip length */
760 } 816 }
761 else { 817 else {
762 *result = p; /* store potential final result */ 818 *result = p; /* store potential final result */
763 READ_ENCINT(R); /* skip chunk number */ 819 READ_ENCINT(R); /* skip chunk number */
764 } 820 }
765 } 821 }
766 822
767 /* PMGL? not found. PMGI? maybe found */ 823 /* PMGL? not found. PMGI? maybe found */
@@ -773,66 +829,34 @@ static int search_chunk(struct mschmd_header *chm,
773} 829}
774 830
775#if HAVE_TOWLOWER 831#if HAVE_TOWLOWER
776# if HAVE_WCTYPE_H 832# include <wctype.h>
777# include <wctype.h>
778# endif
779# define TOLOWER(x) towlower(x) 833# define TOLOWER(x) towlower(x)
780#elif HAVE_TOLOWER
781# if HAVE_CTYPE_H
782# include <ctype.h>
783# endif
784# define TOLOWER(x) tolower(x)
785#else 834#else
786# define TOLOWER(x) (((x)<0||(x)>256)?(x):mspack_tolower_map[(x)]) 835# include <ctype.h>
787/* Map of char -> lowercase char for the first 256 chars. Generated with: 836# define TOLOWER(x) tolower(x)
788 * LC_CTYPE=en_GB.utf-8 perl -Mlocale -le 'print map{ord(lc chr).","} 0..255'
789 */
790static const unsigned char mspack_tolower_map[256] = {
791 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,
792 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,
793 53,54,55,56,57,58,59,60,61,62,63,64,97,98,99,100,101,102,103,104,105,106,
794 107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,
795 95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
796 115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,
797 134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,
798 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,
799 172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,
800 191,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,
801 242,243,244,245,246,215,248,249,250,251,252,253,254,223,224,225,226,227,228,
802 229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,
803 248,249,250,251,252,253,254,255
804};
805#endif 837#endif
806 838
807/* decodes a UTF-8 character from s[] into c. Will not read past e. */ 839/* decodes a UTF-8 character from s[] into c. Will not read past e.
808#define GET_UTF8_CHAR(s, e, c) do { \ 840 * doesn't test that extension bytes are %10xxxxxx.
809 unsigned char x = *s++; \ 841 * allows some overlong encodings.
810 if (x < 0x80) c = x; \ 842 */
811 else if (x < 0xC0) c = -1; \ 843#define GET_UTF8_CHAR(s, e, c) do { \
812 else if (x < 0xE0) { \ 844 unsigned char x = *s++; \
813 c = (s >= e) ? -1 : ((x & 0x1F) << 6) | (*s++ & 0x3F); \ 845 if (x < 0x80) c = x; \
814 } \ 846 else if (x >= 0xC2 && x < 0xE0 && s < e) { \
815 else if (x < 0xF0) { \ 847 c = (x & 0x1F) << 6 | (*s++ & 0x3F); \
816 c = (s+2 > e) ? -1 : ((x & 0x0F) << 12) | ((s[0] & 0x3F) << 6) \ 848 } \
817 | (s[1] & 0x3F); \ 849 else if (x >= 0xE0 && x < 0xF0 && s+1 < e) { \
818 s += 2; \ 850 c = (x & 0x0F) << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); \
819 } \ 851 s += 2; \
820 else if (x < 0xF8) { \ 852 } \
821 c = (s+3 > e) ? -1 : ((x & 0x07) << 18) | ((s[0] & 0x3F) << 12) \ 853 else if (x >= 0xF0 && x <= 0xF5 && s+2 < e) { \
822 | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F); \ 854 c = (x & 0x07) << 18 | (s[0] & 0x3F) << 12 | \
823 s += 3; \ 855 (s[1] & 0x3F) << 6 | (s[2] & 0x3F); \
824 } \ 856 if (c > 0x10FFFF) c = 0xFFFD; \
825 else if (x < 0xFC) { \ 857 s += 3; \
826 c = (s+4 > e) ? -1 : ((x & 0x03) << 24) | ((s[0] & 0x3F) << 18) \ 858 } \
827 | ((s[1] & 0x3F) << 12)|((s[2] & 0x3F) << 6)|(s[3] & 0x3F); \ 859 else c = 0xFFFD; \
828 s += 4; \
829 } \
830 else if (x < 0xFE) { \
831 c = (s+5>e)?-1:((x&1)<<30)|((s[0]&0x3F)<<24)|((s[1]&0x3F)<<18)| \
832 ((s[2] & 0x3F) << 12) | ((s[3] & 0x3F) << 6)|(s[4] & 0x3F); \
833 s += 5; \
834 } \
835 else c = -1; \
836} while (0) 860} while (0)
837 861
838/* case-insensitively compares two UTF8 encoded strings. String length for 862/* case-insensitively compares two UTF8 encoded strings. String length for
@@ -844,12 +868,12 @@ static inline int compare(const char *s1, const char *s2, int l1, int l2) {
844 int c1, c2; 868 int c1, c2;
845 869
846 while (p1 < e1 && p2 < e2) { 870 while (p1 < e1 && p2 < e2) {
847 GET_UTF8_CHAR(p1, e1, c1); 871 GET_UTF8_CHAR(p1, e1, c1);
848 GET_UTF8_CHAR(p2, e2, c2); 872 GET_UTF8_CHAR(p2, e2, c2);
849 if (c1 == c2) continue; 873 if (c1 == c2) continue;
850 c1 = TOLOWER(c1); 874 c1 = TOLOWER(c1);
851 c2 = TOLOWER(c2); 875 c2 = TOLOWER(c2);
852 if (c1 != c2) return c1 - c2; 876 if (c1 != c2) return c1 - c2;
853 } 877 }
854 return l1 - l2; 878 return l1 - l2;
855} 879}
@@ -861,7 +885,7 @@ static inline int compare(const char *s1, const char *s2, int l1, int l2) {
861 * extracts a file from a CHM helpfile 885 * extracts a file from a CHM helpfile
862 */ 886 */
863static int chmd_extract(struct mschm_decompressor *base, 887static int chmd_extract(struct mschm_decompressor *base,
864 struct mschmd_file *file, const char *filename) 888 struct mschmd_file *file, const char *filename)
865{ 889{
866 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base; 890 struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
867 struct mspack_system *sys; 891 struct mspack_system *sys;
@@ -915,7 +939,7 @@ static int chmd_extract(struct mschm_decompressor *base,
915 case 0: /* Uncompressed section file */ 939 case 0: /* Uncompressed section file */
916 /* simple seek + copy */ 940 /* simple seek + copy */
917 if (sys->seek(self->d->infh, file->section->chm->sec0.offset 941 if (sys->seek(self->d->infh, file->section->chm->sec0.offset
918 + file->offset, MSPACK_SYS_SEEK_START)) 942 + file->offset, MSPACK_SYS_SEEK_START))
919 { 943 {
920 self->error = MSPACK_ERR_SEEK; 944 self->error = MSPACK_ERR_SEEK;
921 } 945 }
@@ -923,17 +947,17 @@ static int chmd_extract(struct mschm_decompressor *base,
923 unsigned char buf[512]; 947 unsigned char buf[512];
924 off_t length = file->length; 948 off_t length = file->length;
925 while (length > 0) { 949 while (length > 0) {
926 int run = sizeof(buf); 950 int run = sizeof(buf);
927 if ((off_t)run > length) run = (int)length; 951 if ((off_t)run > length) run = (int)length;
928 if (sys->read(self->d->infh, &buf[0], run) != run) { 952 if (sys->read(self->d->infh, &buf[0], run) != run) {
929 self->error = MSPACK_ERR_READ; 953 self->error = MSPACK_ERR_READ;
930 break; 954 break;
931 } 955 }
932 if (sys->write(fh, &buf[0], run) != run) { 956 if (sys->write(fh, &buf[0], run) != run) {
933 self->error = MSPACK_ERR_WRITE; 957 self->error = MSPACK_ERR_WRITE;
934 break; 958 break;
935 } 959 }
936 length -= run; 960 length -= run;
937 } 961 }
938 } 962 }
939 break; 963 break;
@@ -944,8 +968,8 @@ static int chmd_extract(struct mschm_decompressor *base,
944 */ 968 */
945 if (!self->d->state || (file->offset < self->d->offset)) { 969 if (!self->d->state || (file->offset < self->d->offset)) {
946 if (self->d->state) { 970 if (self->d->state) {
947 lzxd_free(self->d->state); 971 lzxd_free(self->d->state);
948 self->d->state = NULL; 972 self->d->state = NULL;
949 } 973 }
950 if (chmd_init_decomp(self, file)) break; 974 if (chmd_init_decomp(self, file)) break;
951 } 975 }
@@ -1009,7 +1033,7 @@ static int chmd_sys_write(struct mspack_file *file, void *buffer, int bytes) {
1009 * file. 1033 * file.
1010 */ 1034 */
1011static int chmd_init_decomp(struct mschm_decompressor_p *self, 1035static int chmd_init_decomp(struct mschm_decompressor_p *self,
1012 struct mschmd_file *file) 1036 struct mschmd_file *file)
1013{ 1037{
1014 int window_size, window_bits, reset_interval, entry, err; 1038 int window_size, window_bits, reset_interval, entry, err;
1015 struct mspack_system *sys = self->system; 1039 struct mspack_system *sys = self->system;
@@ -1077,7 +1101,7 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
1077 } 1101 }
1078 1102
1079 /* validate reset_interval */ 1103 /* validate reset_interval */
1080 if (reset_interval % LZX_FRAME_SIZE) { 1104 if (reset_interval == 0 || reset_interval % LZX_FRAME_SIZE) {
1081 D(("bad controldata reset interval")) 1105 D(("bad controldata reset interval"))
1082 return self->error = MSPACK_ERR_DATAFORMAT; 1106 return self->error = MSPACK_ERR_DATAFORMAT;
1083 } 1107 }
@@ -1116,9 +1140,9 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
1116 1140
1117 /* initialise LZX stream */ 1141 /* initialise LZX stream */
1118 self->d->state = lzxd_init(&self->d->sys, self->d->infh, 1142 self->d->state = lzxd_init(&self->d->sys, self->d->infh,
1119 (struct mspack_file *) self, window_bits, 1143 (struct mspack_file *) self, window_bits,
1120 reset_interval / LZX_FRAME_SIZE, 1144 reset_interval / LZX_FRAME_SIZE,
1121 4096, length); 1145 4096, length, 0);
1122 if (!self->d->state) self->error = MSPACK_ERR_NOMEMORY; 1146 if (!self->d->state) self->error = MSPACK_ERR_NOMEMORY;
1123 return self->error; 1147 return self->error;
1124} 1148}
@@ -1131,12 +1155,13 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
1131 * Returns non-zero for success, zero for failure. 1155 * Returns non-zero for success, zero for failure.
1132 */ 1156 */
1133static int read_reset_table(struct mschm_decompressor_p *self, 1157static int read_reset_table(struct mschm_decompressor_p *self,
1134 struct mschmd_sec_mscompressed *sec, 1158 struct mschmd_sec_mscompressed *sec,
1135 int entry, off_t *length_ptr, off_t *offset_ptr) 1159 unsigned int entry,
1160 off_t *length_ptr, off_t *offset_ptr)
1136{ 1161{
1137 struct mspack_system *sys = self->system; 1162 struct mspack_system *sys = self->system;
1138 unsigned char *data; 1163 unsigned char *data;
1139 int pos, entrysize; 1164 unsigned int pos, entrysize;
1140 1165
1141 /* do we have a ResetTable file? */ 1166 /* do we have a ResetTable file? */
1142 int err = find_sys_file(self, sec, &sec->rtable, rtable_name); 1167 int err = find_sys_file(self, sec, &sec->rtable, rtable_name);
@@ -1144,25 +1169,25 @@ static int read_reset_table(struct mschm_decompressor_p *self,
1144 1169
1145 /* read ResetTable file */ 1170 /* read ResetTable file */
1146 if (sec->rtable->length < lzxrt_headerSIZEOF) { 1171 if (sec->rtable->length < lzxrt_headerSIZEOF) {
1147 D(("ResetTable file is too short")) 1172 D(("ResetTable file is too short"))
1148 return 0; 1173 return 0;
1149 } 1174 }
1150 if (!(data = read_sys_file(self, sec->rtable))) { 1175 if (!(data = read_sys_file(self, sec->rtable))) {
1151 D(("can't read reset table")) 1176 D(("can't read reset table"))
1152 return 0; 1177 return 0;
1153 } 1178 }
1154 1179
1155 /* check sanity of reset table */ 1180 /* check sanity of reset table */
1156 if (EndGetI32(&data[lzxrt_FrameLen]) != LZX_FRAME_SIZE) { 1181 if (EndGetI32(&data[lzxrt_FrameLen]) != LZX_FRAME_SIZE) {
1157 D(("bad reset table frame length")) 1182 D(("bad reset table frame length"))
1158 sys->free(data); 1183 sys->free(data);
1159 return 0; 1184 return 0;
1160 } 1185 }
1161 1186
1162 /* get the uncompressed length of the LZX stream */ 1187 /* get the uncompressed length of the LZX stream */
1163 if (read_off64(length_ptr, data, sys, self->d->infh)) { 1188 if (read_off64(length_ptr, &data[lzxrt_UncompLen], sys, self->d->infh)) {
1164 sys->free(data); 1189 sys->free(data);
1165 return 0; 1190 return 0;
1166 } 1191 }
1167 1192
1168 entrysize = EndGetI32(&data[lzxrt_EntrySize]); 1193 entrysize = EndGetI32(&data[lzxrt_EntrySize]);
@@ -1170,25 +1195,25 @@ static int read_reset_table(struct mschm_decompressor_p *self,
1170 1195
1171 /* ensure reset table entry for this offset exists */ 1196 /* ensure reset table entry for this offset exists */
1172 if (entry < EndGetI32(&data[lzxrt_NumEntries]) && 1197 if (entry < EndGetI32(&data[lzxrt_NumEntries]) &&
1173 ((pos + entrysize) <= sec->rtable->length)) 1198 pos <= (sec->rtable->length - entrysize))
1174 { 1199 {
1175 switch (entrysize) { 1200 switch (entrysize) {
1176 case 4: 1201 case 4:
1177 *offset_ptr = EndGetI32(&data[pos]); 1202 *offset_ptr = EndGetI32(&data[pos]);
1178 err = 0; 1203 err = 0;
1179 break; 1204 break;
1180 case 8: 1205 case 8:
1181 err = read_off64(offset_ptr, &data[pos], sys, self->d->infh); 1206 err = read_off64(offset_ptr, &data[pos], sys, self->d->infh);
1182 break; 1207 break;
1183 default: 1208 default:
1184 D(("reset table entry size neither 4 nor 8")) 1209 D(("reset table entry size neither 4 nor 8"))
1185 err = 1; 1210 err = 1;
1186 break; 1211 break;
1187 } 1212 }
1188 } 1213 }
1189 else { 1214 else {
1190 D(("bad reset interval")) 1215 D(("bad reset interval"))
1191 err = 1; 1216 err = 1;
1192 } 1217 }
1193 1218
1194 /* free the reset table */ 1219 /* free the reset table */
@@ -1205,8 +1230,8 @@ static int read_reset_table(struct mschm_decompressor_p *self,
1205 * Returns zero for success or a non-zero error code for failure. 1230 * Returns zero for success or a non-zero error code for failure.
1206 */ 1231 */
1207static int read_spaninfo(struct mschm_decompressor_p *self, 1232static int read_spaninfo(struct mschm_decompressor_p *self,
1208 struct mschmd_sec_mscompressed *sec, 1233 struct mschmd_sec_mscompressed *sec,
1209 off_t *length_ptr) 1234 off_t *length_ptr)
1210{ 1235{
1211 struct mspack_system *sys = self->system; 1236 struct mspack_system *sys = self->system;
1212 unsigned char *data; 1237 unsigned char *data;
@@ -1217,21 +1242,27 @@ static int read_spaninfo(struct mschm_decompressor_p *self,
1217 1242
1218 /* check it's large enough */ 1243 /* check it's large enough */
1219 if (sec->spaninfo->length != 8) { 1244 if (sec->spaninfo->length != 8) {
1220 D(("SpanInfo file is wrong size")) 1245 D(("SpanInfo file is wrong size"))
1221 return MSPACK_ERR_DATAFORMAT; 1246 return MSPACK_ERR_DATAFORMAT;
1222 } 1247 }
1223 1248
1224 /* read the SpanInfo file */ 1249 /* read the SpanInfo file */
1225 if (!(data = read_sys_file(self, sec->spaninfo))) { 1250 if (!(data = read_sys_file(self, sec->spaninfo))) {
1226 D(("can't read SpanInfo file")) 1251 D(("can't read SpanInfo file"))
1227 return self->error; 1252 return self->error;
1228 } 1253 }
1229 1254
1230 /* get the uncompressed length of the LZX stream */ 1255 /* get the uncompressed length of the LZX stream */
1231 err = read_off64(length_ptr, data, sys, self->d->infh); 1256 err = read_off64(length_ptr, data, sys, self->d->infh);
1232
1233 sys->free(data); 1257 sys->free(data);
1234 return (err) ? MSPACK_ERR_DATAFORMAT : MSPACK_ERR_OK; 1258 if (err) return MSPACK_ERR_DATAFORMAT;
1259
1260 if (*length_ptr <= 0) {
1261 D(("output length is invalid"))
1262 return MSPACK_ERR_DATAFORMAT;
1263 }
1264
1265 return MSPACK_ERR_OK;
1235} 1266}
1236 1267
1237/*************************************** 1268/***************************************
@@ -1242,8 +1273,8 @@ static int read_spaninfo(struct mschm_decompressor_p *self,
1242 * for success, non-zero for both failure and the file not existing. 1273 * for success, non-zero for both failure and the file not existing.
1243 */ 1274 */
1244static int find_sys_file(struct mschm_decompressor_p *self, 1275static int find_sys_file(struct mschm_decompressor_p *self,
1245 struct mschmd_sec_mscompressed *sec, 1276 struct mschmd_sec_mscompressed *sec,
1246 struct mschmd_file **f_ptr, const char *name) 1277 struct mschmd_file **f_ptr, const char *name)
1247{ 1278{
1248 struct mspack_system *sys = self->system; 1279 struct mspack_system *sys = self->system;
1249 struct mschmd_file result; 1280 struct mschmd_file result;
@@ -1254,13 +1285,13 @@ static int find_sys_file(struct mschm_decompressor_p *self,
1254 /* try using fast_find to find the file - return DATAFORMAT error if 1285 /* try using fast_find to find the file - return DATAFORMAT error if
1255 * it fails, or successfully doesn't find the file */ 1286 * it fails, or successfully doesn't find the file */
1256 if (chmd_fast_find((struct mschm_decompressor *) self, sec->base.chm, 1287 if (chmd_fast_find((struct mschm_decompressor *) self, sec->base.chm,
1257 name, &result, (int)sizeof(result)) || !result.section) 1288 name, &result, (int)sizeof(result)) || !result.section)
1258 { 1289 {
1259 return MSPACK_ERR_DATAFORMAT; 1290 return MSPACK_ERR_DATAFORMAT;
1260 } 1291 }
1261 1292
1262 if (!(*f_ptr = (struct mschmd_file *) sys->alloc(sys, sizeof(result)))) { 1293 if (!(*f_ptr = (struct mschmd_file *) sys->alloc(sys, sizeof(result)))) {
1263 return MSPACK_ERR_NOMEMORY; 1294 return MSPACK_ERR_NOMEMORY;
1264 } 1295 }
1265 1296
1266 /* copy result */ 1297 /* copy result */
@@ -1280,7 +1311,7 @@ static int find_sys_file(struct mschm_decompressor_p *self,
1280 * memory. 1311 * memory.
1281 */ 1312 */
1282static unsigned char *read_sys_file(struct mschm_decompressor_p *self, 1313static unsigned char *read_sys_file(struct mschm_decompressor_p *self,
1283 struct mschmd_file *file) 1314 struct mschmd_file *file)
1284{ 1315{
1285 struct mspack_system *sys = self->system; 1316 struct mspack_system *sys = self->system;
1286 unsigned char *data = NULL; 1317 unsigned char *data = NULL;
@@ -1298,7 +1329,7 @@ static unsigned char *read_sys_file(struct mschm_decompressor_p *self,
1298 return NULL; 1329 return NULL;
1299 } 1330 }
1300 if (sys->seek(self->d->infh, file->section->chm->sec0.offset 1331 if (sys->seek(self->d->infh, file->section->chm->sec0.offset
1301 + file->offset, MSPACK_SYS_SEEK_START)) 1332 + file->offset, MSPACK_SYS_SEEK_START))
1302 { 1333 {
1303 self->error = MSPACK_ERR_SEEK; 1334 self->error = MSPACK_ERR_SEEK;
1304 sys->free(data); 1335 sys->free(data);
@@ -1331,15 +1362,15 @@ static int chmd_error(struct mschm_decompressor *base) {
1331 * are accepted, offsets beyond that cause an error message. 1362 * are accepted, offsets beyond that cause an error message.
1332 */ 1363 */
1333static int read_off64(off_t *var, unsigned char *mem, 1364static int read_off64(off_t *var, unsigned char *mem,
1334 struct mspack_system *sys, struct mspack_file *fh) 1365 struct mspack_system *sys, struct mspack_file *fh)
1335{ 1366{
1336#ifdef LARGEFILE_SUPPORT 1367#if LARGEFILE_SUPPORT
1337 *var = EndGetI64(mem); 1368 *var = EndGetI64(mem);
1338#else 1369#else
1339 *var = EndGetI32(mem); 1370 *var = EndGetI32(mem);
1340 if ((*var & 0x80000000) || EndGetI32(mem+4)) { 1371 if ((*var & 0x80000000) || EndGetI32(mem+4)) {
1341 sys->message(fh, (char *)largefile_msg); 1372 sys->message(fh, (char *)largefile_msg);
1342 return 1; 1373 return 1;
1343 } 1374 }
1344#endif 1375#endif
1345 return 0; 1376 return 0;
diff --git a/rbutil/rbutilqt/mspack/kwajd.c b/rbutil/rbutilqt/mspack/kwajd.c
index 440f1dcfdd..24e0b0613b 100644
--- a/rbutil/rbutilqt/mspack/kwajd.c
+++ b/rbutil/rbutilqt/mspack/kwajd.c
@@ -1,5 +1,5 @@
1/* This file is part of libmspack. 1/* This file is part of libmspack.
2 * (C) 2003-2010 Stuart Caie. 2 * (C) 2003-2011 Stuart Caie.
3 * 3 *
4 * KWAJ is a format very similar to SZDD. KWAJ method 3 (LZH) was 4 * KWAJ is a format very similar to SZDD. KWAJ method 3 (LZH) was
5 * written by Jeff Johnson. 5 * written by Jeff Johnson.
@@ -14,6 +14,7 @@
14 14
15#include "system-mspack.h" 15#include "system-mspack.h"
16#include "kwaj.h" 16#include "kwaj.h"
17#include "mszip.h"
17 18
18/* prototypes */ 19/* prototypes */
19static struct mskwajd_header *kwajd_open( 20static struct mskwajd_header *kwajd_open(
@@ -40,7 +41,7 @@ static void lzh_free(
40static int lzh_read_lens( 41static int lzh_read_lens(
41 struct kwajd_stream *kwaj, 42 struct kwajd_stream *kwaj,
42 unsigned int type, unsigned int numsyms, 43 unsigned int type, unsigned int numsyms,
43 unsigned char *lens, unsigned short *table); 44 unsigned char *lens);
44static int lzh_read_input( 45static int lzh_read_input(
45 struct kwajd_stream *kwaj); 46 struct kwajd_stream *kwaj);
46 47
@@ -79,8 +80,8 @@ void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *base)
79{ 80{
80 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base; 81 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
81 if (self) { 82 if (self) {
82 struct mspack_system *sys = self->system; 83 struct mspack_system *sys = self->system;
83 sys->free(self); 84 sys->free(self);
84 } 85 }
85} 86}
86 87
@@ -90,7 +91,7 @@ void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *base)
90 * opens a KWAJ file without decompressing, reads header 91 * opens a KWAJ file without decompressing, reads header
91 */ 92 */
92static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base, 93static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base,
93 const char *filename) 94 const char *filename)
94{ 95{
95 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base; 96 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
96 struct mskwajd_header *hdr; 97 struct mskwajd_header *hdr;
@@ -103,18 +104,18 @@ static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base,
103 fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ); 104 fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
104 hdr = (struct mskwajd_header *) sys->alloc(sys, sizeof(struct mskwajd_header_p)); 105 hdr = (struct mskwajd_header *) sys->alloc(sys, sizeof(struct mskwajd_header_p));
105 if (fh && hdr) { 106 if (fh && hdr) {
106 ((struct mskwajd_header_p *) hdr)->fh = fh; 107 ((struct mskwajd_header_p *) hdr)->fh = fh;
107 self->error = kwajd_read_headers(sys, fh, hdr); 108 self->error = kwajd_read_headers(sys, fh, hdr);
108 } 109 }
109 else { 110 else {
110 if (!fh) self->error = MSPACK_ERR_OPEN; 111 if (!fh) self->error = MSPACK_ERR_OPEN;
111 if (!hdr) self->error = MSPACK_ERR_NOMEMORY; 112 if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
112 } 113 }
113 114
114 if (self->error) { 115 if (self->error) {
115 if (fh) sys->close(fh); 116 if (fh) sys->close(fh);
116 if (hdr) sys->free(hdr); 117 sys->free(hdr);
117 hdr = NULL; 118 hdr = NULL;
118 } 119 }
119 120
120 return hdr; 121 return hdr;
@@ -126,7 +127,7 @@ static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base,
126 * closes a KWAJ file 127 * closes a KWAJ file
127 */ 128 */
128static void kwajd_close(struct mskwaj_decompressor *base, 129static void kwajd_close(struct mskwaj_decompressor *base,
129 struct mskwajd_header *hdr) 130 struct mskwajd_header *hdr)
130{ 131{
131 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base; 132 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
132 struct mskwajd_header_p *hdr_p = (struct mskwajd_header_p *) hdr; 133 struct mskwajd_header_p *hdr_p = (struct mskwajd_header_p *) hdr;
@@ -148,22 +149,22 @@ static void kwajd_close(struct mskwaj_decompressor *base,
148 * reads the headers of a KWAJ format file 149 * reads the headers of a KWAJ format file
149 */ 150 */
150static int kwajd_read_headers(struct mspack_system *sys, 151static int kwajd_read_headers(struct mspack_system *sys,
151 struct mspack_file *fh, 152 struct mspack_file *fh,
152 struct mskwajd_header *hdr) 153 struct mskwajd_header *hdr)
153{ 154{
154 unsigned char buf[16]; 155 unsigned char buf[16];
155 int i; 156 int i;
156 157
157 /* read in the header */ 158 /* read in the header */
158 if (sys->read(fh, &buf[0], kwajh_SIZEOF) != kwajh_SIZEOF) { 159 if (sys->read(fh, &buf[0], kwajh_SIZEOF) != kwajh_SIZEOF) {
159 return MSPACK_ERR_READ; 160 return MSPACK_ERR_READ;
160 } 161 }
161 162
162 /* check for "KWAJ" signature */ 163 /* check for "KWAJ" signature */
163 if (((unsigned int) EndGetI32(&buf[kwajh_Signature1]) != 0x4A41574B) || 164 if (((unsigned int) EndGetI32(&buf[kwajh_Signature1]) != 0x4A41574B) ||
164 ((unsigned int) EndGetI32(&buf[kwajh_Signature2]) != 0xD127F088)) 165 ((unsigned int) EndGetI32(&buf[kwajh_Signature2]) != 0xD127F088))
165 { 166 {
166 return MSPACK_ERR_SIGNATURE; 167 return MSPACK_ERR_SIGNATURE;
167 } 168 }
168 169
169 /* basic header fields */ 170 /* basic header fields */
@@ -179,61 +180,67 @@ static int kwajd_read_headers(struct mspack_system *sys,
179 180
180 /* 4 bytes: length of unpacked file */ 181 /* 4 bytes: length of unpacked file */
181 if (hdr->headers & MSKWAJ_HDR_HASLENGTH) { 182 if (hdr->headers & MSKWAJ_HDR_HASLENGTH) {
182 if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ; 183 if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ;
183 hdr->length = EndGetI32(&buf[0]); 184 hdr->length = EndGetI32(&buf[0]);
184 } 185 }
185 186
186 /* 2 bytes: unknown purpose */ 187 /* 2 bytes: unknown purpose */
187 if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN1) { 188 if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN1) {
188 if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ; 189 if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
189 } 190 }
190 191
191 /* 2 bytes: length of section, then [length] bytes: unknown purpose */ 192 /* 2 bytes: length of section, then [length] bytes: unknown purpose */
192 if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN2) { 193 if (hdr->headers & MSKWAJ_HDR_HASUNKNOWN2) {
193 if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ; 194 if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
194 i = EndGetI16(&buf[0]); 195 i = EndGetI16(&buf[0]);
195 if (sys->seek(fh, (off_t)i, MSPACK_SYS_SEEK_CUR)) return MSPACK_ERR_SEEK; 196 if (sys->seek(fh, (off_t)i, MSPACK_SYS_SEEK_CUR)) return MSPACK_ERR_SEEK;
196 } 197 }
197 198
198 /* filename and extension */ 199 /* filename and extension */
199 if (hdr->headers & (MSKWAJ_HDR_HASFILENAME | MSKWAJ_HDR_HASFILEEXT)) { 200 if (hdr->headers & (MSKWAJ_HDR_HASFILENAME | MSKWAJ_HDR_HASFILEEXT)) {
200 off_t pos = sys->tell(fh); 201 int len;
201 char *fn = (char *) sys->alloc(sys, (size_t) 13); 202 /* allocate memory for maximum length filename */
202 203 char *fn = (char *) sys->alloc(sys, (size_t) 13);
203 /* allocate memory for maximum length filename */ 204 if (!(hdr->filename = fn)) return MSPACK_ERR_NOMEMORY;
204 if (! fn) return MSPACK_ERR_NOMEMORY; 205
205 hdr->filename = fn; 206 /* copy filename if present */
206 207 if (hdr->headers & MSKWAJ_HDR_HASFILENAME) {
207 /* copy filename if present */ 208 /* read and copy up to 9 bytes of a null terminated string */
208 if (hdr->headers & MSKWAJ_HDR_HASFILENAME) { 209 if ((len = sys->read(fh, &buf[0], 9)) < 2) return MSPACK_ERR_READ;
209 if (sys->read(fh, &buf[0], 9) != 9) return MSPACK_ERR_READ; 210 for (i = 0; i < len; i++) if (!(*fn++ = buf[i])) break;
210 for (i = 0; i < 9; i++, fn++) if (!(*fn = buf[i])) break; 211 /* if string was 9 bytes with no null terminator, reject it */
211 pos += (i < 9) ? i+1 : 9; 212 if (i == 9 && buf[8] != '\0') return MSPACK_ERR_DATAFORMAT;
212 if (sys->seek(fh, pos, MSPACK_SYS_SEEK_START)) 213 /* seek to byte after string ended in file */
213 return MSPACK_ERR_SEEK; 214 if (sys->seek(fh, (off_t)(i + 1 - len), MSPACK_SYS_SEEK_CUR))
214 } 215 return MSPACK_ERR_SEEK;
215 216 fn--; /* remove the null terminator */
216 /* copy extension if present */ 217 }
217 if (hdr->headers & MSKWAJ_HDR_HASFILEEXT) { 218
218 *fn++ = '.'; 219 /* copy extension if present */
219 if (sys->read(fh, &buf[0], 4) != 4) return MSPACK_ERR_READ; 220 if (hdr->headers & MSKWAJ_HDR_HASFILEEXT) {
220 for (i = 0; i < 4; i++, fn++) if (!(*fn = buf[i])) break; 221 *fn++ = '.';
221 pos += (i < 4) ? i+1 : 4; 222 /* read and copy up to 4 bytes of a null terminated string */
222 if (sys->seek(fh, pos, MSPACK_SYS_SEEK_START)) 223 if ((len = sys->read(fh, &buf[0], 4)) < 2) return MSPACK_ERR_READ;
223 return MSPACK_ERR_SEEK; 224 for (i = 0; i < len; i++) if (!(*fn++ = buf[i])) break;
224 } 225 /* if string was 4 bytes with no null terminator, reject it */
225 *fn = '\0'; 226 if (i == 4 && buf[3] != '\0') return MSPACK_ERR_DATAFORMAT;
227 /* seek to byte after string ended in file */
228 if (sys->seek(fh, (off_t)(i + 1 - len), MSPACK_SYS_SEEK_CUR))
229 return MSPACK_ERR_SEEK;
230 fn--; /* remove the null terminator */
231 }
232 *fn = '\0';
226 } 233 }
227 234
228 /* 2 bytes: extra text length then [length] bytes of extra text data */ 235 /* 2 bytes: extra text length then [length] bytes of extra text data */
229 if (hdr->headers & MSKWAJ_HDR_HASEXTRATEXT) { 236 if (hdr->headers & MSKWAJ_HDR_HASEXTRATEXT) {
230 if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ; 237 if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
231 i = EndGetI16(&buf[0]); 238 i = EndGetI16(&buf[0]);
232 hdr->extra = (char *) sys->alloc(sys, (size_t)i+1); 239 hdr->extra = (char *) sys->alloc(sys, (size_t)i+1);
233 if (! hdr->extra) return MSPACK_ERR_NOMEMORY; 240 if (! hdr->extra) return MSPACK_ERR_NOMEMORY;
234 if (sys->read(fh, hdr->extra, i) != i) return MSPACK_ERR_READ; 241 if (sys->read(fh, hdr->extra, i) != i) return MSPACK_ERR_READ;
235 hdr->extra[i] = '\0'; 242 hdr->extra[i] = '\0';
236 hdr->extra_length = i; 243 hdr->extra_length = i;
237 } 244 }
238 return MSPACK_ERR_OK; 245 return MSPACK_ERR_OK;
239} 246}
@@ -244,7 +251,7 @@ static int kwajd_read_headers(struct mspack_system *sys,
244 * decompresses a KWAJ file 251 * decompresses a KWAJ file
245 */ 252 */
246static int kwajd_extract(struct mskwaj_decompressor *base, 253static int kwajd_extract(struct mskwaj_decompressor *base,
247 struct mskwajd_header *hdr, const char *filename) 254 struct mskwajd_header *hdr, const char *filename)
248{ 255{
249 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base; 256 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
250 struct mspack_system *sys; 257 struct mspack_system *sys;
@@ -258,51 +265,56 @@ static int kwajd_extract(struct mskwaj_decompressor *base,
258 265
259 /* seek to the compressed data */ 266 /* seek to the compressed data */
260 if (sys->seek(fh, hdr->data_offset, MSPACK_SYS_SEEK_START)) { 267 if (sys->seek(fh, hdr->data_offset, MSPACK_SYS_SEEK_START)) {
261 return self->error = MSPACK_ERR_SEEK; 268 return self->error = MSPACK_ERR_SEEK;
262 } 269 }
263 270
264 /* open file for output */ 271 /* open file for output */
265 if (!(outfh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) { 272 if (!(outfh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
266 return self->error = MSPACK_ERR_OPEN; 273 return self->error = MSPACK_ERR_OPEN;
267 } 274 }
268 275
269 self->error = MSPACK_ERR_OK; 276 self->error = MSPACK_ERR_OK;
270 277
271 /* decompress based on format */ 278 /* decompress based on format */
272 if (hdr->comp_type == MSKWAJ_COMP_NONE || 279 if (hdr->comp_type == MSKWAJ_COMP_NONE ||
273 hdr->comp_type == MSKWAJ_COMP_XOR) 280 hdr->comp_type == MSKWAJ_COMP_XOR)
274 { 281 {
275 /* NONE is a straight copy. XOR is a copy xored with 0xFF */ 282 /* NONE is a straight copy. XOR is a copy xored with 0xFF */
276 unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) KWAJ_INPUT_SIZE); 283 unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) KWAJ_INPUT_SIZE);
277 if (buf) { 284 if (buf) {
278 int read, i; 285 int read, i;
279 while ((read = sys->read(fh, buf, KWAJ_INPUT_SIZE)) > 0) { 286 while ((read = sys->read(fh, buf, KWAJ_INPUT_SIZE)) > 0) {
280 if (hdr->comp_type == MSKWAJ_COMP_XOR) { 287 if (hdr->comp_type == MSKWAJ_COMP_XOR) {
281 for (i = 0; i < read; i++) buf[i] ^= 0xFF; 288 for (i = 0; i < read; i++) buf[i] ^= 0xFF;
282 } 289 }
283 if (sys->write(outfh, buf, read) != read) { 290 if (sys->write(outfh, buf, read) != read) {
284 self->error = MSPACK_ERR_WRITE; 291 self->error = MSPACK_ERR_WRITE;
285 break; 292 break;
286 } 293 }
287 } 294 }
288 if (read < 0) self->error = MSPACK_ERR_READ; 295 if (read < 0) self->error = MSPACK_ERR_READ;
289 sys->free(buf); 296 sys->free(buf);
290 } 297 }
291 else { 298 else {
292 self->error = MSPACK_ERR_NOMEMORY; 299 self->error = MSPACK_ERR_NOMEMORY;
293 } 300 }
294 } 301 }
295 else if (hdr->comp_type == MSKWAJ_COMP_SZDD) { 302 else if (hdr->comp_type == MSKWAJ_COMP_SZDD) {
296 self->error = lzss_decompress(sys, fh, outfh, KWAJ_INPUT_SIZE, 303 self->error = lzss_decompress(sys, fh, outfh, KWAJ_INPUT_SIZE,
297 LZSS_MODE_EXPAND); 304 LZSS_MODE_EXPAND);
298 } 305 }
299 else if (hdr->comp_type == MSKWAJ_COMP_LZH) { 306 else if (hdr->comp_type == MSKWAJ_COMP_LZH) {
300 struct kwajd_stream *lzh = lzh_init(sys, fh, outfh); 307 struct kwajd_stream *lzh = lzh_init(sys, fh, outfh);
301 self->error = (lzh) ? lzh_decompress(lzh) : MSPACK_ERR_NOMEMORY; 308 self->error = (lzh) ? lzh_decompress(lzh) : MSPACK_ERR_NOMEMORY;
302 lzh_free(lzh); 309 lzh_free(lzh);
310 }
311 else if (hdr->comp_type == MSKWAJ_COMP_MSZIP) {
312 struct mszipd_stream *zip = mszipd_init(sys,fh,outfh,KWAJ_INPUT_SIZE,0);
313 self->error = (zip) ? mszipd_decompress_kwaj(zip) : MSPACK_ERR_NOMEMORY;
314 mszipd_free(zip);
303 } 315 }
304 else { 316 else {
305 self->error = MSPACK_ERR_DATAFORMAT; 317 self->error = MSPACK_ERR_DATAFORMAT;
306 } 318 }
307 319
308 /* close output file */ 320 /* close output file */
@@ -317,7 +329,7 @@ static int kwajd_extract(struct mskwaj_decompressor *base,
317 * unpacks directly from input to output 329 * unpacks directly from input to output
318 */ 330 */
319static int kwajd_decompress(struct mskwaj_decompressor *base, 331static int kwajd_decompress(struct mskwaj_decompressor *base,
320 const char *input, const char *output) 332 const char *input, const char *output)
321{ 333{
322 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base; 334 struct mskwaj_decompressor_p *self = (struct mskwaj_decompressor_p *) base;
323 struct mskwajd_header *hdr; 335 struct mskwajd_header *hdr;
@@ -353,15 +365,15 @@ static int kwajd_error(struct mskwaj_decompressor *base)
353#define BITS_VAR lzh 365#define BITS_VAR lzh
354#define BITS_ORDER_MSB 366#define BITS_ORDER_MSB
355#define BITS_NO_READ_INPUT 367#define BITS_NO_READ_INPUT
356#define READ_BYTES do { \ 368#define READ_BYTES do { \
357 if (i_ptr >= i_end) { \ 369 if (i_ptr >= i_end) { \
358 if ((err = lzh_read_input(lzh))) return err; \ 370 if ((err = lzh_read_input(lzh))) return err; \
359 i_ptr = lzh->i_ptr; \ 371 i_ptr = lzh->i_ptr; \
360 i_end = lzh->i_end; \ 372 i_end = lzh->i_end; \
361 } \ 373 } \
362 INJECT_BITS(*i_ptr++, 8); \ 374 INJECT_BITS(*i_ptr++, 8); \
363} while (0) 375} while (0)
364#include "readbits.h" 376#include <readbits.h>
365 377
366/* import huffman-reading macros and code */ 378/* import huffman-reading macros and code */
367#define TABLEBITS(tbl) KWAJ_TABLEBITS 379#define TABLEBITS(tbl) KWAJ_TABLEBITS
@@ -369,7 +381,7 @@ static int kwajd_error(struct mskwaj_decompressor *base)
369#define HUFF_TABLE(tbl,idx) lzh->tbl##_table[idx] 381#define HUFF_TABLE(tbl,idx) lzh->tbl##_table[idx]
370#define HUFF_LEN(tbl,idx) lzh->tbl##_len[idx] 382#define HUFF_LEN(tbl,idx) lzh->tbl##_len[idx]
371#define HUFF_ERROR return MSPACK_ERR_DATAFORMAT 383#define HUFF_ERROR return MSPACK_ERR_DATAFORMAT
372#include "readhuff.h" 384#include <readhuff.h>
373 385
374/* In the KWAJ LZH format, there is no special 'eof' marker, it just 386/* In the KWAJ LZH format, there is no special 'eof' marker, it just
375 * ends. Depending on how many bits are left in the final byte when 387 * 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)
381 * isn't how the default readbits.h read_input() works (it simply lets 393 * isn't how the default readbits.h read_input() works (it simply lets
382 * 2 fake bytes in then stops), so we implement our own. 394 * 2 fake bytes in then stops), so we implement our own.
383 */ 395 */
384#define READ_BITS_SAFE(val, n) do { \ 396#define READ_BITS_SAFE(val, n) do { \
385 READ_BITS(val, n); \ 397 READ_BITS(val, n); \
386 if (lzh->input_end && bits_left < lzh->input_end) \ 398 if (lzh->input_end && bits_left < lzh->input_end) \
387 return MSPACK_ERR_OK; \ 399 return MSPACK_ERR_OK; \
388} while (0) 400} while (0)
389 401
390#define READ_HUFFSYM_SAFE(tbl, val) do { \ 402#define READ_HUFFSYM_SAFE(tbl, val) do { \
391 READ_HUFFSYM(tbl, val); \ 403 READ_HUFFSYM(tbl, val); \
392 if (lzh->input_end && bits_left < lzh->input_end) \ 404 if (lzh->input_end && bits_left < lzh->input_end) \
393 return MSPACK_ERR_OK; \ 405 return MSPACK_ERR_OK; \
394} while (0) 406} while (0)
395 407
396#define BUILD_TREE(tbl, type) \ 408#define BUILD_TREE(tbl, type) \
397 STORE_BITS; \ 409 STORE_BITS; \
398 err = lzh_read_lens(lzh, type, MAXSYMBOLS(tbl), \ 410 err = lzh_read_lens(lzh, type, MAXSYMBOLS(tbl), &HUFF_LEN(tbl,0)); \
399 &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0)); \ 411 if (err) return err; \
400 if (err) return err; \ 412 RESTORE_BITS; \
401 RESTORE_BITS; \ 413 if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
402 if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \ 414 &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
403 &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \ 415 return MSPACK_ERR_DATAFORMAT;
404 return MSPACK_ERR_DATAFORMAT; 416
405 417#define WRITE_BYTE do { \
406#define WRITE_BYTE do { \ 418 if (lzh->sys->write(lzh->output, &lzh->window[pos], 1) != 1) \
407 if (lzh->sys->write(lzh->output, &lzh->window[pos], 1) != 1) \ 419 return MSPACK_ERR_WRITE; \
408 return MSPACK_ERR_WRITE; \
409} while (0) 420} while (0)
410 421
411static struct kwajd_stream *lzh_init(struct mspack_system *sys, 422static struct kwajd_stream *lzh_init(struct mspack_system *sys,
@@ -447,33 +458,33 @@ static int lzh_decompress(struct kwajd_stream *lzh)
447 BUILD_TREE(LITERAL, types[4]); 458 BUILD_TREE(LITERAL, types[4]);
448 459
449 while (!lzh->input_end) { 460 while (!lzh->input_end) {
450 if (lit_run) READ_HUFFSYM_SAFE(MATCHLEN2, len); 461 if (lit_run) READ_HUFFSYM_SAFE(MATCHLEN2, len);
451 else READ_HUFFSYM_SAFE(MATCHLEN1, len); 462 else READ_HUFFSYM_SAFE(MATCHLEN1, len);
452 463
453 if (len > 0) { 464 if (len > 0) {
454 len += 2; 465 len += 2;
455 lit_run = 0; /* not the end of a literal run */ 466 lit_run = 0; /* not the end of a literal run */
456 READ_HUFFSYM_SAFE(OFFSET, j); offset = j << 6; 467 READ_HUFFSYM_SAFE(OFFSET, j); offset = j << 6;
457 READ_BITS_SAFE(j, 6); offset |= j; 468 READ_BITS_SAFE(j, 6); offset |= j;
458 469
459 /* copy match as output and into the ring buffer */ 470 /* copy match as output and into the ring buffer */
460 while (len-- > 0) { 471 while (len-- > 0) {
461 lzh->window[pos] = lzh->window[(pos+4096-offset) & 4095]; 472 lzh->window[pos] = lzh->window[(pos+4096-offset) & 4095];
462 WRITE_BYTE; 473 WRITE_BYTE;
463 pos++; pos &= 4095; 474 pos++; pos &= 4095;
464 } 475 }
465 } 476 }
466 else { 477 else {
467 READ_HUFFSYM_SAFE(LITLEN, len); len++; 478 READ_HUFFSYM_SAFE(LITLEN, len); len++;
468 lit_run = (len == 32) ? 0 : 1; /* end of a literal run? */ 479 lit_run = (len == 32) ? 0 : 1; /* end of a literal run? */
469 while (len-- > 0) { 480 while (len-- > 0) {
470 READ_HUFFSYM_SAFE(LITERAL, j); 481 READ_HUFFSYM_SAFE(LITERAL, j);
471 /* copy as output and into the ring buffer */ 482 /* copy as output and into the ring buffer */
472 lzh->window[pos] = j; 483 lzh->window[pos] = j;
473 WRITE_BYTE; 484 WRITE_BYTE;
474 pos++; pos &= 4095; 485 pos++; pos &= 4095;
475 } 486 }
476 } 487 }
477 } 488 }
478 return MSPACK_ERR_OK; 489 return MSPACK_ERR_OK;
479} 490}
@@ -487,8 +498,8 @@ static void lzh_free(struct kwajd_stream *lzh)
487} 498}
488 499
489static int lzh_read_lens(struct kwajd_stream *lzh, 500static int lzh_read_lens(struct kwajd_stream *lzh,
490 unsigned int type, unsigned int numsyms, 501 unsigned int type, unsigned int numsyms,
491 unsigned char *lens, unsigned short *table) 502 unsigned char *lens)
492{ 503{
493 register unsigned int bit_buffer; 504 register unsigned int bit_buffer;
494 register int bits_left; 505 register int bits_left;
@@ -499,33 +510,33 @@ static int lzh_read_lens(struct kwajd_stream *lzh,
499 RESTORE_BITS; 510 RESTORE_BITS;
500 switch (type) { 511 switch (type) {
501 case 0: 512 case 0:
502 i = numsyms; c = (i==16)?4: (i==32)?5: (i==64)?6: (i==256)?8 :0; 513 i = numsyms; c = (i==16)?4: (i==32)?5: (i==64)?6: (i==256)?8 :0;
503 for (i = 0; i < numsyms; i++) lens[i] = c; 514 for (i = 0; i < numsyms; i++) lens[i] = c;
504 break; 515 break;
505 516
506 case 1: 517 case 1:
507 READ_BITS_SAFE(c, 4); lens[0] = c; 518 READ_BITS_SAFE(c, 4); lens[0] = c;
508 for (i = 1; i < numsyms; i++) { 519 for (i = 1; i < numsyms; i++) {
509 READ_BITS_SAFE(sel, 1); if (sel == 0) lens[i] = c; 520 READ_BITS_SAFE(sel, 1); if (sel == 0) lens[i] = c;
510 else { READ_BITS_SAFE(sel, 1); if (sel == 0) lens[i] = ++c; 521 else { READ_BITS_SAFE(sel, 1); if (sel == 0) lens[i] = ++c;
511 else { READ_BITS_SAFE(c, 4); lens[i] = c; }} 522 else { READ_BITS_SAFE(c, 4); lens[i] = c; }}
512 } 523 }
513 break; 524 break;
514 525
515 case 2: 526 case 2:
516 READ_BITS_SAFE(c, 4); lens[0] = c; 527 READ_BITS_SAFE(c, 4); lens[0] = c;
517 for (i = 1; i < numsyms; i++) { 528 for (i = 1; i < numsyms; i++) {
518 READ_BITS_SAFE(sel, 2); 529 READ_BITS_SAFE(sel, 2);
519 if (sel == 3) READ_BITS_SAFE(c, 4); else c += (char) sel-1; 530 if (sel == 3) READ_BITS_SAFE(c, 4); else c += (char) sel-1;
520 lens[i] = c; 531 lens[i] = c;
521 } 532 }
522 break; 533 break;
523 534
524 case 3: 535 case 3:
525 for (i = 0; i < numsyms; i++) { 536 for (i = 0; i < numsyms; i++) {
526 READ_BITS_SAFE(c, 4); lens[i] = c; 537 READ_BITS_SAFE(c, 4); lens[i] = c;
527 } 538 }
528 break; 539 break;
529 } 540 }
530 STORE_BITS; 541 STORE_BITS;
531 return MSPACK_ERR_OK; 542 return MSPACK_ERR_OK;
@@ -534,18 +545,18 @@ static int lzh_read_lens(struct kwajd_stream *lzh,
534static int lzh_read_input(struct kwajd_stream *lzh) { 545static int lzh_read_input(struct kwajd_stream *lzh) {
535 int read; 546 int read;
536 if (lzh->input_end) { 547 if (lzh->input_end) {
537 lzh->input_end += 8; 548 lzh->input_end += 8;
538 lzh->inbuf[0] = 0; 549 lzh->inbuf[0] = 0;
539 read = 1; 550 read = 1;
540 } 551 }
541 else { 552 else {
542 read = lzh->sys->read(lzh->input, &lzh->inbuf[0], KWAJ_INPUT_SIZE); 553 read = lzh->sys->read(lzh->input, &lzh->inbuf[0], KWAJ_INPUT_SIZE);
543 if (read < 0) return MSPACK_ERR_READ; 554 if (read < 0) return MSPACK_ERR_READ;
544 if (read == 0) { 555 if (read == 0) {
545 lzh->input_end = 8; 556 lzh->input_end = 8;
546 lzh->inbuf[0] = 0; 557 lzh->inbuf[0] = 0;
547 read = 1; 558 read = 1;
548 } 559 }
549 } 560 }
550 561
551 /* update i_ptr and i_end */ 562 /* update i_ptr and i_end */
diff --git a/rbutil/rbutilqt/mspack/lzss.h b/rbutil/rbutilqt/mspack/lzss.h
index 55e761b5bf..aa946e52ae 100644
--- a/rbutil/rbutilqt/mspack/lzss.h
+++ b/rbutil/rbutilqt/mspack/lzss.h
@@ -54,10 +54,10 @@ extern "C" {
54 * @return an error code, or MSPACK_ERR_OK if successful 54 * @return an error code, or MSPACK_ERR_OK if successful
55 */ 55 */
56extern int lzss_decompress(struct mspack_system *system, 56extern int lzss_decompress(struct mspack_system *system,
57 struct mspack_file *input, 57 struct mspack_file *input,
58 struct mspack_file *output, 58 struct mspack_file *output,
59 int input_buffer_size, 59 int input_buffer_size,
60 int mode); 60 int mode);
61 61
62#ifdef __cplusplus 62#ifdef __cplusplus
63} 63}
diff --git a/rbutil/rbutilqt/mspack/lzssd.c b/rbutil/rbutilqt/mspack/lzssd.c
index f1a47c7a01..63716d414a 100644
--- a/rbutil/rbutilqt/mspack/lzssd.c
+++ b/rbutil/rbutilqt/mspack/lzssd.c
@@ -14,31 +14,31 @@
14#include "system-mspack.h" 14#include "system-mspack.h"
15#include "lzss.h" 15#include "lzss.h"
16 16
17#define ENSURE_BYTES do { \ 17#define ENSURE_BYTES do { \
18 if (i_ptr >= i_end) { \ 18 if (i_ptr >= i_end) { \
19 read = system->read(input, &inbuf[0], \ 19 read = system->read(input, &inbuf[0], \
20 input_buffer_size); \ 20 input_buffer_size); \
21 if (read <= 0) { \ 21 if (read <= 0) { \
22 system->free(window); \ 22 system->free(window); \
23 return (read < 0) ? MSPACK_ERR_READ \ 23 return (read < 0) ? MSPACK_ERR_READ \
24 : MSPACK_ERR_OK; \ 24 : MSPACK_ERR_OK; \
25 } \ 25 } \
26 i_ptr = &inbuf[0]; i_end = &inbuf[read]; \ 26 i_ptr = &inbuf[0]; i_end = &inbuf[read]; \
27 } \ 27 } \
28} while (0) 28} while (0)
29 29
30#define WRITE_BYTE do { \ 30#define WRITE_BYTE do { \
31 if (system->write(output, &window[pos], 1) != 1) { \ 31 if (system->write(output, &window[pos], 1) != 1) { \
32 system->free(window); \ 32 system->free(window); \
33 return MSPACK_ERR_WRITE; \ 33 return MSPACK_ERR_WRITE; \
34 } \ 34 } \
35} while (0) 35} while (0)
36 36
37int lzss_decompress(struct mspack_system *system, 37int lzss_decompress(struct mspack_system *system,
38 struct mspack_file *input, 38 struct mspack_file *input,
39 struct mspack_file *output, 39 struct mspack_file *output,
40 int input_buffer_size, 40 int input_buffer_size,
41 int mode) 41 int mode)
42{ 42{
43 unsigned char *window, *inbuf, *i_ptr, *i_end; 43 unsigned char *window, *inbuf, *i_ptr, *i_end;
44 unsigned int pos, i, c, invert, mpos, len; 44 unsigned int pos, i, c, invert, mpos, len;
@@ -48,7 +48,7 @@ int lzss_decompress(struct mspack_system *system,
48 if (!system || input_buffer_size < 1 || (mode != LZSS_MODE_EXPAND && 48 if (!system || input_buffer_size < 1 || (mode != LZSS_MODE_EXPAND &&
49 mode != LZSS_MODE_MSHELP && mode != LZSS_MODE_QBASIC)) 49 mode != LZSS_MODE_MSHELP && mode != LZSS_MODE_QBASIC))
50 { 50 {
51 return MSPACK_ERR_ARGS; 51 return MSPACK_ERR_ARGS;
52 } 52 }
53 53
54 /* allocate memory */ 54 /* allocate memory */
@@ -64,27 +64,27 @@ int lzss_decompress(struct mspack_system *system,
64 64
65 /* loop forever; exit condition is in ENSURE_BYTES macro */ 65 /* loop forever; exit condition is in ENSURE_BYTES macro */
66 for (;;) { 66 for (;;) {
67 ENSURE_BYTES; c = *i_ptr++ ^ invert; 67 ENSURE_BYTES; c = *i_ptr++ ^ invert;
68 for (i = 0x01; i & 0xFF; i <<= 1) { 68 for (i = 0x01; i & 0xFF; i <<= 1) {
69 if (c & i) { 69 if (c & i) {
70 /* literal */ 70 /* literal */
71 ENSURE_BYTES; window[pos] = *i_ptr++; 71 ENSURE_BYTES; window[pos] = *i_ptr++;
72 WRITE_BYTE; 72 WRITE_BYTE;
73 pos++; pos &= LZSS_WINDOW_SIZE - 1; 73 pos++; pos &= LZSS_WINDOW_SIZE - 1;
74 } 74 }
75 else { 75 else {
76 /* match */ 76 /* match */
77 ENSURE_BYTES; mpos = *i_ptr++; 77 ENSURE_BYTES; mpos = *i_ptr++;
78 ENSURE_BYTES; mpos |= (*i_ptr & 0xF0) << 4; 78 ENSURE_BYTES; mpos |= (*i_ptr & 0xF0) << 4;
79 len = (*i_ptr++ & 0x0F) + 3; 79 len = (*i_ptr++ & 0x0F) + 3;
80 while (len--) { 80 while (len--) {
81 window[pos] = window[mpos]; 81 window[pos] = window[mpos];
82 WRITE_BYTE; 82 WRITE_BYTE;
83 pos++; pos &= LZSS_WINDOW_SIZE - 1; 83 pos++; pos &= LZSS_WINDOW_SIZE - 1;
84 mpos++; mpos &= LZSS_WINDOW_SIZE - 1; 84 mpos++; mpos &= LZSS_WINDOW_SIZE - 1;
85 } 85 }
86 } 86 }
87 } 87 }
88 } 88 }
89 89
90 /* not reached */ 90 /* not reached */
diff --git a/rbutil/rbutilqt/mspack/lzx.h b/rbutil/rbutilqt/mspack/lzx.h
index fc69928c96..a6152f622b 100644
--- a/rbutil/rbutilqt/mspack/lzx.h
+++ b/rbutil/rbutilqt/mspack/lzx.h
@@ -1,5 +1,5 @@
1/* This file is part of libmspack. 1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie. 2 * (C) 2003-2013 Stuart Caie.
3 * 3 *
4 * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted 4 * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
5 * by Microsoft Corporation. 5 * by Microsoft Corporation.
@@ -35,7 +35,7 @@ extern "C" {
35/* LZX huffman defines: tweak tablebits as desired */ 35/* LZX huffman defines: tweak tablebits as desired */
36#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS) 36#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
37#define LZX_PRETREE_TABLEBITS (6) 37#define LZX_PRETREE_TABLEBITS (6)
38#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8) 38#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 290*8)
39#define LZX_MAINTREE_TABLEBITS (12) 39#define LZX_MAINTREE_TABLEBITS (12)
40#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1) 40#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
41#define LZX_LENGTH_TABLEBITS (12) 41#define LZX_LENGTH_TABLEBITS (12)
@@ -55,6 +55,8 @@ struct lzxd_stream {
55 55
56 unsigned char *window; /* decoding window */ 56 unsigned char *window; /* decoding window */
57 unsigned int window_size; /* window size */ 57 unsigned int window_size; /* window size */
58 unsigned int ref_data_size; /* LZX DELTA reference data size */
59 unsigned int num_offsets; /* number of match_offset entries in table */
58 unsigned int window_posn; /* decompression offset within window */ 60 unsigned int window_posn; /* decompression offset within window */
59 unsigned int frame_posn; /* current frame offset within in window */ 61 unsigned int frame_posn; /* current frame offset within in window */
60 unsigned int frame; /* the number of 32kb frames processed */ 62 unsigned int frame; /* the number of 32kb frames processed */
@@ -70,8 +72,8 @@ struct lzxd_stream {
70 unsigned char intel_started; /* has intel E8 decoding started? */ 72 unsigned char intel_started; /* has intel E8 decoding started? */
71 unsigned char block_type; /* type of the current block */ 73 unsigned char block_type; /* type of the current block */
72 unsigned char header_read; /* have we started decoding at all yet? */ 74 unsigned char header_read; /* have we started decoding at all yet? */
73 unsigned char posn_slots; /* how many posn slots in stream? */
74 unsigned char input_end; /* have we reached the end of input? */ 75 unsigned char input_end; /* have we reached the end of input? */
76 unsigned char is_delta; /* does stream follow LZX DELTA spec? */
75 77
76 int error; 78 int error;
77 79
@@ -87,13 +89,13 @@ struct lzxd_stream {
87 89
88 /* huffman decoding tables */ 90 /* huffman decoding tables */
89 unsigned short PRETREE_table [(1 << LZX_PRETREE_TABLEBITS) + 91 unsigned short PRETREE_table [(1 << LZX_PRETREE_TABLEBITS) +
90 (LZX_PRETREE_MAXSYMBOLS * 2)]; 92 (LZX_PRETREE_MAXSYMBOLS * 2)];
91 unsigned short MAINTREE_table[(1 << LZX_MAINTREE_TABLEBITS) + 93 unsigned short MAINTREE_table[(1 << LZX_MAINTREE_TABLEBITS) +
92 (LZX_MAINTREE_MAXSYMBOLS * 2)]; 94 (LZX_MAINTREE_MAXSYMBOLS * 2)];
93 unsigned short LENGTH_table [(1 << LZX_LENGTH_TABLEBITS) + 95 unsigned short LENGTH_table [(1 << LZX_LENGTH_TABLEBITS) +
94 (LZX_LENGTH_MAXSYMBOLS * 2)]; 96 (LZX_LENGTH_MAXSYMBOLS * 2)];
95 unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) + 97 unsigned short ALIGNED_table [(1 << LZX_ALIGNED_TABLEBITS) +
96 (LZX_ALIGNED_MAXSYMBOLS * 2)]; 98 (LZX_ALIGNED_MAXSYMBOLS * 2)];
97 unsigned char LENGTH_empty; 99 unsigned char LENGTH_empty;
98 100
99 /* this is used purely for doing the intel E8 transform */ 101 /* this is used purely for doing the intel E8 transform */
@@ -114,12 +116,14 @@ struct lzxd_stream {
114 * @param input an input stream with the LZX data. 116 * @param input an input stream with the LZX data.
115 * @param output an output stream to write the decoded data to. 117 * @param output an output stream to write the decoded data to.
116 * @param window_bits the size of the decoding window, which must be 118 * @param window_bits the size of the decoding window, which must be
117 * between 15 and 21 inclusive. 119 * between 15 and 21 inclusive for regular LZX
120 * data, or between 17 and 25 inclusive for
121 * LZX DELTA data.
118 * @param reset_interval the interval at which the LZX bitstream is 122 * @param reset_interval the interval at which the LZX bitstream is
119 * reset, in multiples of LZX frames (32678 123 * reset, in multiples of LZX frames (32678
120 * bytes), e.g. a value of 2 indicates the input 124 * bytes), e.g. a value of 2 indicates the input
121 * stream resets after every 65536 output bytes. 125 * stream resets after every 65536 output bytes.
122 * A value of 0 indicates that the bistream never 126 * A value of 0 indicates that the bitstream never
123 * resets, such as in CAB LZX streams. 127 * resets, such as in CAB LZX streams.
124 * @param input_buffer_size the number of bytes to use as an input 128 * @param input_buffer_size the number of bytes to use as an input
125 * bitstream buffer. 129 * bitstream buffer.
@@ -135,26 +139,49 @@ struct lzxd_stream {
135 * lzxd_set_output_length() once it is 139 * lzxd_set_output_length() once it is
136 * known. If never set, 4 of the final 6 bytes 140 * known. If never set, 4 of the final 6 bytes
137 * of the output stream may be incorrect. 141 * of the output stream may be incorrect.
142 * @param is_delta should be zero for all regular LZX data,
143 * non-zero for LZX DELTA encoded data.
138 * @return a pointer to an initialised lzxd_stream structure, or NULL if 144 * @return a pointer to an initialised lzxd_stream structure, or NULL if
139 * there was not enough memory or parameters to the function were wrong. 145 * there was not enough memory or parameters to the function were wrong.
140 */ 146 */
141extern struct lzxd_stream *lzxd_init(struct mspack_system *system, 147extern struct lzxd_stream *lzxd_init(struct mspack_system *system,
142 struct mspack_file *input, 148 struct mspack_file *input,
143 struct mspack_file *output, 149 struct mspack_file *output,
144 int window_bits, 150 int window_bits,
145 int reset_interval, 151 int reset_interval,
146 int input_buffer_size, 152 int input_buffer_size,
147 off_t output_length); 153 off_t output_length,
154 char is_delta);
148 155
149/* see description of output_length in lzxd_init() */ 156/* see description of output_length in lzxd_init() */
150extern void lzxd_set_output_length(struct lzxd_stream *lzx, 157extern void lzxd_set_output_length(struct lzxd_stream *lzx,
151 off_t output_length); 158 off_t output_length);
159
160/**
161 * Reads LZX DELTA reference data into the window and allows
162 * lzxd_decompress() to reference it.
163 *
164 * Call this before the first call to lzxd_decompress().
165
166 * @param lzx the LZX stream to apply this reference data to
167 * @param system an mspack_system implementation to use with the
168 * input param. Only read() will be called.
169 * @param input an input file handle to read reference data using
170 * system->read().
171 * @param length the length of the reference data. Cannot be longer
172 * than the LZX window size.
173 * @return an error code, or MSPACK_ERR_OK if successful
174 */
175extern int lzxd_set_reference_data(struct lzxd_stream *lzx,
176 struct mspack_system *system,
177 struct mspack_file *input,
178 unsigned int length);
152 179
153/** 180/**
154 * Decompresses entire or partial LZX streams. 181 * Decompresses entire or partial LZX streams.
155 * 182 *
156 * The number of bytes of data that should be decompressed is given as the 183 * The number of bytes of data that should be decompressed is given as the
157 * out_bytes parameter. If more bytes are decoded than are needed, they 184 * out_bytes parameter. If more bytes are decoded than are needed, they
158 * will be kept over for a later invocation. 185 * will be kept over for a later invocation.
159 * 186 *
160 * The output bytes will be passed to the system->write() function given in 187 * The output bytes will be passed to the system->write() function given in
diff --git a/rbutil/rbutilqt/mspack/lzxd.c b/rbutil/rbutilqt/mspack/lzxd.c
index 9b26bac3e0..88cfd90c2a 100644
--- a/rbutil/rbutilqt/mspack/lzxd.c
+++ b/rbutil/rbutilqt/mspack/lzxd.c
@@ -1,5 +1,5 @@
1/* This file is part of libmspack. 1/* This file is part of libmspack.
2 * (C) 2003-2004 Stuart Caie. 2 * (C) 2003-2013 Stuart Caie.
3 * 3 *
4 * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted 4 * The LZX method was created by Jonathan Forbes and Tomi Poutanen, adapted
5 * by Microsoft Corporation. 5 * by Microsoft Corporation.
@@ -70,6 +70,10 @@
70 * The maximum window size has increased from 2MB to 32MB. This also 70 * The maximum window size has increased from 2MB to 32MB. This also
71 * increases the maximum number of position slots, etc. 71 * increases the maximum number of position slots, etc.
72 * 72 *
73 * If the match length is 257 (the maximum possible), this signals
74 * a further length decoding step, that allows for matches up to
75 * 33024 bytes long.
76 *
73 * The format now allows for "reference data", supplied by the caller. 77 * The format now allows for "reference data", supplied by the caller.
74 * If match offsets go further back than the number of bytes 78 * If match offsets go further back than the number of bytes
75 * decompressed so far, that is them accessing the reference data. 79 * decompressed so far, that is them accessing the reference data.
@@ -79,11 +83,11 @@
79#define BITS_TYPE struct lzxd_stream 83#define BITS_TYPE struct lzxd_stream
80#define BITS_VAR lzx 84#define BITS_VAR lzx
81#define BITS_ORDER_MSB 85#define BITS_ORDER_MSB
82#define READ_BYTES do { \ 86#define READ_BYTES do { \
83 unsigned char b0, b1; \ 87 unsigned char b0, b1; \
84 READ_IF_NEEDED; b0 = *i_ptr++; \ 88 READ_IF_NEEDED; b0 = *i_ptr++; \
85 READ_IF_NEEDED; b1 = *i_ptr++; \ 89 READ_IF_NEEDED; b1 = *i_ptr++; \
86 INJECT_BITS((b1 << 8) | b0, 16); \ 90 INJECT_BITS((b1 << 8) | b0, 16); \
87} while (0) 91} while (0)
88#include "readbits.h" 92#include "readbits.h"
89 93
@@ -96,43 +100,43 @@
96#include "readhuff.h" 100#include "readhuff.h"
97 101
98/* BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */ 102/* BUILD_TABLE(tbl) builds a huffman lookup table from code lengths */
99#define BUILD_TABLE(tbl) \ 103#define BUILD_TABLE(tbl) \
100 if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \ 104 if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
101 &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \ 105 &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
102 { \ 106 { \
103 D(("failed to build %s table", #tbl)) \ 107 D(("failed to build %s table", #tbl)) \
104 return lzx->error = MSPACK_ERR_DECRUNCH; \ 108 return lzx->error = MSPACK_ERR_DECRUNCH; \
105 } 109 }
106 110
107#define BUILD_TABLE_MAYBE_EMPTY(tbl) do { \ 111#define BUILD_TABLE_MAYBE_EMPTY(tbl) do { \
108 lzx->tbl##_empty = 0; \ 112 lzx->tbl##_empty = 0; \
109 if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \ 113 if (make_decode_table(MAXSYMBOLS(tbl), TABLEBITS(tbl), \
110 &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \ 114 &HUFF_LEN(tbl,0), &HUFF_TABLE(tbl,0))) \
111 { \ 115 { \
112 for (i = 0; i < MAXSYMBOLS(tbl); i++) { \ 116 for (i = 0; i < MAXSYMBOLS(tbl); i++) { \
113 if (HUFF_LEN(tbl, i) > 0) { \ 117 if (HUFF_LEN(tbl, i) > 0) { \
114 D(("failed to build %s table", #tbl)) \ 118 D(("failed to build %s table", #tbl)) \
115 return lzx->error = MSPACK_ERR_DECRUNCH; \ 119 return lzx->error = MSPACK_ERR_DECRUNCH; \
116 } \ 120 } \
117 } \ 121 } \
118 /* empty tree - allow it, but don't decode symbols with it */ \ 122 /* empty tree - allow it, but don't decode symbols with it */ \
119 lzx->tbl##_empty = 1; \ 123 lzx->tbl##_empty = 1; \
120 } \ 124 } \
121} while (0) 125} while (0)
122 126
123/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols 127/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols
124 * first to last in the given table. The code lengths are stored in their 128 * first to last in the given table. The code lengths are stored in their
125 * own special LZX way. 129 * own special LZX way.
126 */ 130 */
127#define READ_LENGTHS(tbl, first, last) do { \ 131#define READ_LENGTHS(tbl, first, last) do { \
128 STORE_BITS; \ 132 STORE_BITS; \
129 if (lzxd_read_lens(lzx, &HUFF_LEN(tbl, 0), (first), \ 133 if (lzxd_read_lens(lzx, &HUFF_LEN(tbl, 0), (first), \
130 (unsigned int)(last))) return lzx->error; \ 134 (unsigned int)(last))) return lzx->error; \
131 RESTORE_BITS; \ 135 RESTORE_BITS; \
132} while (0) 136} while (0)
133 137
134static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens, 138static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens,
135 unsigned int first, unsigned int last) 139 unsigned int first, unsigned int last)
136{ 140{
137 /* bit buffer and huffman symbol decode variables */ 141 /* bit buffer and huffman symbol decode variables */
138 register unsigned int bit_buffer; 142 register unsigned int bit_buffer;
@@ -189,27 +193,70 @@ static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens,
189 * a small 'position slot' number and a small offset from that slot are 193 * a small 'position slot' number and a small offset from that slot are
190 * encoded instead of one large offset. 194 * encoded instead of one large offset.
191 * 195 *
196 * The number of slots is decided by how many are needed to encode the
197 * largest offset for a given window size. This is easy when the gap between
198 * slots is less than 128Kb, it's a linear relationship. But when extra_bits
199 * reaches its limit of 17 (because LZX can only ensure reading 17 bits of
200 * data at a time), we can only jump 128Kb at a time and have to start
201 * using more and more position slots as each window size doubles.
202 *
192 * position_base[] is an index to the position slot bases 203 * position_base[] is an index to the position slot bases
193 * 204 *
194 * extra_bits[] states how many bits of offset-from-base data is needed. 205 * extra_bits[] states how many bits of offset-from-base data is needed.
195 * 206 *
196 * They are generated like so: 207 * They are calculated as follows:
197 * for (i = 0; i < 4; i++) extra_bits[i] = 0; 208 * extra_bits[i] = 0 where i < 4
198 * for (i = 4, j = 0; i < 36; i+=2) extra_bits[i] = extra_bits[i+1] = j++; 209 * extra_bits[i] = floor(i/2)-1 where i >= 4 && i < 36
199 * for (i = 36; i < 51; i++) extra_bits[i] = 17; 210 * extra_bits[i] = 17 where i >= 36
200 * for (i = 0, j = 0; i < 51; j += 1 << extra_bits[i++]) position_base[i] = j; 211 * position_base[0] = 0
212 * position_base[i] = position_base[i-1] + (1 << extra_bits[i-1])
201 */ 213 */
202static const unsigned int position_base[51] = { 214static const unsigned int position_slots[11] = {
203 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 215 30, 32, 34, 36, 38, 42, 50, 66, 98, 162, 290
204 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 216};
205 16384, 24576, 32768, 49152, 65536, 98304, 131072, 196608, 262144, 217static const unsigned char extra_bits[36] = {
206 393216, 524288, 655360, 786432, 917504, 1048576, 1179648, 1310720, 218 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
207 1441792, 1572864, 1703936, 1835008, 1966080, 2097152 219 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16
208}; 220};
209static const unsigned char extra_bits[51] = { 221static const unsigned int position_base[290] = {
210 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 222 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512,
211 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 223 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768,
212 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17 224 49152, 65536, 98304, 131072, 196608, 262144, 393216, 524288, 655360,
225 786432, 917504, 1048576, 1179648, 1310720, 1441792, 1572864, 1703936,
226 1835008, 1966080, 2097152, 2228224, 2359296, 2490368, 2621440, 2752512,
227 2883584, 3014656, 3145728, 3276800, 3407872, 3538944, 3670016, 3801088,
228 3932160, 4063232, 4194304, 4325376, 4456448, 4587520, 4718592, 4849664,
229 4980736, 5111808, 5242880, 5373952, 5505024, 5636096, 5767168, 5898240,
230 6029312, 6160384, 6291456, 6422528, 6553600, 6684672, 6815744, 6946816,
231 7077888, 7208960, 7340032, 7471104, 7602176, 7733248, 7864320, 7995392,
232 8126464, 8257536, 8388608, 8519680, 8650752, 8781824, 8912896, 9043968,
233 9175040, 9306112, 9437184, 9568256, 9699328, 9830400, 9961472, 10092544,
234 10223616, 10354688, 10485760, 10616832, 10747904, 10878976, 11010048,
235 11141120, 11272192, 11403264, 11534336, 11665408, 11796480, 11927552,
236 12058624, 12189696, 12320768, 12451840, 12582912, 12713984, 12845056,
237 12976128, 13107200, 13238272, 13369344, 13500416, 13631488, 13762560,
238 13893632, 14024704, 14155776, 14286848, 14417920, 14548992, 14680064,
239 14811136, 14942208, 15073280, 15204352, 15335424, 15466496, 15597568,
240 15728640, 15859712, 15990784, 16121856, 16252928, 16384000, 16515072,
241 16646144, 16777216, 16908288, 17039360, 17170432, 17301504, 17432576,
242 17563648, 17694720, 17825792, 17956864, 18087936, 18219008, 18350080,
243 18481152, 18612224, 18743296, 18874368, 19005440, 19136512, 19267584,
244 19398656, 19529728, 19660800, 19791872, 19922944, 20054016, 20185088,
245 20316160, 20447232, 20578304, 20709376, 20840448, 20971520, 21102592,
246 21233664, 21364736, 21495808, 21626880, 21757952, 21889024, 22020096,
247 22151168, 22282240, 22413312, 22544384, 22675456, 22806528, 22937600,
248 23068672, 23199744, 23330816, 23461888, 23592960, 23724032, 23855104,
249 23986176, 24117248, 24248320, 24379392, 24510464, 24641536, 24772608,
250 24903680, 25034752, 25165824, 25296896, 25427968, 25559040, 25690112,
251 25821184, 25952256, 26083328, 26214400, 26345472, 26476544, 26607616,
252 26738688, 26869760, 27000832, 27131904, 27262976, 27394048, 27525120,
253 27656192, 27787264, 27918336, 28049408, 28180480, 28311552, 28442624,
254 28573696, 28704768, 28835840, 28966912, 29097984, 29229056, 29360128,
255 29491200, 29622272, 29753344, 29884416, 30015488, 30146560, 30277632,
256 30408704, 30539776, 30670848, 30801920, 30932992, 31064064, 31195136,
257 31326208, 31457280, 31588352, 31719424, 31850496, 31981568, 32112640,
258 32243712, 32374784, 32505856, 32636928, 32768000, 32899072, 33030144,
259 33161216, 33292288, 33423360
213}; 260};
214 261
215static void lzxd_reset_state(struct lzxd_stream *lzx) { 262static void lzxd_reset_state(struct lzxd_stream *lzx) {
@@ -230,23 +277,37 @@ static void lzxd_reset_state(struct lzxd_stream *lzx) {
230/*-------- main LZX code --------*/ 277/*-------- main LZX code --------*/
231 278
232struct lzxd_stream *lzxd_init(struct mspack_system *system, 279struct lzxd_stream *lzxd_init(struct mspack_system *system,
233 struct mspack_file *input, 280 struct mspack_file *input,
234 struct mspack_file *output, 281 struct mspack_file *output,
235 int window_bits, 282 int window_bits,
236 int reset_interval, 283 int reset_interval,
237 int input_buffer_size, 284 int input_buffer_size,
238 off_t output_length) 285 off_t output_length,
286 char is_delta)
239{ 287{
240 unsigned int window_size = 1 << window_bits; 288 unsigned int window_size = 1 << window_bits;
241 struct lzxd_stream *lzx; 289 struct lzxd_stream *lzx;
242 290
243 if (!system) return NULL; 291 if (!system) return NULL;
244 292
245 /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */ 293 /* LZX DELTA window sizes are between 2^17 (128KiB) and 2^25 (32MiB),
246 if (window_bits < 15 || window_bits > 21) return NULL; 294 * regular LZX windows are between 2^15 (32KiB) and 2^21 (2MiB)
295 */
296 if (is_delta) {
297 if (window_bits < 17 || window_bits > 25) return NULL;
298 }
299 else {
300 if (window_bits < 15 || window_bits > 21) return NULL;
301 }
247 302
303 if (reset_interval < 0 || output_length < 0) {
304 D(("reset interval or output length < 0"))
305 return NULL;
306 }
307
308 /* round up input buffer size to multiple of two */
248 input_buffer_size = (input_buffer_size + 1) & -2; 309 input_buffer_size = (input_buffer_size + 1) & -2;
249 if (!input_buffer_size) return NULL; 310 if (input_buffer_size < 2) return NULL;
250 311
251 /* allocate decompression state */ 312 /* allocate decompression state */
252 if (!(lzx = (struct lzxd_stream *) system->alloc(system, sizeof(struct lzxd_stream)))) { 313 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,
272 333
273 lzx->inbuf_size = input_buffer_size; 334 lzx->inbuf_size = input_buffer_size;
274 lzx->window_size = 1 << window_bits; 335 lzx->window_size = 1 << window_bits;
336 lzx->ref_data_size = 0;
275 lzx->window_posn = 0; 337 lzx->window_posn = 0;
276 lzx->frame_posn = 0; 338 lzx->frame_posn = 0;
277 lzx->frame = 0; 339 lzx->frame = 0;
@@ -280,11 +342,8 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system,
280 lzx->intel_curpos = 0; 342 lzx->intel_curpos = 0;
281 lzx->intel_started = 0; 343 lzx->intel_started = 0;
282 lzx->error = MSPACK_ERR_OK; 344 lzx->error = MSPACK_ERR_OK;
283 345 lzx->num_offsets = position_slots[window_bits - 15] << 3;
284 /* window bits: 15 16 17 18 19 20 21 346 lzx->is_delta = is_delta;
285 * position slots: 30 32 34 36 38 42 50 */
286 lzx->posn_slots = ((window_bits == 21) ? 50 :
287 ((window_bits == 20) ? 42 : (window_bits << 1)));
288 347
289 lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0]; 348 lzx->o_ptr = lzx->o_end = &lzx->e8_buf[0];
290 lzxd_reset_state(lzx); 349 lzxd_reset_state(lzx);
@@ -292,8 +351,44 @@ struct lzxd_stream *lzxd_init(struct mspack_system *system,
292 return lzx; 351 return lzx;
293} 352}
294 353
354int lzxd_set_reference_data(struct lzxd_stream *lzx,
355 struct mspack_system *system,
356 struct mspack_file *input,
357 unsigned int length)
358{
359 if (!lzx) return MSPACK_ERR_ARGS;
360
361 if (!lzx->is_delta) {
362 D(("only LZX DELTA streams support reference data"))
363 return MSPACK_ERR_ARGS;
364 }
365 if (lzx->offset) {
366 D(("too late to set reference data after decoding starts"))
367 return MSPACK_ERR_ARGS;
368 }
369 if (length > lzx->window_size) {
370 D(("reference length (%u) is longer than the window", length))
371 return MSPACK_ERR_ARGS;
372 }
373 if (length > 0 && (!system || !input)) {
374 D(("length > 0 but no system or input"))
375 return MSPACK_ERR_ARGS;
376 }
377
378 lzx->ref_data_size = length;
379 if (length > 0) {
380 /* copy reference data */
381 unsigned char *pos = &lzx->window[lzx->window_size - length];
382 int bytes = system->read(input, pos, length);
383 /* length can't be more than 2^25, so no signedness problem */
384 if (bytes < (int)length) return MSPACK_ERR_READ;
385 }
386 lzx->ref_data_size = length;
387 return MSPACK_ERR_OK;
388}
389
295void lzxd_set_output_length(struct lzxd_stream *lzx, off_t out_bytes) { 390void lzxd_set_output_length(struct lzxd_stream *lzx, off_t out_bytes) {
296 if (lzx) lzx->length = out_bytes; 391 if (lzx && out_bytes > 0) lzx->length = out_bytes;
297} 392}
298 393
299int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { 394int 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) {
304 register unsigned short sym; 399 register unsigned short sym;
305 400
306 int match_length, length_footer, extra, verbatim_bits, bytes_todo; 401 int match_length, length_footer, extra, verbatim_bits, bytes_todo;
307 int this_run, main_element, aligned_bits, j; 402 int this_run, main_element, aligned_bits, j, warned = 0;
308 unsigned char *window, *runsrc, *rundest, buf[12]; 403 unsigned char *window, *runsrc, *rundest, buf[12];
309 unsigned int frame_size=0, end_frame, match_offset, window_posn; 404 unsigned int frame_size=0, end_frame, match_offset, window_posn;
310 unsigned int R0, R1, R2; 405 unsigned int R0, R1, R2;
@@ -340,8 +435,12 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
340 /* have we reached the reset interval? (if there is one?) */ 435 /* have we reached the reset interval? (if there is one?) */
341 if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) { 436 if (lzx->reset_interval && ((lzx->frame % lzx->reset_interval) == 0)) {
342 if (lzx->block_remaining) { 437 if (lzx->block_remaining) {
343 D(("%d bytes remaining at reset interval", lzx->block_remaining)) 438 /* this is a file format error, we can make a best effort to extract what we can */
344 return lzx->error = MSPACK_ERR_DECRUNCH; 439 D(("%d bytes remaining at reset interval", lzx->block_remaining))
440 if (!warned) {
441 lzx->sys->message(NULL, "WARNING; invalid reset interval detected during LZX decompression");
442 warned++;
443 }
345 } 444 }
346 445
347 /* re-read the intel header and reset the huffman lengths */ 446 /* 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) {
351 R2 = lzx->R2; 450 R2 = lzx->R2;
352 } 451 }
353 452
453 /* LZX DELTA format has chunk_size, not present in LZX format */
454 if (lzx->is_delta) {
455 ENSURE_BITS(16);
456 REMOVE_BITS(16);
457 }
458
354 /* read header if necessary */ 459 /* read header if necessary */
355 if (!lzx->header_read) { 460 if (!lzx->header_read) {
356 /* read 1 bit. if bit=0, intel filesize = 0. 461 /* read 1 bit. if bit=0, intel filesize = 0.
@@ -373,62 +478,61 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
373 while (bytes_todo > 0) { 478 while (bytes_todo > 0) {
374 /* initialise new block, if one is needed */ 479 /* initialise new block, if one is needed */
375 if (lzx->block_remaining == 0) { 480 if (lzx->block_remaining == 0) {
376 /* realign if previous block was an odd-sized UNCOMPRESSED block */ 481 /* realign if previous block was an odd-sized UNCOMPRESSED block */
377 if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) && 482 if ((lzx->block_type == LZX_BLOCKTYPE_UNCOMPRESSED) &&
378 (lzx->block_length & 1)) 483 (lzx->block_length & 1))
379 { 484 {
380 READ_IF_NEEDED; 485 READ_IF_NEEDED;
381 i_ptr++; 486 i_ptr++;
382 } 487 }
383 488
384 /* read block type (3 bits) and block length (24 bits) */ 489 /* read block type (3 bits) and block length (24 bits) */
385 READ_BITS(lzx->block_type, 3); 490 READ_BITS(lzx->block_type, 3);
386 READ_BITS(i, 16); READ_BITS(j, 8); 491 READ_BITS(i, 16); READ_BITS(j, 8);
387 lzx->block_remaining = lzx->block_length = (i << 8) | j; 492 lzx->block_remaining = lzx->block_length = (i << 8) | j;
388 /*D(("new block t%d len %u", lzx->block_type, lzx->block_length))*/ 493 /*D(("new block t%d len %u", lzx->block_type, lzx->block_length))*/
389 494
390 /* read individual block headers */ 495 /* read individual block headers */
391 switch (lzx->block_type) { 496 switch (lzx->block_type) {
392 case LZX_BLOCKTYPE_ALIGNED: 497 case LZX_BLOCKTYPE_ALIGNED:
393 /* read lengths of and build aligned huffman decoding tree */ 498 /* read lengths of and build aligned huffman decoding tree */
394 for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; } 499 for (i = 0; i < 8; i++) { READ_BITS(j, 3); lzx->ALIGNED_len[i] = j; }
395 BUILD_TABLE(ALIGNED); 500 BUILD_TABLE(ALIGNED);
396 /* no break -- rest of aligned header is same as verbatim */ 501 /* rest of aligned header is same as verbatim */ /*@fallthrough@*/
397 case LZX_BLOCKTYPE_VERBATIM: 502 case LZX_BLOCKTYPE_VERBATIM:
398 /* read lengths of and build main huffman decoding tree */ 503 /* read lengths of and build main huffman decoding tree */
399 READ_LENGTHS(MAINTREE, 0, 256); 504 READ_LENGTHS(MAINTREE, 0, 256);
400 READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + (lzx->posn_slots << 3)); 505 READ_LENGTHS(MAINTREE, 256, LZX_NUM_CHARS + lzx->num_offsets);
401 BUILD_TABLE(MAINTREE); 506 BUILD_TABLE(MAINTREE);
402 /* if the literal 0xE8 is anywhere in the block... */ 507 /* if the literal 0xE8 is anywhere in the block... */
403 if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1; 508 if (lzx->MAINTREE_len[0xE8] != 0) lzx->intel_started = 1;
404 /* read lengths of and build lengths huffman decoding tree */ 509 /* read lengths of and build lengths huffman decoding tree */
405 READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS); 510 READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
406 BUILD_TABLE_MAYBE_EMPTY(LENGTH); 511 BUILD_TABLE_MAYBE_EMPTY(LENGTH);
407 break; 512 break;
408 513
409 case LZX_BLOCKTYPE_UNCOMPRESSED: 514 case LZX_BLOCKTYPE_UNCOMPRESSED:
410 /* because we can't assume otherwise */ 515 /* because we can't assume otherwise */
411 lzx->intel_started = 1; 516 lzx->intel_started = 1;
412 517
413 /* read 1-16 (not 0-15) bits to align to bytes */ 518 /* read 1-16 (not 0-15) bits to align to bytes */
414 ENSURE_BITS(16); 519 if (bits_left == 0) ENSURE_BITS(16);
415 if (bits_left > 16) i_ptr -= 2; 520 bits_left = 0; bit_buffer = 0;
416 bits_left = 0; bit_buffer = 0; 521
417 522 /* read 12 bytes of stored R0 / R1 / R2 values */
418 /* read 12 bytes of stored R0 / R1 / R2 values */ 523 for (rundest = &buf[0], i = 0; i < 12; i++) {
419 for (rundest = &buf[0], i = 0; i < 12; i++) { 524 READ_IF_NEEDED;
420 READ_IF_NEEDED; 525 *rundest++ = *i_ptr++;
421 *rundest++ = *i_ptr++; 526 }
422 } 527 R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
423 R0 = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); 528 R1 = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24);
424 R1 = buf[4] | (buf[5] << 8) | (buf[6] << 16) | (buf[7] << 24); 529 R2 = buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24);
425 R2 = buf[8] | (buf[9] << 8) | (buf[10] << 16) | (buf[11] << 24); 530 break;
426 break; 531
427 532 default:
428 default: 533 D(("bad block type"))
429 D(("bad block type")) 534 return lzx->error = MSPACK_ERR_DECRUNCH;
430 return lzx->error = MSPACK_ERR_DECRUNCH; 535 }
431 }
432 } 536 }
433 537
434 /* decode more of the block: 538 /* decode more of the block:
@@ -443,208 +547,270 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
443 /* decode at least this_run bytes */ 547 /* decode at least this_run bytes */
444 switch (lzx->block_type) { 548 switch (lzx->block_type) {
445 case LZX_BLOCKTYPE_VERBATIM: 549 case LZX_BLOCKTYPE_VERBATIM:
446 while (this_run > 0) { 550 while (this_run > 0) {
447 READ_HUFFSYM(MAINTREE, main_element); 551 READ_HUFFSYM(MAINTREE, main_element);
448 if (main_element < LZX_NUM_CHARS) { 552 if (main_element < LZX_NUM_CHARS) {
449 /* literal: 0 to LZX_NUM_CHARS-1 */ 553 /* literal: 0 to LZX_NUM_CHARS-1 */
450 window[window_posn++] = main_element; 554 window[window_posn++] = main_element;
451 this_run--; 555 this_run--;
452 } 556 }
453 else { 557 else {
454 /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ 558 /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
455 main_element -= LZX_NUM_CHARS; 559 main_element -= LZX_NUM_CHARS;
456 560
457 /* get match length */ 561 /* get match length */
458 match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; 562 match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
459 if (match_length == LZX_NUM_PRIMARY_LENGTHS) { 563 if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
460 if (lzx->LENGTH_empty) { 564 if (lzx->LENGTH_empty) {
461 D(("LENGTH symbol needed but tree is empty")) 565 D(("LENGTH symbol needed but tree is empty"))
462 return lzx->error = MSPACK_ERR_DECRUNCH; 566 return lzx->error = MSPACK_ERR_DECRUNCH;
463 } 567 }
464 READ_HUFFSYM(LENGTH, length_footer); 568 READ_HUFFSYM(LENGTH, length_footer);
465 match_length += length_footer; 569 match_length += length_footer;
466 } 570 }
467 match_length += LZX_MIN_MATCH; 571 match_length += LZX_MIN_MATCH;
468 572
469 /* get match offset */ 573 /* get match offset */
470 switch ((match_offset = (main_element >> 3))) { 574 switch ((match_offset = (main_element >> 3))) {
471 case 0: match_offset = R0; break; 575 case 0: match_offset = R0; break;
472 case 1: match_offset = R1; R1=R0; R0 = match_offset; break; 576 case 1: match_offset = R1; R1=R0; R0 = match_offset; break;
473 case 2: match_offset = R2; R2=R0; R0 = match_offset; break; 577 case 2: match_offset = R2; R2=R0; R0 = match_offset; break;
474 case 3: match_offset = 1; R2=R1; R1=R0; R0 = match_offset; break; 578 case 3: match_offset = 1; R2=R1; R1=R0; R0 = match_offset; break;
475 default: 579 default:
476 extra = extra_bits[match_offset]; 580 extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
477 READ_BITS(verbatim_bits, extra); 581 READ_BITS(verbatim_bits, extra);
478 match_offset = position_base[match_offset] - 2 + verbatim_bits; 582 match_offset = position_base[match_offset] - 2 + verbatim_bits;
479 R2 = R1; R1 = R0; R0 = match_offset; 583 R2 = R1; R1 = R0; R0 = match_offset;
480 } 584 }
481 585
482 if ((window_posn + match_length) > lzx->window_size) { 586 /* LZX DELTA uses max match length to signal even longer match */
483 D(("match ran over window wrap")) 587 if (match_length == LZX_MAX_MATCH && lzx->is_delta) {
484 return lzx->error = MSPACK_ERR_DECRUNCH; 588 int extra_len = 0;
485 } 589 ENSURE_BITS(3); /* 4 entry huffman tree */
486 590 if (PEEK_BITS(1) == 0) {
487 /* copy match */ 591 REMOVE_BITS(1); /* '0' -> 8 extra length bits */
488 rundest = &window[window_posn]; 592 READ_BITS(extra_len, 8);
489 i = match_length; 593 }
490 /* does match offset wrap the window? */ 594 else if (PEEK_BITS(2) == 2) {
491 if (match_offset > window_posn) { 595 REMOVE_BITS(2); /* '10' -> 10 extra length bits + 0x100 */
492 /* j = length from match offset to end of window */ 596 READ_BITS(extra_len, 10);
493 j = match_offset - window_posn; 597 extra_len += 0x100;
494 if (j > (int) lzx->window_size) { 598 }
495 D(("match offset beyond window boundaries")) 599 else if (PEEK_BITS(3) == 6) {
496 return lzx->error = MSPACK_ERR_DECRUNCH; 600 REMOVE_BITS(3); /* '110' -> 12 extra length bits + 0x500 */
497 } 601 READ_BITS(extra_len, 12);
498 runsrc = &window[lzx->window_size - j]; 602 extra_len += 0x500;
499 if (j < i) { 603 }
500 /* if match goes over the window edge, do two copy runs */ 604 else {
501 i -= j; while (j-- > 0) *rundest++ = *runsrc++; 605 REMOVE_BITS(3); /* '111' -> 15 extra length bits */
502 runsrc = window; 606 READ_BITS(extra_len, 15);
503 } 607 }
504 while (i-- > 0) *rundest++ = *runsrc++; 608 match_length += extra_len;
505 } 609 }
506 else { 610
507 runsrc = rundest - match_offset; 611 if ((window_posn + match_length) > lzx->window_size) {
508 while (i-- > 0) *rundest++ = *runsrc++; 612 D(("match ran over window wrap"))
509 } 613 return lzx->error = MSPACK_ERR_DECRUNCH;
510 614 }
511 this_run -= match_length; 615
512 window_posn += match_length; 616 /* copy match */
513 } 617 rundest = &window[window_posn];
514 } /* while (this_run > 0) */ 618 i = match_length;
515 break; 619 /* does match offset wrap the window? */
620 if (match_offset > window_posn) {
621 if (match_offset > lzx->offset &&
622 (match_offset - window_posn) > lzx->ref_data_size)
623 {
624 D(("match offset beyond LZX stream"))
625 return lzx->error = MSPACK_ERR_DECRUNCH;
626 }
627 /* j = length from match offset to end of window */
628 j = match_offset - window_posn;
629 if (j > (int) lzx->window_size) {
630 D(("match offset beyond window boundaries"))
631 return lzx->error = MSPACK_ERR_DECRUNCH;
632 }
633 runsrc = &window[lzx->window_size - j];
634 if (j < i) {
635 /* if match goes over the window edge, do two copy runs */
636 i -= j; while (j-- > 0) *rundest++ = *runsrc++;
637 runsrc = window;
638 }
639 while (i-- > 0) *rundest++ = *runsrc++;
640 }
641 else {
642 runsrc = rundest - match_offset;
643 while (i-- > 0) *rundest++ = *runsrc++;
644 }
645
646 this_run -= match_length;
647 window_posn += match_length;
648 }
649 } /* while (this_run > 0) */
650 break;
516 651
517 case LZX_BLOCKTYPE_ALIGNED: 652 case LZX_BLOCKTYPE_ALIGNED:
518 while (this_run > 0) { 653 while (this_run > 0) {
519 READ_HUFFSYM(MAINTREE, main_element); 654 READ_HUFFSYM(MAINTREE, main_element);
520 if (main_element < LZX_NUM_CHARS) { 655 if (main_element < LZX_NUM_CHARS) {
521 /* literal: 0 to LZX_NUM_CHARS-1 */ 656 /* literal: 0 to LZX_NUM_CHARS-1 */
522 window[window_posn++] = main_element; 657 window[window_posn++] = main_element;
523 this_run--; 658 this_run--;
524 } 659 }
525 else { 660 else {
526 /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */ 661 /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
527 main_element -= LZX_NUM_CHARS; 662 main_element -= LZX_NUM_CHARS;
528 663
529 /* get match length */ 664 /* get match length */
530 match_length = main_element & LZX_NUM_PRIMARY_LENGTHS; 665 match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
531 if (match_length == LZX_NUM_PRIMARY_LENGTHS) { 666 if (match_length == LZX_NUM_PRIMARY_LENGTHS) {
532 if (lzx->LENGTH_empty) { 667 if (lzx->LENGTH_empty) {
533 D(("LENGTH symbol needed but tree is empty")) 668 D(("LENGTH symbol needed but tree is empty"))
534 return lzx->error = MSPACK_ERR_DECRUNCH; 669 return lzx->error = MSPACK_ERR_DECRUNCH;
535 } 670 }
536 READ_HUFFSYM(LENGTH, length_footer); 671 READ_HUFFSYM(LENGTH, length_footer);
537 match_length += length_footer; 672 match_length += length_footer;
538 } 673 }
539 match_length += LZX_MIN_MATCH; 674 match_length += LZX_MIN_MATCH;
540 675
541 /* get match offset */ 676 /* get match offset */
542 switch ((match_offset = (main_element >> 3))) { 677 switch ((match_offset = (main_element >> 3))) {
543 case 0: match_offset = R0; break; 678 case 0: match_offset = R0; break;
544 case 1: match_offset = R1; R1 = R0; R0 = match_offset; break; 679 case 1: match_offset = R1; R1 = R0; R0 = match_offset; break;
545 case 2: match_offset = R2; R2 = R0; R0 = match_offset; break; 680 case 2: match_offset = R2; R2 = R0; R0 = match_offset; break;
546 default: 681 default:
547 extra = extra_bits[match_offset]; 682 extra = (match_offset >= 36) ? 17 : extra_bits[match_offset];
548 match_offset = position_base[match_offset] - 2; 683 match_offset = position_base[match_offset] - 2;
549 if (extra > 3) { 684 if (extra > 3) {
550 /* verbatim and aligned bits */ 685 /* verbatim and aligned bits */
551 extra -= 3; 686 extra -= 3;
552 READ_BITS(verbatim_bits, extra); 687 READ_BITS(verbatim_bits, extra);
553 match_offset += (verbatim_bits << 3); 688 match_offset += (verbatim_bits << 3);
554 READ_HUFFSYM(ALIGNED, aligned_bits); 689 READ_HUFFSYM(ALIGNED, aligned_bits);
555 match_offset += aligned_bits; 690 match_offset += aligned_bits;
556 } 691 }
557 else if (extra == 3) { 692 else if (extra == 3) {
558 /* aligned bits only */ 693 /* aligned bits only */
559 READ_HUFFSYM(ALIGNED, aligned_bits); 694 READ_HUFFSYM(ALIGNED, aligned_bits);
560 match_offset += aligned_bits; 695 match_offset += aligned_bits;
561 } 696 }
562 else if (extra > 0) { /* extra==1, extra==2 */ 697 else if (extra > 0) { /* extra==1, extra==2 */
563 /* verbatim bits only */ 698 /* verbatim bits only */
564 READ_BITS(verbatim_bits, extra); 699 READ_BITS(verbatim_bits, extra);
565 match_offset += verbatim_bits; 700 match_offset += verbatim_bits;
566 } 701 }
567 else /* extra == 0 */ { 702 else /* extra == 0 */ {
568 /* ??? not defined in LZX specification! */ 703 /* ??? not defined in LZX specification! */
569 match_offset = 1; 704 match_offset = 1;
570 } 705 }
571 /* update repeated offset LRU queue */ 706 /* update repeated offset LRU queue */
572 R2 = R1; R1 = R0; R0 = match_offset; 707 R2 = R1; R1 = R0; R0 = match_offset;
573 } 708 }
574 709
575 if ((window_posn + match_length) > lzx->window_size) { 710 /* LZX DELTA uses max match length to signal even longer match */
576 D(("match ran over window wrap")) 711 if (match_length == LZX_MAX_MATCH && lzx->is_delta) {
577 return lzx->error = MSPACK_ERR_DECRUNCH; 712 int extra_len = 0;
578 } 713 ENSURE_BITS(3); /* 4 entry huffman tree */
579 714 if (PEEK_BITS(1) == 0) {
580 /* copy match */ 715 REMOVE_BITS(1); /* '0' -> 8 extra length bits */
581 rundest = &window[window_posn]; 716 READ_BITS(extra_len, 8);
582 i = match_length; 717 }
583 /* does match offset wrap the window? */ 718 else if (PEEK_BITS(2) == 2) {
584 if (match_offset > window_posn) { 719 REMOVE_BITS(2); /* '10' -> 10 extra length bits + 0x100 */
585 /* j = length from match offset to end of window */ 720 READ_BITS(extra_len, 10);
586 j = match_offset - window_posn; 721 extra_len += 0x100;
587 if (j > (int) lzx->window_size) { 722 }
588 D(("match offset beyond window boundaries")) 723 else if (PEEK_BITS(3) == 6) {
589 return lzx->error = MSPACK_ERR_DECRUNCH; 724 REMOVE_BITS(3); /* '110' -> 12 extra length bits + 0x500 */
590 } 725 READ_BITS(extra_len, 12);
591 runsrc = &window[lzx->window_size - j]; 726 extra_len += 0x500;
592 if (j < i) { 727 }
593 /* if match goes over the window edge, do two copy runs */ 728 else {
594 i -= j; while (j-- > 0) *rundest++ = *runsrc++; 729 REMOVE_BITS(3); /* '111' -> 15 extra length bits */
595 runsrc = window; 730 READ_BITS(extra_len, 15);
596 } 731 }
597 while (i-- > 0) *rundest++ = *runsrc++; 732 match_length += extra_len;
598 } 733 }
599 else { 734
600 runsrc = rundest - match_offset; 735 if ((window_posn + match_length) > lzx->window_size) {
601 while (i-- > 0) *rundest++ = *runsrc++; 736 D(("match ran over window wrap"))
602 } 737 return lzx->error = MSPACK_ERR_DECRUNCH;
603 738 }
604 this_run -= match_length; 739
605 window_posn += match_length; 740 /* copy match */
606 } 741 rundest = &window[window_posn];
607 } /* while (this_run > 0) */ 742 i = match_length;
608 break; 743 /* does match offset wrap the window? */
744 if (match_offset > window_posn) {
745 if (match_offset > lzx->offset &&
746 (match_offset - window_posn) > lzx->ref_data_size)
747 {
748 D(("match offset beyond LZX stream"))
749 return lzx->error = MSPACK_ERR_DECRUNCH;
750 }
751 /* j = length from match offset to end of window */
752 j = match_offset - window_posn;
753 if (j > (int) lzx->window_size) {
754 D(("match offset beyond window boundaries"))
755 return lzx->error = MSPACK_ERR_DECRUNCH;
756 }
757 runsrc = &window[lzx->window_size - j];
758 if (j < i) {
759 /* if match goes over the window edge, do two copy runs */
760 i -= j; while (j-- > 0) *rundest++ = *runsrc++;
761 runsrc = window;
762 }
763 while (i-- > 0) *rundest++ = *runsrc++;
764 }
765 else {
766 runsrc = rundest - match_offset;
767 while (i-- > 0) *rundest++ = *runsrc++;
768 }
769
770 this_run -= match_length;
771 window_posn += match_length;
772 }
773 } /* while (this_run > 0) */
774 break;
609 775
610 case LZX_BLOCKTYPE_UNCOMPRESSED: 776 case LZX_BLOCKTYPE_UNCOMPRESSED:
611 /* as this_run is limited not to wrap a frame, this also means it 777 /* as this_run is limited not to wrap a frame, this also means it
612 * won't wrap the window (as the window is a multiple of 32k) */ 778 * won't wrap the window (as the window is a multiple of 32k) */
613 rundest = &window[window_posn]; 779 rundest = &window[window_posn];
614 window_posn += this_run; 780 window_posn += this_run;
615 while (this_run > 0) { 781 while (this_run > 0) {
616 if ((i = i_end - i_ptr) == 0) { 782 if ((i = i_end - i_ptr) == 0) {
617 READ_IF_NEEDED; 783 READ_IF_NEEDED;
618 } 784 }
619 else { 785 else {
620 if (i > this_run) i = this_run; 786 if (i > this_run) i = this_run;
621 lzx->sys->copy(i_ptr, rundest, (size_t) i); 787 lzx->sys->copy(i_ptr, rundest, (size_t) i);
622 rundest += i; 788 rundest += i;
623 i_ptr += i; 789 i_ptr += i;
624 this_run -= i; 790 this_run -= i;
625 } 791 }
626 } 792 }
627 break; 793 break;
628 794
629 default: 795 default:
630 return lzx->error = MSPACK_ERR_DECRUNCH; /* might as well */ 796 return lzx->error = MSPACK_ERR_DECRUNCH; /* might as well */
631 } 797 }
632 798
633 /* did the final match overrun our desired this_run length? */ 799 /* did the final match overrun our desired this_run length? */
634 if (this_run < 0) { 800 if (this_run < 0) {
635 if ((unsigned int)(-this_run) > lzx->block_remaining) { 801 if ((unsigned int)(-this_run) > lzx->block_remaining) {
636 D(("overrun went past end of block by %d (%d remaining)", 802 D(("overrun went past end of block by %d (%d remaining)",
637 -this_run, lzx->block_remaining )) 803 -this_run, lzx->block_remaining ))
638 return lzx->error = MSPACK_ERR_DECRUNCH; 804 return lzx->error = MSPACK_ERR_DECRUNCH;
639 } 805 }
640 lzx->block_remaining -= -this_run; 806 lzx->block_remaining -= -this_run;
641 } 807 }
642 } /* while (bytes_todo > 0) */ 808 } /* while (bytes_todo > 0) */
643 809
644 /* streams don't extend over frame boundaries */ 810 /* streams don't extend over frame boundaries */
645 if ((window_posn - lzx->frame_posn) != frame_size) { 811 if ((window_posn - lzx->frame_posn) != frame_size) {
646 D(("decode beyond output frame limits! %d != %d", 812 D(("decode beyond output frame limits! %d != %d",
647 window_posn - lzx->frame_posn, frame_size)) 813 window_posn - lzx->frame_posn, frame_size))
648 return lzx->error = MSPACK_ERR_DECRUNCH; 814 return lzx->error = MSPACK_ERR_DECRUNCH;
649 } 815 }
650 816
@@ -654,13 +820,14 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
654 820
655 /* check that we've used all of the previous frame first */ 821 /* check that we've used all of the previous frame first */
656 if (lzx->o_ptr != lzx->o_end) { 822 if (lzx->o_ptr != lzx->o_end) {
657 D(("%ld avail bytes, new %d frame", lzx->o_end-lzx->o_ptr, frame_size)) 823 D(("%ld avail bytes, new %d frame",
824 (long)(lzx->o_end - lzx->o_ptr), frame_size))
658 return lzx->error = MSPACK_ERR_DECRUNCH; 825 return lzx->error = MSPACK_ERR_DECRUNCH;
659 } 826 }
660 827
661 /* does this intel block _really_ need decoding? */ 828 /* does this intel block _really_ need decoding? */
662 if (lzx->intel_started && lzx->intel_filesize && 829 if (lzx->intel_started && lzx->intel_filesize &&
663 (lzx->frame <= 32768) && (frame_size > 10)) 830 (lzx->frame <= 32768) && (frame_size > 10))
664 { 831 {
665 unsigned char *data = &lzx->e8_buf[0]; 832 unsigned char *data = &lzx->e8_buf[0];
666 unsigned char *dataend = &lzx->e8_buf[frame_size - 10]; 833 unsigned char *dataend = &lzx->e8_buf[frame_size - 10];
@@ -673,17 +840,17 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) {
673 lzx->sys->copy(&lzx->window[lzx->frame_posn], data, frame_size); 840 lzx->sys->copy(&lzx->window[lzx->frame_posn], data, frame_size);
674 841
675 while (data < dataend) { 842 while (data < dataend) {
676 if (*data++ != 0xE8) { curpos++; continue; } 843 if (*data++ != 0xE8) { curpos++; continue; }
677 abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24); 844 abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
678 if ((abs_off >= -curpos) && (abs_off < filesize)) { 845 if ((abs_off >= -curpos) && (abs_off < filesize)) {
679 rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize; 846 rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
680 data[0] = (unsigned char) rel_off; 847 data[0] = (unsigned char) rel_off;
681 data[1] = (unsigned char) (rel_off >> 8); 848 data[1] = (unsigned char) (rel_off >> 8);
682 data[2] = (unsigned char) (rel_off >> 16); 849 data[2] = (unsigned char) (rel_off >> 16);
683 data[3] = (unsigned char) (rel_off >> 24); 850 data[3] = (unsigned char) (rel_off >> 24);
684 } 851 }
685 data += 4; 852 data += 4;
686 curpos += 5; 853 curpos += 5;
687 } 854 }
688 lzx->intel_curpos += frame_size; 855 lzx->intel_curpos += frame_size;
689 } 856 }
diff --git a/rbutil/rbutilqt/mspack/mspack.h b/rbutil/rbutilqt/mspack/mspack.h
index 7f6bdf1465..3e99624463 100644
--- a/rbutil/rbutilqt/mspack/mspack.h
+++ b/rbutil/rbutilqt/mspack/mspack.h
@@ -1,5 +1,5 @@
1/* libmspack -- a library for working with Microsoft compression formats. 1/* libmspack -- a library for working with Microsoft compression formats.
2 * (C) 2003-2011 Stuart Caie <kyzer@4u.net> 2 * (C) 2003-2019 Stuart Caie <kyzer@cabextract.org.uk>
3 * 3 *
4 * libmspack is free software; you can redistribute it and/or modify it under 4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1 5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
@@ -30,6 +30,7 @@
30 * - .CAB (MS Cabinet) files, which use deflate, LZX or Quantum compression 30 * - .CAB (MS Cabinet) files, which use deflate, LZX or Quantum compression
31 * - .CHM (HTML Help) files, which use LZX compression 31 * - .CHM (HTML Help) files, which use LZX compression
32 * - .LIT (MS EBook) files, which use LZX compression and DES encryption 32 * - .LIT (MS EBook) files, which use LZX compression and DES encryption
33 * - .LZX (Exchange Offline Addressbook) files, which use LZX compression
33 * 34 *
34 * To determine the capabilities of the library, and the binary 35 * To determine the capabilities of the library, and the binary
35 * compatibility version of any particular compressor or decompressor, use 36 * compatibility version of any particular compressor or decompressor, use
@@ -60,6 +61,7 @@
60 * - mspack_create_hlp_compressor() creates a mshlp_compressor 61 * - mspack_create_hlp_compressor() creates a mshlp_compressor
61 * - mspack_create_szdd_compressor() creates a msszdd_compressor 62 * - mspack_create_szdd_compressor() creates a msszdd_compressor
62 * - mspack_create_kwaj_compressor() creates a mskwaj_compressor 63 * - mspack_create_kwaj_compressor() creates a mskwaj_compressor
64 * - mspack_create_oab_compressor() creates a msoab_compressor
63 * 65 *
64 * For decompression: 66 * For decompression:
65 * - mspack_create_cab_decompressor() creates a mscab_decompressor 67 * - mspack_create_cab_decompressor() creates a mscab_decompressor
@@ -68,6 +70,7 @@
68 * - mspack_create_hlp_decompressor() creates a mshlp_decompressor 70 * - mspack_create_hlp_decompressor() creates a mshlp_decompressor
69 * - mspack_create_szdd_decompressor() creates a msszdd_decompressor 71 * - mspack_create_szdd_decompressor() creates a msszdd_decompressor
70 * - mspack_create_kwaj_decompressor() creates a mskwaj_decompressor 72 * - mspack_create_kwaj_decompressor() creates a mskwaj_decompressor
73 * - mspack_create_oab_decompressor() creates a msoab_decompressor
71 * 74 *
72 * Once finished working with a format, each kind of 75 * Once finished working with a format, each kind of
73 * compressor/decompressor has its own specific destructor: 76 * compressor/decompressor has its own specific destructor:
@@ -83,6 +86,8 @@
83 * - mspack_destroy_szdd_decompressor() 86 * - mspack_destroy_szdd_decompressor()
84 * - mspack_destroy_kwaj_compressor() 87 * - mspack_destroy_kwaj_compressor()
85 * - mspack_destroy_kwaj_decompressor() 88 * - mspack_destroy_kwaj_decompressor()
89 * - mspack_destroy_oab_compressor()
90 * - mspack_destroy_oab_decompressor()
86 * 91 *
87 * Destroying a compressor or decompressor does not destroy any objects, 92 * Destroying a compressor or decompressor does not destroy any objects,
88 * structures or handles that have been created using that compressor or 93 * structures or handles that have been created using that compressor or
@@ -208,6 +213,8 @@ extern int mspack_sys_selftest_internal(int);
208 * - #MSPACK_VER_MSSZDDC: the msszdd_compressor interface 213 * - #MSPACK_VER_MSSZDDC: the msszdd_compressor interface
209 * - #MSPACK_VER_MSKWAJD: the mskwaj_decompressor interface 214 * - #MSPACK_VER_MSKWAJD: the mskwaj_decompressor interface
210 * - #MSPACK_VER_MSKWAJC: the mskwaj_compressor interface 215 * - #MSPACK_VER_MSKWAJC: the mskwaj_compressor interface
216 * - #MSPACK_VER_MSOABD: the msoab_decompressor interface
217 * - #MSPACK_VER_MSOABC: the msoab_compressor interface
211 * 218 *
212 * The result of the function should be interpreted as follows: 219 * The result of the function should be interpreted as follows:
213 * - -1: this interface is completely unknown to the library 220 * - -1: this interface is completely unknown to the library
@@ -249,6 +256,10 @@ extern int mspack_version(int entity);
249#define MSPACK_VER_MSKWAJD (12) 256#define MSPACK_VER_MSKWAJD (12)
250/** Pass to mspack_version() to get the mskwaj_compressor version */ 257/** Pass to mspack_version() to get the mskwaj_compressor version */
251#define MSPACK_VER_MSKWAJC (13) 258#define MSPACK_VER_MSKWAJC (13)
259/** Pass to mspack_version() to get the msoab_decompressor version */
260#define MSPACK_VER_MSOABD (14)
261/** Pass to mspack_version() to get the msoab_compressor version */
262#define MSPACK_VER_MSOABC (15)
252 263
253/* --- file I/O abstraction ------------------------------------------------ */ 264/* --- file I/O abstraction ------------------------------------------------ */
254 265
@@ -297,8 +308,8 @@ struct mspack_system {
297 * @see close(), read(), write(), seek(), tell(), message() 308 * @see close(), read(), write(), seek(), tell(), message()
298 */ 309 */
299 struct mspack_file * (*open)(struct mspack_system *self, 310 struct mspack_file * (*open)(struct mspack_system *self,
300 const char *filename, 311 const char *filename,
301 int mode); 312 int mode);
302 313
303 /** 314 /**
304 * Closes a previously opened file. If any memory was allocated for this 315 * Closes a previously opened file. If any memory was allocated for this
@@ -317,12 +328,14 @@ struct mspack_system {
317 * @param bytes the number of bytes to read from the file. 328 * @param bytes the number of bytes to read from the file.
318 * @return the number of bytes successfully read (this can be less than 329 * @return the number of bytes successfully read (this can be less than
319 * the number requested), zero to mark the end of file, or less 330 * the number requested), zero to mark the end of file, or less
320 * than zero to indicate an error. 331 * than zero to indicate an error. The library does not "retry"
332 * reads and assumes short reads are due to EOF, so you should
333 * avoid returning short reads because of transient errors.
321 * @see open(), write() 334 * @see open(), write()
322 */ 335 */
323 int (*read)(struct mspack_file *file, 336 int (*read)(struct mspack_file *file,
324 void *buffer, 337 void *buffer,
325 int bytes); 338 int bytes);
326 339
327 /** 340 /**
328 * Writes a given number of bytes to an open file. 341 * Writes a given number of bytes to an open file.
@@ -338,8 +351,8 @@ struct mspack_system {
338 * @see open(), read() 351 * @see open(), read()
339 */ 352 */
340 int (*write)(struct mspack_file *file, 353 int (*write)(struct mspack_file *file,
341 void *buffer, 354 void *buffer,
342 int bytes); 355 int bytes);
343 356
344 /** 357 /**
345 * Seeks to a specific file offset within an open file. 358 * Seeks to a specific file offset within an open file.
@@ -365,8 +378,8 @@ struct mspack_system {
365 * @see open(), tell() 378 * @see open(), tell()
366 */ 379 */
367 int (*seek)(struct mspack_file *file, 380 int (*seek)(struct mspack_file *file,
368 off_t offset, 381 off_t offset,
369 int mode); 382 int mode);
370 383
371 /** 384 /**
372 * Returns the current file position (in bytes) of the given file. 385 * Returns the current file position (in bytes) of the given file.
@@ -392,8 +405,8 @@ struct mspack_system {
392 * @see open() 405 * @see open()
393 */ 406 */
394 void (*message)(struct mspack_file *file, 407 void (*message)(struct mspack_file *file,
395 const char *format, 408 const char *format,
396 ...); 409 ...);
397 410
398 /** 411 /**
399 * Allocates memory. 412 * Allocates memory.
@@ -406,12 +419,12 @@ struct mspack_system {
406 * @see free() 419 * @see free()
407 */ 420 */
408 void * (*alloc)(struct mspack_system *self, 421 void * (*alloc)(struct mspack_system *self,
409 size_t bytes); 422 size_t bytes);
410 423
411 /** 424 /**
412 * Frees memory. 425 * Frees memory.
413 * 426 *
414 * @param ptr the memory to be freed. 427 * @param ptr the memory to be freed. NULL is accepted and ignored.
415 * @see alloc() 428 * @see alloc()
416 */ 429 */
417 void (*free)(void *ptr); 430 void (*free)(void *ptr);
@@ -429,8 +442,8 @@ struct mspack_system {
429 * @param bytes the size of the memory region, in bytes 442 * @param bytes the size of the memory region, in bytes
430 */ 443 */
431 void (*copy)(void *src, 444 void (*copy)(void *src,
432 void *dest, 445 void *dest,
433 size_t bytes); 446 size_t bytes);
434 447
435 /** 448 /**
436 * A null pointer to mark the end of mspack_system. It must equal NULL. 449 * 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);
645extern void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *self); 658extern void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *self);
646 659
647 660
661/** Creates a new OAB compressor.
662 * @param sys a custom mspack_system structure, or NULL to use the default
663 * @return a #msoab_compressor or NULL
664 */
665extern struct msoab_compressor *
666 mspack_create_oab_compressor(struct mspack_system *sys);
667
668/** Creates a new OAB decompressor.
669 * @param sys a custom mspack_system structure, or NULL to use the default
670 * @return a #msoab_decompressor or NULL
671 */
672extern struct msoab_decompressor *
673 mspack_create_oab_decompressor(struct mspack_system *sys);
674
675/** Destroys an existing OAB compressor.
676 * @param self the #msoab_compressor to destroy
677 */
678extern void mspack_destroy_oab_compressor(struct msoab_compressor *self);
679
680/** Destroys an existing OAB decompressor.
681 * @param self the #msoab_decompressor to destroy
682 */
683extern void mspack_destroy_oab_decompressor(struct msoab_decompressor *self);
684
685
648/* --- support for .CAB (MS Cabinet) file format --------------------------- */ 686/* --- support for .CAB (MS Cabinet) file format --------------------------- */
649 687
650/** 688/**
@@ -896,6 +934,13 @@ struct mscabd_file {
896#define MSCABD_PARAM_FIXMSZIP (1) 934#define MSCABD_PARAM_FIXMSZIP (1)
897/** mscab_decompressor::set_param() parameter: size of decompression buffer */ 935/** mscab_decompressor::set_param() parameter: size of decompression buffer */
898#define MSCABD_PARAM_DECOMPBUF (2) 936#define MSCABD_PARAM_DECOMPBUF (2)
937/** mscab_decompressor::set_param() parameter: salvage data from bad cabinets?
938 * If enabled, open() will skip file with bad folder indices or filenames
939 * rather than reject the whole cabinet, and extract() will limit rather than
940 * reject files with invalid offsets and lengths, and bad data block checksums
941 * will be ignored. Available only in CAB decoder version 2 and above.
942 */
943#define MSCABD_PARAM_SALVAGE (3)
899 944
900/** TODO */ 945/** TODO */
901struct mscab_compressor { 946struct mscab_compressor {
@@ -931,7 +976,7 @@ struct mscab_decompressor {
931 * @see close(), search(), last_error() 976 * @see close(), search(), last_error()
932 */ 977 */
933 struct mscabd_cabinet * (*open) (struct mscab_decompressor *self, 978 struct mscabd_cabinet * (*open) (struct mscab_decompressor *self,
934 const char *filename); 979 const char *filename);
935 980
936 /** 981 /**
937 * Closes a previously opened cabinet or cabinet set. 982 * Closes a previously opened cabinet or cabinet set.
@@ -963,7 +1008,7 @@ struct mscab_decompressor {
963 * @see open(), search(), append(), prepend() 1008 * @see open(), search(), append(), prepend()
964 */ 1009 */
965 void (*close)(struct mscab_decompressor *self, 1010 void (*close)(struct mscab_decompressor *self,
966 struct mscabd_cabinet *cab); 1011 struct mscabd_cabinet *cab);
967 1012
968 /** 1013 /**
969 * Searches a regular file for embedded cabinets. 1014 * Searches a regular file for embedded cabinets.
@@ -1000,7 +1045,7 @@ struct mscab_decompressor {
1000 * @see close(), open(), last_error() 1045 * @see close(), open(), last_error()
1001 */ 1046 */
1002 struct mscabd_cabinet * (*search) (struct mscab_decompressor *self, 1047 struct mscabd_cabinet * (*search) (struct mscab_decompressor *self,
1003 const char *filename); 1048 const char *filename);
1004 1049
1005 /** 1050 /**
1006 * Appends one mscabd_cabinet to another, forming or extending a cabinet 1051 * Appends one mscabd_cabinet to another, forming or extending a cabinet
@@ -1043,8 +1088,8 @@ struct mscab_decompressor {
1043 * @see prepend(), open(), close() 1088 * @see prepend(), open(), close()
1044 */ 1089 */
1045 int (*append) (struct mscab_decompressor *self, 1090 int (*append) (struct mscab_decompressor *self,
1046 struct mscabd_cabinet *cab, 1091 struct mscabd_cabinet *cab,
1047 struct mscabd_cabinet *nextcab); 1092 struct mscabd_cabinet *nextcab);
1048 1093
1049 /** 1094 /**
1050 * Prepends one mscabd_cabinet to another, forming or extending a 1095 * Prepends one mscabd_cabinet to another, forming or extending a
@@ -1065,8 +1110,8 @@ struct mscab_decompressor {
1065 * @see append(), open(), close() 1110 * @see append(), open(), close()
1066 */ 1111 */
1067 int (*prepend) (struct mscab_decompressor *self, 1112 int (*prepend) (struct mscab_decompressor *self,
1068 struct mscabd_cabinet *cab, 1113 struct mscabd_cabinet *cab,
1069 struct mscabd_cabinet *prevcab); 1114 struct mscabd_cabinet *prevcab);
1070 1115
1071 /** 1116 /**
1072 * Extracts a file from a cabinet or cabinet set. 1117 * Extracts a file from a cabinet or cabinet set.
@@ -1091,8 +1136,8 @@ struct mscab_decompressor {
1091 * @return an error code, or MSPACK_ERR_OK if successful 1136 * @return an error code, or MSPACK_ERR_OK if successful
1092 */ 1137 */
1093 int (*extract)(struct mscab_decompressor *self, 1138 int (*extract)(struct mscab_decompressor *self,
1094 struct mscabd_file *file, 1139 struct mscabd_file *file,
1095 const char *filename); 1140 const char *filename);
1096 1141
1097 /** 1142 /**
1098 * Sets a CAB decompression engine parameter. 1143 * Sets a CAB decompression engine parameter.
@@ -1117,8 +1162,8 @@ struct mscab_decompressor {
1117 * @see search(), extract() 1162 * @see search(), extract()
1118 */ 1163 */
1119 int (*set_param)(struct mscab_decompressor *self, 1164 int (*set_param)(struct mscab_decompressor *self,
1120 int param, 1165 int param,
1121 int value); 1166 int value);
1122 1167
1123 /** 1168 /**
1124 * Returns the error code set by the most recently called method. 1169 * Returns the error code set by the most recently called method.
@@ -1403,8 +1448,8 @@ struct mschm_compressor {
1403 * @see use_temporary_file() set_param() 1448 * @see use_temporary_file() set_param()
1404 */ 1449 */
1405 int (*generate)(struct mschm_compressor *self, 1450 int (*generate)(struct mschm_compressor *self,
1406 struct mschmc_file file_list[], 1451 struct mschmc_file file_list[],
1407 const char *output_file); 1452 const char *output_file);
1408 1453
1409 /** 1454 /**
1410 * Specifies whether a temporary file is used during CHM generation. 1455 * Specifies whether a temporary file is used during CHM generation.
@@ -1460,8 +1505,8 @@ struct mschm_compressor {
1460 * @see generate() 1505 * @see generate()
1461 */ 1506 */
1462 int (*use_temporary_file)(struct mschm_compressor *self, 1507 int (*use_temporary_file)(struct mschm_compressor *self,
1463 int use_temp_file, 1508 int use_temp_file,
1464 const char *temp_file); 1509 const char *temp_file);
1465 /** 1510 /**
1466 * Sets a CHM compression engine parameter. 1511 * Sets a CHM compression engine parameter.
1467 * 1512 *
@@ -1508,8 +1553,8 @@ struct mschm_compressor {
1508 * @see generate() 1553 * @see generate()
1509 */ 1554 */
1510 int (*set_param)(struct mschm_compressor *self, 1555 int (*set_param)(struct mschm_compressor *self,
1511 int param, 1556 int param,
1512 unsigned int value); 1557 int value);
1513 1558
1514 /** 1559 /**
1515 * Returns the error code set by the most recently called method. 1560 * Returns the error code set by the most recently called method.
@@ -1551,7 +1596,7 @@ struct mschm_decompressor {
1551 * @see close() 1596 * @see close()
1552 */ 1597 */
1553 struct mschmd_header *(*open)(struct mschm_decompressor *self, 1598 struct mschmd_header *(*open)(struct mschm_decompressor *self,
1554 const char *filename); 1599 const char *filename);
1555 1600
1556 /** 1601 /**
1557 * Closes a previously opened CHM helpfile. 1602 * Closes a previously opened CHM helpfile.
@@ -1571,7 +1616,7 @@ struct mschm_decompressor {
1571 * @see open(), fast_open() 1616 * @see open(), fast_open()
1572 */ 1617 */
1573 void (*close)(struct mschm_decompressor *self, 1618 void (*close)(struct mschm_decompressor *self,
1574 struct mschmd_header *chm); 1619 struct mschmd_header *chm);
1575 1620
1576 /** 1621 /**
1577 * Extracts a file from a CHM helpfile. 1622 * Extracts a file from a CHM helpfile.
@@ -1592,8 +1637,8 @@ struct mschm_decompressor {
1592 * @return an error code, or MSPACK_ERR_OK if successful 1637 * @return an error code, or MSPACK_ERR_OK if successful
1593 */ 1638 */
1594 int (*extract)(struct mschm_decompressor *self, 1639 int (*extract)(struct mschm_decompressor *self,
1595 struct mschmd_file *file, 1640 struct mschmd_file *file,
1596 const char *filename); 1641 const char *filename);
1597 1642
1598 /** 1643 /**
1599 * Returns the error code set by the most recently called method. 1644 * Returns the error code set by the most recently called method.
@@ -1631,7 +1676,7 @@ struct mschm_decompressor {
1631 * @see open(), close(), fast_find(), extract() 1676 * @see open(), close(), fast_find(), extract()
1632 */ 1677 */
1633 struct mschmd_header *(*fast_open)(struct mschm_decompressor *self, 1678 struct mschmd_header *(*fast_open)(struct mschm_decompressor *self,
1634 const char *filename); 1679 const char *filename);
1635 1680
1636 /** 1681 /**
1637 * Finds file details quickly. 1682 * Finds file details quickly.
@@ -1672,10 +1717,10 @@ struct mschm_decompressor {
1672 * @see open(), close(), fast_find(), extract() 1717 * @see open(), close(), fast_find(), extract()
1673 */ 1718 */
1674 int (*fast_find)(struct mschm_decompressor *self, 1719 int (*fast_find)(struct mschm_decompressor *self,
1675 struct mschmd_header *chm, 1720 struct mschmd_header *chm,
1676 const char *filename, 1721 const char *filename,
1677 struct mschmd_file *f_ptr, 1722 struct mschmd_file *f_ptr,
1678 int f_size); 1723 int f_size);
1679}; 1724};
1680 1725
1681/* --- support for .LIT (EBook) file format -------------------------------- */ 1726/* --- support for .LIT (EBook) file format -------------------------------- */
@@ -1781,9 +1826,9 @@ struct msszdd_compressor {
1781 * @see set_param() 1826 * @see set_param()
1782 */ 1827 */
1783 int (*compress)(struct msszdd_compressor *self, 1828 int (*compress)(struct msszdd_compressor *self,
1784 const char *input, 1829 const char *input,
1785 const char *output, 1830 const char *output,
1786 off_t length); 1831 off_t length);
1787 1832
1788 /** 1833 /**
1789 * Sets an SZDD compression engine parameter. 1834 * Sets an SZDD compression engine parameter.
@@ -1807,8 +1852,8 @@ struct msszdd_compressor {
1807 * @see compress() 1852 * @see compress()
1808 */ 1853 */
1809 int (*set_param)(struct msszdd_compressor *self, 1854 int (*set_param)(struct msszdd_compressor *self,
1810 int param, 1855 int param,
1811 unsigned int value); 1856 int value);
1812 1857
1813 /** 1858 /**
1814 * Returns the error code set by the most recently called method. 1859 * Returns the error code set by the most recently called method.
@@ -1849,7 +1894,7 @@ struct msszdd_decompressor {
1849 * @see close() 1894 * @see close()
1850 */ 1895 */
1851 struct msszddd_header *(*open)(struct msszdd_decompressor *self, 1896 struct msszddd_header *(*open)(struct msszdd_decompressor *self,
1852 const char *filename); 1897 const char *filename);
1853 1898
1854 /** 1899 /**
1855 * Closes a previously opened SZDD file. 1900 * Closes a previously opened SZDD file.
@@ -1865,7 +1910,7 @@ struct msszdd_decompressor {
1865 * @see open() 1910 * @see open()
1866 */ 1911 */
1867 void (*close)(struct msszdd_decompressor *self, 1912 void (*close)(struct msszdd_decompressor *self,
1868 struct msszddd_header *szdd); 1913 struct msszddd_header *szdd);
1869 1914
1870 /** 1915 /**
1871 * Extracts the compressed data from a SZDD file. 1916 * Extracts the compressed data from a SZDD file.
@@ -1881,8 +1926,8 @@ struct msszdd_decompressor {
1881 * @return an error code, or MSPACK_ERR_OK if successful 1926 * @return an error code, or MSPACK_ERR_OK if successful
1882 */ 1927 */
1883 int (*extract)(struct msszdd_decompressor *self, 1928 int (*extract)(struct msszdd_decompressor *self,
1884 struct msszddd_header *szdd, 1929 struct msszddd_header *szdd,
1885 const char *filename); 1930 const char *filename);
1886 1931
1887 /** 1932 /**
1888 * Decompresses an SZDD file to an output file in one step. 1933 * Decompresses an SZDD file to an output file in one step.
@@ -1902,8 +1947,8 @@ struct msszdd_decompressor {
1902 * @return an error code, or MSPACK_ERR_OK if successful 1947 * @return an error code, or MSPACK_ERR_OK if successful
1903 */ 1948 */
1904 int (*decompress)(struct msszdd_decompressor *self, 1949 int (*decompress)(struct msszdd_decompressor *self,
1905 const char *input, 1950 const char *input,
1906 const char *output); 1951 const char *output);
1907 1952
1908 /** 1953 /**
1909 * Returns the error code set by the most recently called method. 1954 * Returns the error code set by the most recently called method.
@@ -1937,6 +1982,8 @@ struct msszdd_decompressor {
1937#define MSKWAJ_COMP_SZDD (2) 1982#define MSKWAJ_COMP_SZDD (2)
1938/** KWAJ compression type: LZ+Huffman compression */ 1983/** KWAJ compression type: LZ+Huffman compression */
1939#define MSKWAJ_COMP_LZH (3) 1984#define MSKWAJ_COMP_LZH (3)
1985/** KWAJ compression type: MSZIP */
1986#define MSKWAJ_COMP_MSZIP (4)
1940 1987
1941/** KWAJ optional header flag: decompressed file length is included */ 1988/** KWAJ optional header flag: decompressed file length is included */
1942#define MSKWAJ_HDR_HASLENGTH (0x01) 1989#define MSKWAJ_HDR_HASLENGTH (0x01)
@@ -2015,9 +2062,9 @@ struct mskwaj_compressor {
2015 * @see set_param() 2062 * @see set_param()
2016 */ 2063 */
2017 int (*compress)(struct mskwaj_compressor *self, 2064 int (*compress)(struct mskwaj_compressor *self,
2018 const char *input, 2065 const char *input,
2019 const char *output, 2066 const char *output,
2020 off_t length); 2067 off_t length);
2021 2068
2022 /** 2069 /**
2023 * Sets an KWAJ compression engine parameter. 2070 * Sets an KWAJ compression engine parameter.
@@ -2043,8 +2090,8 @@ struct mskwaj_compressor {
2043 * @see generate() 2090 * @see generate()
2044 */ 2091 */
2045 int (*set_param)(struct mskwaj_compressor *self, 2092 int (*set_param)(struct mskwaj_compressor *self,
2046 int param, 2093 int param,
2047 unsigned int value); 2094 int value);
2048 2095
2049 2096
2050 /** 2097 /**
@@ -2065,7 +2112,7 @@ struct mskwaj_compressor {
2065 * filename is too long 2112 * filename is too long
2066 */ 2113 */
2067 int (*set_filename)(struct mskwaj_compressor *self, 2114 int (*set_filename)(struct mskwaj_compressor *self,
2068 const char *filename); 2115 const char *filename);
2069 2116
2070 /** 2117 /**
2071 * Sets arbitrary data that will be stored in the header of the 2118 * Sets arbitrary data that will be stored in the header of the
@@ -2085,8 +2132,8 @@ struct mskwaj_compressor {
2085 * is too long 2132 * is too long
2086 */ 2133 */
2087 int (*set_extra_data)(struct mskwaj_compressor *self, 2134 int (*set_extra_data)(struct mskwaj_compressor *self,
2088 void *data, 2135 void *data,
2089 size_t bytes); 2136 size_t bytes);
2090 2137
2091 /** 2138 /**
2092 * Returns the error code set by the most recently called method. 2139 * Returns the error code set by the most recently called method.
@@ -2127,7 +2174,7 @@ struct mskwaj_decompressor {
2127 * @see close() 2174 * @see close()
2128 */ 2175 */
2129 struct mskwajd_header *(*open)(struct mskwaj_decompressor *self, 2176 struct mskwajd_header *(*open)(struct mskwaj_decompressor *self,
2130 const char *filename); 2177 const char *filename);
2131 2178
2132 /** 2179 /**
2133 * Closes a previously opened KWAJ file. 2180 * Closes a previously opened KWAJ file.
@@ -2142,7 +2189,7 @@ struct mskwaj_decompressor {
2142 * @see open() 2189 * @see open()
2143 */ 2190 */
2144 void (*close)(struct mskwaj_decompressor *self, 2191 void (*close)(struct mskwaj_decompressor *self,
2145 struct mskwajd_header *kwaj); 2192 struct mskwajd_header *kwaj);
2146 2193
2147 /** 2194 /**
2148 * Extracts the compressed data from a KWAJ file. 2195 * Extracts the compressed data from a KWAJ file.
@@ -2158,8 +2205,8 @@ struct mskwaj_decompressor {
2158 * @return an error code, or MSPACK_ERR_OK if successful 2205 * @return an error code, or MSPACK_ERR_OK if successful
2159 */ 2206 */
2160 int (*extract)(struct mskwaj_decompressor *self, 2207 int (*extract)(struct mskwaj_decompressor *self,
2161 struct mskwajd_header *kwaj, 2208 struct mskwajd_header *kwaj,
2162 const char *filename); 2209 const char *filename);
2163 2210
2164 /** 2211 /**
2165 * Decompresses an KWAJ file to an output file in one step. 2212 * Decompresses an KWAJ file to an output file in one step.
@@ -2179,8 +2226,8 @@ struct mskwaj_decompressor {
2179 * @return an error code, or MSPACK_ERR_OK if successful 2226 * @return an error code, or MSPACK_ERR_OK if successful
2180 */ 2227 */
2181 int (*decompress)(struct mskwaj_decompressor *self, 2228 int (*decompress)(struct mskwaj_decompressor *self,
2182 const char *input, 2229 const char *input,
2183 const char *output); 2230 const char *output);
2184 2231
2185 /** 2232 /**
2186 * Returns the error code set by the most recently called method. 2233 * Returns the error code set by the most recently called method.
@@ -2196,6 +2243,141 @@ struct mskwaj_decompressor {
2196 int (*last_error)(struct mskwaj_decompressor *self); 2243 int (*last_error)(struct mskwaj_decompressor *self);
2197}; 2244};
2198 2245
2246/* --- support for .LZX (Offline Address Book) file format ----------------- */
2247
2248/**
2249 * A compressor for the Offline Address Book (OAB) format.
2250 *
2251 * All fields are READ ONLY.
2252 *
2253 * @see mspack_create_oab_compressor(), mspack_destroy_oab_compressor()
2254 */
2255struct msoab_compressor {
2256 /**
2257 * Compress a full OAB file.
2258 *
2259 * The input file will be read and the compressed contents written to the
2260 * output file.
2261 *
2262 * @param self a self-referential pointer to the msoab_decompressor
2263 * instance being called
2264 * @param input the filename of the input file. This is passed
2265 * directly to mspack_system::open().
2266 * @param output the filename of the output file. This is passed
2267 * directly to mspack_system::open().
2268 * @return an error code, or MSPACK_ERR_OK if successful
2269 */
2270 int (*compress) (struct msoab_compressor *self,
2271 const char *input,
2272 const char *output);
2273
2274 /**
2275 * Generate a compressed incremental OAB patch file.
2276 *
2277 * The two uncompressed files "input" and "base" will be read, and an
2278 * incremental patch to generate "input" from "base" will be written to
2279 * the output file.
2280 *
2281 * @param self a self-referential pointer to the msoab_compressor
2282 * instance being called
2283 * @param input the filename of the input file containing the new
2284 * version of its contents. This is passed directly
2285 * to mspack_system::open().
2286 * @param base the filename of the original base file containing
2287 * the old version of its contents, against which the
2288 * incremental patch shall generated. This is passed
2289 * directly to mspack_system::open().
2290 * @param output the filename of the output file. This is passed
2291 * directly to mspack_system::open().
2292 * @return an error code, or MSPACK_ERR_OK if successful
2293 */
2294 int (*compress_incremental) (struct msoab_compressor *self,
2295 const char *input,
2296 const char *base,
2297 const char *output);
2298};
2299
2300/**
2301 * A decompressor for .LZX (Offline Address Book) files
2302 *
2303 * All fields are READ ONLY.
2304 *
2305 * @see mspack_create_oab_decompressor(), mspack_destroy_oab_decompressor()
2306 */
2307struct msoab_decompressor {
2308 /**
2309 * Decompresses a full Offline Address Book file.
2310 *
2311 * If the input file is a valid compressed Offline Address Book file,
2312 * it will be read and the decompressed contents will be written to
2313 * the output file.
2314 *
2315 * @param self a self-referential pointer to the msoab_decompressor
2316 * instance being called
2317 * @param input the filename of the input file. This is passed
2318 * directly to mspack_system::open().
2319 * @param output the filename of the output file. This is passed
2320 * directly to mspack_system::open().
2321 * @return an error code, or MSPACK_ERR_OK if successful
2322 */
2323 int (*decompress) (struct msoab_decompressor *self,
2324 const char *input,
2325 const char *output);
2326
2327 /**
2328 * Decompresses an Offline Address Book with an incremental patch file.
2329 *
2330 * This requires both a full UNCOMPRESSED Offline Address Book file to
2331 * act as the "base", and a compressed incremental patch file as input.
2332 * If the input file is valid, it will be decompressed with reference to
2333 * the base file, and the decompressed contents will be written to the
2334 * output file.
2335 *
2336 * There is no way to tell what the right base file is for the given
2337 * incremental patch, but if you get it wrong, this will usually result
2338 * in incorrect data being decompressed, which will then fail a checksum
2339 * test.
2340 *
2341 * @param self a self-referential pointer to the msoab_decompressor
2342 * instance being called
2343 * @param input the filename of the input file. This is passed
2344 * directly to mspack_system::open().
2345 * @param base the filename of the base file to which the
2346 * incremental patch shall be applied. This is passed
2347 * directly to mspack_system::open().
2348 * @param output the filename of the output file. This is passed
2349 * directly to mspack_system::open().
2350 * @return an error code, or MSPACK_ERR_OK if successful
2351 */
2352 int (*decompress_incremental) (struct msoab_decompressor *self,
2353 const char *input,
2354 const char *base,
2355 const char *output);
2356
2357 /**
2358 * Sets an OAB decompression engine parameter. Available only in OAB
2359 * decompressor version 2 and above.
2360 *
2361 * - #MSOABD_PARAM_DECOMPBUF: How many bytes should be used as an input
2362 * buffer by decompressors? The minimum value is 16. The default value
2363 * is 4096.
2364 *
2365 * @param self a self-referential pointer to the msoab_decompressor
2366 * instance being called
2367 * @param param the parameter to set
2368 * @param value the value to set the parameter to
2369 * @return MSPACK_ERR_OK if all is OK, or MSPACK_ERR_ARGS if there
2370 * is a problem with either parameter or value.
2371 */
2372 int (*set_param)(struct msoab_decompressor *self,
2373 int param,
2374 int value);
2375
2376};
2377
2378/** msoab_decompressor::set_param() parameter: size of decompression buffer */
2379#define MSOABD_PARAM_DECOMPBUF (0)
2380
2199#ifdef __cplusplus 2381#ifdef __cplusplus
2200} 2382}
2201#endif 2383#endif
diff --git a/rbutil/rbutilqt/mspack/mszip.h b/rbutil/rbutilqt/mspack/mszip.h
index 13c9542ee6..2cd608234e 100644
--- a/rbutil/rbutilqt/mspack/mszip.h
+++ b/rbutil/rbutilqt/mspack/mszip.h
@@ -32,14 +32,14 @@ extern "C" {
32# define MSZIP_LITERAL_TABLESIZE (MSZIP_LITERAL_MAXSYMBOLS * 4) 32# define MSZIP_LITERAL_TABLESIZE (MSZIP_LITERAL_MAXSYMBOLS * 4)
33#else 33#else
34# define MSZIP_LITERAL_TABLESIZE ((1 << MSZIP_LITERAL_TABLEBITS) + \ 34# define MSZIP_LITERAL_TABLESIZE ((1 << MSZIP_LITERAL_TABLEBITS) + \
35 (MSZIP_LITERAL_MAXSYMBOLS * 2)) 35 (MSZIP_LITERAL_MAXSYMBOLS * 2))
36#endif 36#endif
37 37
38#if (1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2) 38#if (1 << MSZIP_DISTANCE_TABLEBITS) < (MSZIP_DISTANCE_MAXSYMBOLS * 2)
39# define MSZIP_DISTANCE_TABLESIZE (MSZIP_DISTANCE_MAXSYMBOLS * 4) 39# define MSZIP_DISTANCE_TABLESIZE (MSZIP_DISTANCE_MAXSYMBOLS * 4)
40#else 40#else
41# define MSZIP_DISTANCE_TABLESIZE ((1 << MSZIP_DISTANCE_TABLEBITS) + \ 41# define MSZIP_DISTANCE_TABLESIZE ((1 << MSZIP_DISTANCE_TABLEBITS) + \
42 (MSZIP_DISTANCE_MAXSYMBOLS * 2)) 42 (MSZIP_DISTANCE_MAXSYMBOLS * 2))
43#endif 43#endif
44 44
45struct mszipd_stream { 45struct mszipd_stream {
@@ -83,10 +83,10 @@ struct mszipd_stream {
83 * a partial recovery of erroneous data. 83 * a partial recovery of erroneous data.
84 */ 84 */
85extern struct mszipd_stream *mszipd_init(struct mspack_system *system, 85extern struct mszipd_stream *mszipd_init(struct mspack_system *system,
86 struct mspack_file *input, 86 struct mspack_file *input,
87 struct mspack_file *output, 87 struct mspack_file *output,
88 int input_buffer_size, 88 int input_buffer_size,
89 int repair_mode); 89 int repair_mode);
90 90
91/* decompresses, or decompresses more of, an MS-ZIP stream. 91/* decompresses, or decompresses more of, an MS-ZIP stream.
92 * 92 *
@@ -108,6 +108,11 @@ extern struct mszipd_stream *mszipd_init(struct mspack_system *system,
108 */ 108 */
109extern int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes); 109extern int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes);
110 110
111/* decompresses an entire MS-ZIP stream in a KWAJ file. Acts very much
112 * like mszipd_decompress(), but doesn't take an out_bytes parameter
113 */
114extern int mszipd_decompress_kwaj(struct mszipd_stream *zip);
115
111/* frees all stream associated with an MS-ZIP data stream 116/* frees all stream associated with an MS-ZIP data stream
112 * 117 *
113 * - calls system->free() using the system pointer given in mszipd_init() 118 * - calls system->free() using the system pointer given in mszipd_init()
diff --git a/rbutil/rbutilqt/mspack/mszipd.c b/rbutil/rbutilqt/mspack/mszipd.c
index 3c158fbd4d..c1b02b1207 100644
--- a/rbutil/rbutilqt/mspack/mszipd.c
+++ b/rbutil/rbutilqt/mspack/mszipd.c
@@ -20,9 +20,9 @@
20#define BITS_VAR zip 20#define BITS_VAR zip
21#define BITS_ORDER_LSB 21#define BITS_ORDER_LSB
22#define BITS_LSB_TABLE 22#define BITS_LSB_TABLE
23#define READ_BYTES do { \ 23#define READ_BYTES do { \
24 READ_IF_NEEDED; \ 24 READ_IF_NEEDED; \
25 INJECT_BITS(*i_ptr++, 8); \ 25 INJECT_BITS(*i_ptr++, 8); \
26} while (0) 26} while (0)
27#include "readbits.h" 27#include "readbits.h"
28 28
@@ -34,13 +34,13 @@
34#define HUFF_ERROR return INF_ERR_HUFFSYM 34#define HUFF_ERROR return INF_ERR_HUFFSYM
35#include "readhuff.h" 35#include "readhuff.h"
36 36
37#define FLUSH_IF_NEEDED do { \ 37#define FLUSH_IF_NEEDED do { \
38 if (zip->window_posn == MSZIP_FRAME_SIZE) { \ 38 if (zip->window_posn == MSZIP_FRAME_SIZE) { \
39 if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) { \ 39 if (zip->flush_window(zip, MSZIP_FRAME_SIZE)) { \
40 return INF_ERR_FLUSH; \ 40 return INF_ERR_FLUSH; \
41 } \ 41 } \
42 zip->window_posn = 0; \ 42 zip->window_posn = 0; \
43 } \ 43 } \
44} while (0) 44} while (0)
45 45
46/* match lengths for literal codes 257.. 285 */ 46/* match lengths for literal codes 257.. 285 */
@@ -181,14 +181,14 @@ static int inflate(struct mszipd_stream *zip) {
181 181
182 /* read 4 bytes of data, emptying the bit-buffer if necessary */ 182 /* read 4 bytes of data, emptying the bit-buffer if necessary */
183 for (i = 0; (bits_left >= 8); i++) { 183 for (i = 0; (bits_left >= 8); i++) {
184 if (i == 4) return INF_ERR_BITBUF; 184 if (i == 4) return INF_ERR_BITBUF;
185 lens_buf[i] = PEEK_BITS(8); 185 lens_buf[i] = PEEK_BITS(8);
186 REMOVE_BITS(8); 186 REMOVE_BITS(8);
187 } 187 }
188 if (bits_left != 0) return INF_ERR_BITBUF; 188 if (bits_left != 0) return INF_ERR_BITBUF;
189 while (i < 4) { 189 while (i < 4) {
190 READ_IF_NEEDED; 190 READ_IF_NEEDED;
191 lens_buf[i++] = *i_ptr++; 191 lens_buf[i++] = *i_ptr++;
192 } 192 }
193 193
194 /* get the length and its complement */ 194 /* get the length and its complement */
@@ -198,18 +198,18 @@ static int inflate(struct mszipd_stream *zip) {
198 198
199 /* read and copy the uncompressed data into the window */ 199 /* read and copy the uncompressed data into the window */
200 while (length > 0) { 200 while (length > 0) {
201 READ_IF_NEEDED; 201 READ_IF_NEEDED;
202 202
203 this_run = length; 203 this_run = length;
204 if (this_run > (unsigned int)(i_end - i_ptr)) this_run = i_end - i_ptr; 204 if (this_run > (unsigned int)(i_end - i_ptr)) this_run = i_end - i_ptr;
205 if (this_run > (MSZIP_FRAME_SIZE - zip->window_posn)) 205 if (this_run > (MSZIP_FRAME_SIZE - zip->window_posn))
206 this_run = MSZIP_FRAME_SIZE - zip->window_posn; 206 this_run = MSZIP_FRAME_SIZE - zip->window_posn;
207 207
208 zip->sys->copy(i_ptr, &zip->window[zip->window_posn], this_run); 208 zip->sys->copy(i_ptr, &zip->window[zip->window_posn], this_run);
209 zip->window_posn += this_run; 209 zip->window_posn += this_run;
210 i_ptr += this_run; 210 i_ptr += this_run;
211 length -= this_run; 211 length -= this_run;
212 FLUSH_IF_NEEDED; 212 FLUSH_IF_NEEDED;
213 } 213 }
214 } 214 }
215 else if ((block_type == 1) || (block_type == 2)) { 215 else if ((block_type == 1) || (block_type == 2)) {
@@ -217,92 +217,92 @@ static int inflate(struct mszipd_stream *zip) {
217 unsigned int match_posn, code; 217 unsigned int match_posn, code;
218 218
219 if (block_type == 1) { 219 if (block_type == 1) {
220 /* block with fixed Huffman codes */ 220 /* block with fixed Huffman codes */
221 i = 0; 221 i = 0;
222 while (i < 144) zip->LITERAL_len[i++] = 8; 222 while (i < 144) zip->LITERAL_len[i++] = 8;
223 while (i < 256) zip->LITERAL_len[i++] = 9; 223 while (i < 256) zip->LITERAL_len[i++] = 9;
224 while (i < 280) zip->LITERAL_len[i++] = 7; 224 while (i < 280) zip->LITERAL_len[i++] = 7;
225 while (i < 288) zip->LITERAL_len[i++] = 8; 225 while (i < 288) zip->LITERAL_len[i++] = 8;
226 for (i = 0; i < 32; i++) zip->DISTANCE_len[i] = 5; 226 for (i = 0; i < 32; i++) zip->DISTANCE_len[i] = 5;
227 } 227 }
228 else { 228 else {
229 /* block with dynamic Huffman codes */ 229 /* block with dynamic Huffman codes */
230 STORE_BITS; 230 STORE_BITS;
231 if ((i = zip_read_lens(zip))) return i; 231 if ((i = zip_read_lens(zip))) return i;
232 RESTORE_BITS; 232 RESTORE_BITS;
233 } 233 }
234 234
235 /* now huffman lengths are read for either kind of block, 235 /* now huffman lengths are read for either kind of block,
236 * create huffman decoding tables */ 236 * create huffman decoding tables */
237 if (make_decode_table(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS, 237 if (make_decode_table(MSZIP_LITERAL_MAXSYMBOLS, MSZIP_LITERAL_TABLEBITS,
238 &zip->LITERAL_len[0], &zip->LITERAL_table[0])) 238 &zip->LITERAL_len[0], &zip->LITERAL_table[0]))
239 { 239 {
240 return INF_ERR_LITERALTBL; 240 return INF_ERR_LITERALTBL;
241 } 241 }
242 242
243 if (make_decode_table(MSZIP_DISTANCE_MAXSYMBOLS,MSZIP_DISTANCE_TABLEBITS, 243 if (make_decode_table(MSZIP_DISTANCE_MAXSYMBOLS,MSZIP_DISTANCE_TABLEBITS,
244 &zip->DISTANCE_len[0], &zip->DISTANCE_table[0])) 244 &zip->DISTANCE_len[0], &zip->DISTANCE_table[0]))
245 { 245 {
246 return INF_ERR_DISTANCETBL; 246 return INF_ERR_DISTANCETBL;
247 } 247 }
248 248
249 /* decode forever until end of block code */ 249 /* decode forever until end of block code */
250 for (;;) { 250 for (;;) {
251 READ_HUFFSYM(LITERAL, code); 251 READ_HUFFSYM(LITERAL, code);
252 if (code < 256) { 252 if (code < 256) {
253 zip->window[zip->window_posn++] = (unsigned char) code; 253 zip->window[zip->window_posn++] = (unsigned char) code;
254 FLUSH_IF_NEEDED; 254 FLUSH_IF_NEEDED;
255 } 255 }
256 else if (code == 256) { 256 else if (code == 256) {
257 /* END OF BLOCK CODE: loop break point */ 257 /* END OF BLOCK CODE: loop break point */
258 break; 258 break;
259 } 259 }
260 else { 260 else {
261 code -= 257; /* codes 257-285 are matches */ 261 code -= 257; /* codes 257-285 are matches */
262 if (code >= 29) return INF_ERR_LITCODE; /* codes 286-287 are illegal */ 262 if (code >= 29) return INF_ERR_LITCODE; /* codes 286-287 are illegal */
263 READ_BITS_T(length, lit_extrabits[code]); 263 READ_BITS_T(length, lit_extrabits[code]);
264 length += lit_lengths[code]; 264 length += lit_lengths[code];
265 265
266 READ_HUFFSYM(DISTANCE, code); 266 READ_HUFFSYM(DISTANCE, code);
267 if (code > 30) return INF_ERR_DISTCODE; 267 if (code >= 30) return INF_ERR_DISTCODE;
268 READ_BITS_T(distance, dist_extrabits[code]); 268 READ_BITS_T(distance, dist_extrabits[code]);
269 distance += dist_offsets[code]; 269 distance += dist_offsets[code];
270 270
271 /* match position is window position minus distance. If distance 271 /* match position is window position minus distance. If distance
272 * is more than window position numerically, it must 'wrap 272 * is more than window position numerically, it must 'wrap
273 * around' the frame size. */ 273 * around' the frame size. */
274 match_posn = ((distance > zip->window_posn) ? MSZIP_FRAME_SIZE : 0) 274 match_posn = ((distance > zip->window_posn) ? MSZIP_FRAME_SIZE : 0)
275 + zip->window_posn - distance; 275 + zip->window_posn - distance;
276 276
277 /* copy match */ 277 /* copy match */
278 if (length < 12) { 278 if (length < 12) {
279 /* short match, use slower loop but no loop setup code */ 279 /* short match, use slower loop but no loop setup code */
280 while (length--) { 280 while (length--) {
281 zip->window[zip->window_posn++] = zip->window[match_posn++]; 281 zip->window[zip->window_posn++] = zip->window[match_posn++];
282 match_posn &= MSZIP_FRAME_SIZE - 1; 282 match_posn &= MSZIP_FRAME_SIZE - 1;
283 FLUSH_IF_NEEDED; 283 FLUSH_IF_NEEDED;
284 } 284 }
285 } 285 }
286 else { 286 else {
287 /* longer match, use faster loop but with setup expense */ 287 /* longer match, use faster loop but with setup expense */
288 unsigned char *runsrc, *rundest; 288 unsigned char *runsrc, *rundest;
289 do { 289 do {
290 this_run = length; 290 this_run = length;
291 if ((match_posn + this_run) > MSZIP_FRAME_SIZE) 291 if ((match_posn + this_run) > MSZIP_FRAME_SIZE)
292 this_run = MSZIP_FRAME_SIZE - match_posn; 292 this_run = MSZIP_FRAME_SIZE - match_posn;
293 if ((zip->window_posn + this_run) > MSZIP_FRAME_SIZE) 293 if ((zip->window_posn + this_run) > MSZIP_FRAME_SIZE)
294 this_run = MSZIP_FRAME_SIZE - zip->window_posn; 294 this_run = MSZIP_FRAME_SIZE - zip->window_posn;
295 295
296 rundest = &zip->window[zip->window_posn]; zip->window_posn += this_run; 296 rundest = &zip->window[zip->window_posn]; zip->window_posn += this_run;
297 runsrc = &zip->window[match_posn]; match_posn += this_run; 297 runsrc = &zip->window[match_posn]; match_posn += this_run;
298 length -= this_run; 298 length -= this_run;
299 while (this_run--) *rundest++ = *runsrc++; 299 while (this_run--) *rundest++ = *runsrc++;
300 if (match_posn == MSZIP_FRAME_SIZE) match_posn = 0; 300 if (match_posn == MSZIP_FRAME_SIZE) match_posn = 0;
301 FLUSH_IF_NEEDED; 301 FLUSH_IF_NEEDED;
302 } while (length > 0); 302 } while (length > 0);
303 } 303 }
304 304
305 } /* else (code >= 257) */ 305 } /* else (code >= 257) */
306 306
307 } /* for(;;) -- break point at 'code == 256' */ 307 } /* for(;;) -- break point at 'code == 256' */
308 } 308 }
@@ -328,7 +328,7 @@ static int inflate(struct mszipd_stream *zip) {
328 * is flushed, an error is raised. 328 * is flushed, an error is raised.
329 */ 329 */
330static int mszipd_flush_window(struct mszipd_stream *zip, 330static int mszipd_flush_window(struct mszipd_stream *zip,
331 unsigned int data_flushed) 331 unsigned int data_flushed)
332{ 332{
333 zip->bytes_output += data_flushed; 333 zip->bytes_output += data_flushed;
334 if (zip->bytes_output > MSZIP_FRAME_SIZE) { 334 if (zip->bytes_output > MSZIP_FRAME_SIZE) {
@@ -340,17 +340,18 @@ static int mszipd_flush_window(struct mszipd_stream *zip,
340} 340}
341 341
342struct mszipd_stream *mszipd_init(struct mspack_system *system, 342struct mszipd_stream *mszipd_init(struct mspack_system *system,
343 struct mspack_file *input, 343 struct mspack_file *input,
344 struct mspack_file *output, 344 struct mspack_file *output,
345 int input_buffer_size, 345 int input_buffer_size,
346 int repair_mode) 346 int repair_mode)
347{ 347{
348 struct mszipd_stream *zip; 348 struct mszipd_stream *zip;
349 349
350 if (!system) return NULL; 350 if (!system) return NULL;
351 351
352 /* round up input buffer size to multiple of two */
352 input_buffer_size = (input_buffer_size + 1) & -2; 353 input_buffer_size = (input_buffer_size + 1) & -2;
353 if (!input_buffer_size) return NULL; 354 if (input_buffer_size < 2) return NULL;
354 355
355 /* allocate decompression state */ 356 /* allocate decompression state */
356 if (!(zip = (struct mszipd_stream *) system->alloc(system, sizeof(struct mszipd_stream)))) { 357 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) {
426 if ((error = inflate(zip))) { 427 if ((error = inflate(zip))) {
427 D(("inflate error %d", error)) 428 D(("inflate error %d", error))
428 if (zip->repair_mode) { 429 if (zip->repair_mode) {
429 /* recover partially-inflated buffers */ 430 /* recover partially-inflated buffers */
430 if (zip->bytes_output == 0 && zip->window_posn > 0) { 431 if (zip->bytes_output == 0 && zip->window_posn > 0) {
431 zip->flush_window(zip, zip->window_posn); 432 zip->flush_window(zip, zip->window_posn);
432 } 433 }
433 zip->sys->message(NULL, "MSZIP error, %u bytes of data lost.", 434 zip->sys->message(NULL, "MSZIP error, %u bytes of data lost.",
434 MSZIP_FRAME_SIZE - zip->bytes_output); 435 MSZIP_FRAME_SIZE - zip->bytes_output);
435 for (i = zip->bytes_output; i < MSZIP_FRAME_SIZE; i++) { 436 for (i = zip->bytes_output; i < MSZIP_FRAME_SIZE; i++) {
436 zip->window[i] = '\0'; 437 zip->window[i] = '\0';
437 } 438 }
438 zip->bytes_output = MSZIP_FRAME_SIZE; 439 zip->bytes_output = MSZIP_FRAME_SIZE;
439 } 440 }
440 else { 441 else {
441 return zip->error = (error > 0) ? error : MSPACK_ERR_DECRUNCH; 442 return zip->error = (error > 0) ? error : MSPACK_ERR_DECRUNCH;
442 } 443 }
443 } 444 }
444 zip->o_ptr = &zip->window[0]; 445 zip->o_ptr = &zip->window[0];
@@ -465,6 +466,45 @@ int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes) {
465 return MSPACK_ERR_OK; 466 return MSPACK_ERR_OK;
466} 467}
467 468
469int mszipd_decompress_kwaj(struct mszipd_stream *zip) {
470 /* for the bit buffer */
471 register unsigned int bit_buffer;
472 register int bits_left;
473 unsigned char *i_ptr, *i_end;
474
475 int i, error, block_len;
476
477 /* unpack blocks until block_len == 0 */
478 for (;;) {
479 RESTORE_BITS;
480
481 /* align to bytestream, read block_len */
482 i = bits_left & 7; REMOVE_BITS(i);
483 READ_BITS(block_len, 8);
484 READ_BITS(i, 8); block_len |= i << 8;
485
486 if (block_len == 0) break;
487
488 /* read "CK" header */
489 READ_BITS(i, 8); if (i != 'C') return MSPACK_ERR_DATAFORMAT;
490 READ_BITS(i, 8); if (i != 'K') return MSPACK_ERR_DATAFORMAT;
491
492 /* inflate block */
493 zip->window_posn = 0;
494 zip->bytes_output = 0;
495 STORE_BITS;
496 if ((error = inflate(zip))) {
497 D(("inflate error %d", error))
498 return zip->error = (error > 0) ? error : MSPACK_ERR_DECRUNCH;
499 }
500
501 /* write inflated block */
502 if (zip->sys->write(zip->output, &zip->window[0], zip->bytes_output)
503 != zip->bytes_output) return zip->error = MSPACK_ERR_WRITE;
504 }
505 return MSPACK_ERR_OK;
506}
507
468void mszipd_free(struct mszipd_stream *zip) { 508void mszipd_free(struct mszipd_stream *zip) {
469 struct mspack_system *sys; 509 struct mspack_system *sys;
470 if (zip) { 510 if (zip) {
diff --git a/rbutil/rbutilqt/mspack/qtm.h b/rbutil/rbutilqt/mspack/qtm.h
index ab0bb4c32c..20a38538a2 100644
--- a/rbutil/rbutilqt/mspack/qtm.h
+++ b/rbutil/rbutilqt/mspack/qtm.h
@@ -90,10 +90,10 @@ struct qtmd_stream {
90 * - input_buffer_size is the number of bytes to use to store bitstream data. 90 * - input_buffer_size is the number of bytes to use to store bitstream data.
91 */ 91 */
92extern struct qtmd_stream *qtmd_init(struct mspack_system *system, 92extern struct qtmd_stream *qtmd_init(struct mspack_system *system,
93 struct mspack_file *input, 93 struct mspack_file *input,
94 struct mspack_file *output, 94 struct mspack_file *output,
95 int window_bits, 95 int window_bits,
96 int input_buffer_size); 96 int input_buffer_size);
97 97
98/* decompresses, or decompresses more of, a Quantum stream. 98/* decompresses, or decompresses more of, a Quantum stream.
99 * 99 *
diff --git a/rbutil/rbutilqt/mspack/qtmd.c b/rbutil/rbutilqt/mspack/qtmd.c
index 0fb20da167..58e4787b7f 100644
--- a/rbutil/rbutilqt/mspack/qtmd.c
+++ b/rbutil/rbutilqt/mspack/qtmd.c
@@ -27,11 +27,11 @@
27#define BITS_TYPE struct qtmd_stream 27#define BITS_TYPE struct qtmd_stream
28#define BITS_VAR qtm 28#define BITS_VAR qtm
29#define BITS_ORDER_MSB 29#define BITS_ORDER_MSB
30#define READ_BYTES do { \ 30#define READ_BYTES do { \
31 unsigned char b0, b1; \ 31 unsigned char b0, b1; \
32 READ_IF_NEEDED; b0 = *i_ptr++; \ 32 READ_IF_NEEDED; b0 = *i_ptr++; \
33 READ_IF_NEEDED; b1 = *i_ptr++; \ 33 READ_IF_NEEDED; b1 = *i_ptr++; \
34 INJECT_BITS((b0 << 8) | b1, 16); \ 34 INJECT_BITS((b0 << 8) | b1, 16); \
35} while (0) 35} while (0)
36#include "readbits.h" 36#include "readbits.h"
37 37
@@ -115,7 +115,7 @@ static const unsigned char length_extra[27] = {
115 else break; \ 115 else break; \
116 } \ 116 } \
117 L <<= 1; H = (H << 1) | 1; \ 117 L <<= 1; H = (H << 1) | 1; \
118 ENSURE_BITS(1); \ 118 ENSURE_BITS(1); \
119 C = (C << 1) | PEEK_BITS(1); \ 119 C = (C << 1) | PEEK_BITS(1); \
120 REMOVE_BITS(1); \ 120 REMOVE_BITS(1); \
121 } \ 121 } \
@@ -130,7 +130,7 @@ static void qtmd_update_model(struct qtmd_model *model) {
130 /* -1, not -2; the 0 entry saves this */ 130 /* -1, not -2; the 0 entry saves this */
131 model->syms[i].cumfreq >>= 1; 131 model->syms[i].cumfreq >>= 1;
132 if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) { 132 if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) {
133 model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1; 133 model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1;
134 } 134 }
135 } 135 }
136 } 136 }
@@ -149,11 +149,11 @@ static void qtmd_update_model(struct qtmd_model *model) {
149 * characteristics */ 149 * characteristics */
150 for (i = 0; i < model->entries - 1; i++) { 150 for (i = 0; i < model->entries - 1; i++) {
151 for (j = i + 1; j < model->entries; j++) { 151 for (j = i + 1; j < model->entries; j++) {
152 if (model->syms[i].cumfreq < model->syms[j].cumfreq) { 152 if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
153 tmp = model->syms[i]; 153 tmp = model->syms[i];
154 model->syms[i] = model->syms[j]; 154 model->syms[i] = model->syms[j];
155 model->syms[j] = tmp; 155 model->syms[j] = tmp;
156 } 156 }
157 } 157 }
158 } 158 }
159 159
@@ -166,7 +166,7 @@ static void qtmd_update_model(struct qtmd_model *model) {
166 166
167/* Initialises a model to decode symbols from [start] to [start]+[len]-1 */ 167/* Initialises a model to decode symbols from [start] to [start]+[len]-1 */
168static void qtmd_init_model(struct qtmd_model *model, 168static void qtmd_init_model(struct qtmd_model *model,
169 struct qtmd_modelsym *syms, int start, int len) 169 struct qtmd_modelsym *syms, int start, int len)
170{ 170{
171 int i; 171 int i;
172 172
@@ -184,9 +184,9 @@ static void qtmd_init_model(struct qtmd_model *model,
184/*-------- main Quantum code --------*/ 184/*-------- main Quantum code --------*/
185 185
186struct qtmd_stream *qtmd_init(struct mspack_system *system, 186struct qtmd_stream *qtmd_init(struct mspack_system *system,
187 struct mspack_file *input, 187 struct mspack_file *input,
188 struct mspack_file *output, 188 struct mspack_file *output,
189 int window_bits, int input_buffer_size) 189 int window_bits, int input_buffer_size)
190{ 190{
191 unsigned int window_size = 1 << window_bits; 191 unsigned int window_size = 1 << window_bits;
192 struct qtmd_stream *qtm; 192 struct qtmd_stream *qtm;
@@ -197,6 +197,7 @@ struct qtmd_stream *qtmd_init(struct mspack_system *system,
197 /* Quantum supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */ 197 /* Quantum supports window sizes of 2^10 (1Kb) through 2^21 (2Mb) */
198 if (window_bits < 10 || window_bits > 21) return NULL; 198 if (window_bits < 10 || window_bits > 21) return NULL;
199 199
200 /* round up input buffer size to multiple of two */
200 input_buffer_size = (input_buffer_size + 1) & -2; 201 input_buffer_size = (input_buffer_size + 1) & -2;
201 if (input_buffer_size < 2) return NULL; 202 if (input_buffer_size < 2) return NULL;
202 203
@@ -307,113 +308,113 @@ int qtmd_decompress(struct qtmd_stream *qtm, off_t out_bytes) {
307 while (window_posn < frame_end) { 308 while (window_posn < frame_end) {
308 GET_SYMBOL(qtm->model7, selector); 309 GET_SYMBOL(qtm->model7, selector);
309 if (selector < 4) { 310 if (selector < 4) {
310 /* literal byte */ 311 /* literal byte */
311 struct qtmd_model *mdl = (selector == 0) ? &qtm->model0 : 312 struct qtmd_model *mdl = (selector == 0) ? &qtm->model0 :
312 ((selector == 1) ? &qtm->model1 : 313 ((selector == 1) ? &qtm->model1 :
313 ((selector == 2) ? &qtm->model2 : 314 ((selector == 2) ? &qtm->model2 :
314 &qtm->model3)); 315 &qtm->model3));
315 GET_SYMBOL((*mdl), sym); 316 GET_SYMBOL((*mdl), sym);
316 window[window_posn++] = sym; 317 window[window_posn++] = sym;
317 frame_todo--; 318 frame_todo--;
318 } 319 }
319 else { 320 else {
320 /* match repeated string */ 321 /* match repeated string */
321 switch (selector) { 322 switch (selector) {
322 case 4: /* selector 4 = fixed length match (3 bytes) */ 323 case 4: /* selector 4 = fixed length match (3 bytes) */
323 GET_SYMBOL(qtm->model4, sym); 324 GET_SYMBOL(qtm->model4, sym);
324 READ_MANY_BITS(extra, extra_bits[sym]); 325 READ_MANY_BITS(extra, extra_bits[sym]);
325 match_offset = position_base[sym] + extra + 1; 326 match_offset = position_base[sym] + extra + 1;
326 match_length = 3; 327 match_length = 3;
327 break; 328 break;
328 329
329 case 5: /* selector 5 = fixed length match (4 bytes) */ 330 case 5: /* selector 5 = fixed length match (4 bytes) */
330 GET_SYMBOL(qtm->model5, sym); 331 GET_SYMBOL(qtm->model5, sym);
331 READ_MANY_BITS(extra, extra_bits[sym]); 332 READ_MANY_BITS(extra, extra_bits[sym]);
332 match_offset = position_base[sym] + extra + 1; 333 match_offset = position_base[sym] + extra + 1;
333 match_length = 4; 334 match_length = 4;
334 break; 335 break;
335 336
336 case 6: /* selector 6 = variable length match */ 337 case 6: /* selector 6 = variable length match */
337 GET_SYMBOL(qtm->model6len, sym); 338 GET_SYMBOL(qtm->model6len, sym);
338 READ_MANY_BITS(extra, length_extra[sym]); 339 READ_MANY_BITS(extra, length_extra[sym]);
339 match_length = length_base[sym] + extra + 5; 340 match_length = length_base[sym] + extra + 5;
340 341
341 GET_SYMBOL(qtm->model6, sym); 342 GET_SYMBOL(qtm->model6, sym);
342 READ_MANY_BITS(extra, extra_bits[sym]); 343 READ_MANY_BITS(extra, extra_bits[sym]);
343 match_offset = position_base[sym] + extra + 1; 344 match_offset = position_base[sym] + extra + 1;
344 break; 345 break;
345 346
346 default: 347 default:
347 /* should be impossible, model7 can only return 0-6 */ 348 /* should be impossible, model7 can only return 0-6 */
348 D(("got %d from selector", selector)) 349 D(("got %d from selector", selector))
349 return qtm->error = MSPACK_ERR_DECRUNCH; 350 return qtm->error = MSPACK_ERR_DECRUNCH;
350 } 351 }
351 352
352 rundest = &window[window_posn]; 353 rundest = &window[window_posn];
353 frame_todo -= match_length; 354 frame_todo -= match_length;
354 355
355 /* does match destination wrap the window? This situation is possible 356 /* does match destination wrap the window? This situation is possible
356 * where the window size is less than the 32k frame size, but matches 357 * where the window size is less than the 32k frame size, but matches
357 * must not go beyond a frame boundary */ 358 * must not go beyond a frame boundary */
358 if ((window_posn + match_length) > qtm->window_size) { 359 if ((window_posn + match_length) > qtm->window_size) {
359 /* copy first part of match, before window end */ 360 /* copy first part of match, before window end */
360 i = qtm->window_size - window_posn; 361 i = qtm->window_size - window_posn;
361 j = window_posn - match_offset; 362 j = window_posn - match_offset;
362 while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)]; 363 while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
363 364
364 /* flush currently stored data */ 365 /* flush currently stored data */
365 i = (&window[qtm->window_size] - qtm->o_ptr); 366 i = (&window[qtm->window_size] - qtm->o_ptr);
366 367
367 /* this should not happen, but if it does then this code 368 /* this should not happen, but if it does then this code
368 * can't handle the situation (can't flush up to the end of 369 * can't handle the situation (can't flush up to the end of
369 * the window, but can't break out either because we haven't 370 * the window, but can't break out either because we haven't
370 * finished writing the match). bail out in this case */ 371 * finished writing the match). bail out in this case */
371 if (i > out_bytes) { 372 if (i > out_bytes) {
372 D(("during window-wrap match; %d bytes to flush but only need %d", 373 D(("during window-wrap match; %d bytes to flush but only need %d",
373 i, (int) out_bytes)) 374 i, (int) out_bytes))
374 return qtm->error = MSPACK_ERR_DECRUNCH; 375 return qtm->error = MSPACK_ERR_DECRUNCH;
375 } 376 }
376 if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) { 377 if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
377 return qtm->error = MSPACK_ERR_WRITE; 378 return qtm->error = MSPACK_ERR_WRITE;
378 } 379 }
379 out_bytes -= i; 380 out_bytes -= i;
380 qtm->o_ptr = &window[0]; 381 qtm->o_ptr = &window[0];
381 qtm->o_end = &window[0]; 382 qtm->o_end = &window[0];
382 383
383 /* copy second part of match, after window wrap */ 384 /* copy second part of match, after window wrap */
384 rundest = &window[0]; 385 rundest = &window[0];
385 i = match_length - (qtm->window_size - window_posn); 386 i = match_length - (qtm->window_size - window_posn);
386 while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)]; 387 while (i--) *rundest++ = window[j++ & (qtm->window_size - 1)];
387 window_posn = window_posn + match_length - qtm->window_size; 388 window_posn = window_posn + match_length - qtm->window_size;
388 389
389 break; /* because "window_posn < frame_end" has now failed */ 390 break; /* because "window_posn < frame_end" has now failed */
390 } 391 }
391 else { 392 else {
392 /* normal match - output won't wrap window or frame end */ 393 /* normal match - output won't wrap window or frame end */
393 i = match_length; 394 i = match_length;
394 395
395 /* does match _offset_ wrap the window? */ 396 /* does match _offset_ wrap the window? */
396 if (match_offset > window_posn) { 397 if (match_offset > window_posn) {
397 /* j = length from match offset to end of window */ 398 /* j = length from match offset to end of window */
398 j = match_offset - window_posn; 399 j = match_offset - window_posn;
399 if (j > (int) qtm->window_size) { 400 if (j > (int) qtm->window_size) {
400 D(("match offset beyond window boundaries")) 401 D(("match offset beyond window boundaries"))
401 return qtm->error = MSPACK_ERR_DECRUNCH; 402 return qtm->error = MSPACK_ERR_DECRUNCH;
402 } 403 }
403 runsrc = &window[qtm->window_size - j]; 404 runsrc = &window[qtm->window_size - j];
404 if (j < i) { 405 if (j < i) {
405 /* if match goes over the window edge, do two copy runs */ 406 /* if match goes over the window edge, do two copy runs */
406 i -= j; while (j-- > 0) *rundest++ = *runsrc++; 407 i -= j; while (j-- > 0) *rundest++ = *runsrc++;
407 runsrc = window; 408 runsrc = window;
408 } 409 }
409 while (i-- > 0) *rundest++ = *runsrc++; 410 while (i-- > 0) *rundest++ = *runsrc++;
410 } 411 }
411 else { 412 else {
412 runsrc = rundest - match_offset; 413 runsrc = rundest - match_offset;
413 while (i-- > 0) *rundest++ = *runsrc++; 414 while (i-- > 0) *rundest++ = *runsrc++;
414 } 415 }
415 window_posn += match_length; 416 window_posn += match_length;
416 } 417 }
417 } /* if (window_posn+match_length > frame_end) */ 418 } /* if (window_posn+match_length > frame_end) */
418 } /* while (window_posn < frame_end) */ 419 } /* while (window_posn < frame_end) */
419 420
@@ -448,7 +449,7 @@ int qtmd_decompress(struct qtmd_stream *qtm, off_t out_bytes) {
448 /* break out if we have more than enough to finish this request */ 449 /* break out if we have more than enough to finish this request */
449 if (i >= out_bytes) break; 450 if (i >= out_bytes) break;
450 if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) { 451 if (qtm->sys->write(qtm->output, qtm->o_ptr, i) != i) {
451 return qtm->error = MSPACK_ERR_WRITE; 452 return qtm->error = MSPACK_ERR_WRITE;
452 } 453 }
453 out_bytes -= i; 454 out_bytes -= i;
454 qtm->o_ptr = &window[0]; 455 qtm->o_ptr = &window[0];
diff --git a/rbutil/rbutilqt/mspack/readbits.h b/rbutil/rbutilqt/mspack/readbits.h
index 457cbdd7d4..9b237a3693 100644
--- a/rbutil/rbutilqt/mspack/readbits.h
+++ b/rbutil/rbutilqt/mspack/readbits.h
@@ -100,48 +100,48 @@
100#endif 100#endif
101#define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT) 101#define BITBUF_WIDTH (sizeof(bit_buffer) * CHAR_BIT)
102 102
103#define INIT_BITS do { \ 103#define INIT_BITS do { \
104 BITS_VAR->i_ptr = &BITS_VAR->inbuf[0]; \ 104 BITS_VAR->i_ptr = &BITS_VAR->inbuf[0]; \
105 BITS_VAR->i_end = &BITS_VAR->inbuf[0]; \ 105 BITS_VAR->i_end = &BITS_VAR->inbuf[0]; \
106 BITS_VAR->bit_buffer = 0; \ 106 BITS_VAR->bit_buffer = 0; \
107 BITS_VAR->bits_left = 0; \ 107 BITS_VAR->bits_left = 0; \
108 BITS_VAR->input_end = 0; \ 108 BITS_VAR->input_end = 0; \
109} while (0) 109} while (0)
110 110
111#define STORE_BITS do { \ 111#define STORE_BITS do { \
112 BITS_VAR->i_ptr = i_ptr; \ 112 BITS_VAR->i_ptr = i_ptr; \
113 BITS_VAR->i_end = i_end; \ 113 BITS_VAR->i_end = i_end; \
114 BITS_VAR->bit_buffer = bit_buffer; \ 114 BITS_VAR->bit_buffer = bit_buffer; \
115 BITS_VAR->bits_left = bits_left; \ 115 BITS_VAR->bits_left = bits_left; \
116} while (0) 116} while (0)
117 117
118#define RESTORE_BITS do { \ 118#define RESTORE_BITS do { \
119 i_ptr = BITS_VAR->i_ptr; \ 119 i_ptr = BITS_VAR->i_ptr; \
120 i_end = BITS_VAR->i_end; \ 120 i_end = BITS_VAR->i_end; \
121 bit_buffer = BITS_VAR->bit_buffer; \ 121 bit_buffer = BITS_VAR->bit_buffer; \
122 bits_left = BITS_VAR->bits_left; \ 122 bits_left = BITS_VAR->bits_left; \
123} while (0) 123} while (0)
124 124
125#define ENSURE_BITS(nbits) do { \ 125#define ENSURE_BITS(nbits) do { \
126 while (bits_left < (nbits)) READ_BYTES; \ 126 while (bits_left < (nbits)) READ_BYTES; \
127} while (0) 127} while (0)
128 128
129#define READ_BITS(val, nbits) do { \ 129#define READ_BITS(val, nbits) do { \
130 ENSURE_BITS(nbits); \ 130 ENSURE_BITS(nbits); \
131 (val) = PEEK_BITS(nbits); \ 131 (val) = PEEK_BITS(nbits); \
132 REMOVE_BITS(nbits); \ 132 REMOVE_BITS(nbits); \
133} while (0) 133} while (0)
134 134
135#define READ_MANY_BITS(val, bits) do { \ 135#define READ_MANY_BITS(val, bits) do { \
136 unsigned char needed = (bits), bitrun; \ 136 unsigned char needed = (bits), bitrun; \
137 (val) = 0; \ 137 (val) = 0; \
138 while (needed > 0) { \ 138 while (needed > 0) { \
139 if (bits_left <= (BITBUF_WIDTH - 16)) READ_BYTES; \ 139 if (bits_left <= (BITBUF_WIDTH - 16)) READ_BYTES; \
140 bitrun = (bits_left < needed) ? bits_left : needed; \ 140 bitrun = (bits_left < needed) ? bits_left : needed; \
141 (val) = ((val) << bitrun) | PEEK_BITS(bitrun); \ 141 (val) = ((val) << bitrun) | PEEK_BITS(bitrun); \
142 REMOVE_BITS(bitrun); \ 142 REMOVE_BITS(bitrun); \
143 needed -= bitrun; \ 143 needed -= bitrun; \
144 } \ 144 } \
145} while (0) 145} while (0)
146 146
147#ifdef BITS_ORDER_MSB 147#ifdef BITS_ORDER_MSB
@@ -163,21 +163,21 @@ static const unsigned short lsb_bit_mask[17] = {
163 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff 163 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
164}; 164};
165# define PEEK_BITS_T(nbits) (bit_buffer & lsb_bit_mask[(nbits)]) 165# define PEEK_BITS_T(nbits) (bit_buffer & lsb_bit_mask[(nbits)])
166# define READ_BITS_T(val, nbits) do { \ 166# define READ_BITS_T(val, nbits) do { \
167 ENSURE_BITS(nbits); \ 167 ENSURE_BITS(nbits); \
168 (val) = PEEK_BITS_T(nbits); \ 168 (val) = PEEK_BITS_T(nbits); \
169 REMOVE_BITS(nbits); \ 169 REMOVE_BITS(nbits); \
170} while (0) 170} while (0)
171#endif 171#endif
172 172
173#ifndef BITS_NO_READ_INPUT 173#ifndef BITS_NO_READ_INPUT
174# define READ_IF_NEEDED do { \ 174# define READ_IF_NEEDED do { \
175 if (i_ptr >= i_end) { \ 175 if (i_ptr >= i_end) { \
176 if (read_input(BITS_VAR)) \ 176 if (read_input(BITS_VAR)) \
177 return BITS_VAR->error; \ 177 return BITS_VAR->error; \
178 i_ptr = BITS_VAR->i_ptr; \ 178 i_ptr = BITS_VAR->i_ptr; \
179 i_end = BITS_VAR->i_end; \ 179 i_end = BITS_VAR->i_end; \
180 } \ 180 } \
181} while (0) 181} while (0)
182 182
183static int read_input(BITS_TYPE *p) { 183static int read_input(BITS_TYPE *p) {
@@ -187,15 +187,15 @@ static int read_input(BITS_TYPE *p) {
187 /* we might overrun the input stream by asking for bits we don't use, 187 /* we might overrun the input stream by asking for bits we don't use,
188 * so fake 2 more bytes at the end of input */ 188 * so fake 2 more bytes at the end of input */
189 if (read == 0) { 189 if (read == 0) {
190 if (p->input_end) { 190 if (p->input_end) {
191 D(("out of input bytes")) 191 D(("out of input bytes"))
192 return p->error = MSPACK_ERR_READ; 192 return p->error = MSPACK_ERR_READ;
193 } 193 }
194 else { 194 else {
195 read = 2; 195 read = 2;
196 p->inbuf[0] = p->inbuf[1] = 0; 196 p->inbuf[0] = p->inbuf[1] = 0;
197 p->input_end = 1; 197 p->input_end = 1;
198 } 198 }
199 } 199 }
200 200
201 /* update i_ptr and i_end */ 201 /* update i_ptr and i_end */
diff --git a/rbutil/rbutilqt/mspack/readhuff.h b/rbutil/rbutilqt/mspack/readhuff.h
index bb15c0a123..4d94225789 100644
--- a/rbutil/rbutilqt/mspack/readhuff.h
+++ b/rbutil/rbutilqt/mspack/readhuff.h
@@ -1,5 +1,5 @@
1/* This file is part of libmspack. 1/* This file is part of libmspack.
2 * (C) 2003-2010 Stuart Caie. 2 * (C) 2003-2014 Stuart Caie.
3 * 3 *
4 * libmspack is free software; you can redistribute it and/or modify it under 4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1 5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
@@ -10,8 +10,7 @@
10#ifndef MSPACK_READHUFF_H 10#ifndef MSPACK_READHUFF_H
11#define MSPACK_READHUFF_H 1 11#define MSPACK_READHUFF_H 1
12 12
13/* This implements a fast Huffman tree decoding system. 13/* This implements a fast Huffman tree decoding system. */
14 */
15 14
16#if !(defined(BITS_ORDER_MSB) || defined(BITS_ORDER_LSB)) 15#if !(defined(BITS_ORDER_MSB) || defined(BITS_ORDER_LSB))
17# error "readhuff.h is used in conjunction with readbits.h, include that first" 16# error "readhuff.h is used in conjunction with readbits.h, include that first"
@@ -32,32 +31,32 @@
32/* Decodes the next huffman symbol from the input bitstream into var. 31/* Decodes the next huffman symbol from the input bitstream into var.
33 * Do not use this macro on a table unless build_decode_table() succeeded. 32 * Do not use this macro on a table unless build_decode_table() succeeded.
34 */ 33 */
35#define READ_HUFFSYM(tbl, var) do { \ 34#define READ_HUFFSYM(tbl, var) do { \
36 ENSURE_BITS(HUFF_MAXBITS); \ 35 ENSURE_BITS(HUFF_MAXBITS); \
37 sym = HUFF_TABLE(tbl, PEEK_BITS(TABLEBITS(tbl))); \ 36 sym = HUFF_TABLE(tbl, PEEK_BITS(TABLEBITS(tbl))); \
38 if (sym >= MAXSYMBOLS(tbl)) HUFF_TRAVERSE(tbl); \ 37 if (sym >= MAXSYMBOLS(tbl)) HUFF_TRAVERSE(tbl); \
39 (var) = sym; \ 38 (var) = sym; \
40 i = HUFF_LEN(tbl, sym); \ 39 i = HUFF_LEN(tbl, sym); \
41 REMOVE_BITS(i); \ 40 REMOVE_BITS(i); \
42} while (0) 41} while (0)
43 42
44#ifdef BITS_ORDER_LSB 43#ifdef BITS_ORDER_LSB
45# define HUFF_TRAVERSE(tbl) do { \ 44# define HUFF_TRAVERSE(tbl) do { \
46 i = TABLEBITS(tbl) - 1; \ 45 i = TABLEBITS(tbl) - 1; \
47 do { \ 46 do { \
48 if (i++ > HUFF_MAXBITS) HUFF_ERROR; \ 47 if (i++ > HUFF_MAXBITS) HUFF_ERROR; \
49 sym = HUFF_TABLE(tbl, \ 48 sym = HUFF_TABLE(tbl, \
50 (sym << 1) | ((bit_buffer >> i) & 1)); \ 49 (sym << 1) | ((bit_buffer >> i) & 1)); \
51 } while (sym >= MAXSYMBOLS(tbl)); \ 50 } while (sym >= MAXSYMBOLS(tbl)); \
52} while (0) 51} while (0)
53#else 52#else
54#define HUFF_TRAVERSE(tbl) do { \ 53#define HUFF_TRAVERSE(tbl) do { \
55 i = 1 << (BITBUF_WIDTH - TABLEBITS(tbl)); \ 54 i = 1 << (BITBUF_WIDTH - TABLEBITS(tbl)); \
56 do { \ 55 do { \
57 if ((i >>= 1) == 0) HUFF_ERROR; \ 56 if ((i >>= 1) == 0) HUFF_ERROR; \
58 sym = HUFF_TABLE(tbl, \ 57 sym = HUFF_TABLE(tbl, \
59 (sym << 1) | ((bit_buffer & i) ? 1 : 0)); \ 58 (sym << 1) | ((bit_buffer & i) ? 1 : 0)); \
60 } while (sym >= MAXSYMBOLS(tbl)); \ 59 } while (sym >= MAXSYMBOLS(tbl)); \
61} while (0) 60} while (0)
62#endif 61#endif
63 62
@@ -77,7 +76,7 @@
77 * Returns 0 for OK or 1 for error 76 * Returns 0 for OK or 1 for error
78 */ 77 */
79static int make_decode_table(unsigned int nsyms, unsigned int nbits, 78static int make_decode_table(unsigned int nsyms, unsigned int nbits,
80 unsigned char *length, unsigned short *table) 79 unsigned char *length, unsigned short *table)
81{ 80{
82 register unsigned short sym, next_symbol; 81 register unsigned short sym, next_symbol;
83 register unsigned int leaf, fill; 82 register unsigned int leaf, fill;
@@ -91,27 +90,27 @@ static int make_decode_table(unsigned int nsyms, unsigned int nbits,
91 90
92 /* fill entries for codes short enough for a direct mapping */ 91 /* fill entries for codes short enough for a direct mapping */
93 for (bit_num = 1; bit_num <= nbits; bit_num++) { 92 for (bit_num = 1; bit_num <= nbits; bit_num++) {
94 for (sym = 0; sym < nsyms; sym++) { 93 for (sym = 0; sym < nsyms; sym++) {
95 if (length[sym] != bit_num) continue; 94 if (length[sym] != bit_num) continue;
96#ifdef BITS_ORDER_MSB 95#ifdef BITS_ORDER_MSB
97 leaf = pos; 96 leaf = pos;
98#else 97#else
99 /* reverse the significant bits */ 98 /* reverse the significant bits */
100 fill = length[sym]; reverse = pos >> (nbits - fill); leaf = 0; 99 fill = length[sym]; reverse = pos >> (nbits - fill); leaf = 0;
101 do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill); 100 do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
102#endif 101#endif
103 102
104 if((pos += bit_mask) > table_mask) return 1; /* table overrun */ 103 if((pos += bit_mask) > table_mask) return 1; /* table overrun */
105 104
106 /* fill all possible lookups of this symbol with the symbol itself */ 105 /* fill all possible lookups of this symbol with the symbol itself */
107#ifdef BITS_ORDER_MSB 106#ifdef BITS_ORDER_MSB
108 for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym; 107 for (fill = bit_mask; fill-- > 0;) table[leaf++] = sym;
109#else 108#else
110 fill = bit_mask; next_symbol = 1 << bit_num; 109 fill = bit_mask; next_symbol = 1 << bit_num;
111 do { table[leaf] = sym; leaf += next_symbol; } while (--fill); 110 do { table[leaf] = sym; leaf += next_symbol; } while (--fill);
112#endif 111#endif
113 } 112 }
114 bit_mask >>= 1; 113 bit_mask >>= 1;
115 } 114 }
116 115
117 /* exit with success if table is now complete */ 116 /* exit with success if table is now complete */
@@ -120,11 +119,11 @@ static int make_decode_table(unsigned int nsyms, unsigned int nbits,
120 /* mark all remaining table entries as unused */ 119 /* mark all remaining table entries as unused */
121 for (sym = pos; sym < table_mask; sym++) { 120 for (sym = pos; sym < table_mask; sym++) {
122#ifdef BITS_ORDER_MSB 121#ifdef BITS_ORDER_MSB
123 table[sym] = 0xFFFF; 122 table[sym] = 0xFFFF;
124#else 123#else
125 reverse = sym; leaf = 0; fill = nbits; 124 reverse = sym; leaf = 0; fill = nbits;
126 do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill); 125 do { leaf <<= 1; leaf |= reverse & 1; reverse >>= 1; } while (--fill);
127 table[leaf] = 0xFFFF; 126 table[leaf] = 0xFFFF;
128#endif 127#endif
129 } 128 }
130 129
@@ -138,33 +137,33 @@ static int make_decode_table(unsigned int nsyms, unsigned int nbits,
138 bit_mask = 1 << 15; 137 bit_mask = 1 << 15;
139 138
140 for (bit_num = nbits+1; bit_num <= HUFF_MAXBITS; bit_num++) { 139 for (bit_num = nbits+1; bit_num <= HUFF_MAXBITS; bit_num++) {
141 for (sym = 0; sym < nsyms; sym++) { 140 for (sym = 0; sym < nsyms; sym++) {
142 if (length[sym] != bit_num) continue; 141 if (length[sym] != bit_num) continue;
142 if (pos >= table_mask) return 1; /* table overflow */
143 143
144#ifdef BITS_ORDER_MSB 144#ifdef BITS_ORDER_MSB
145 leaf = pos >> 16; 145 leaf = pos >> 16;
146#else 146#else
147 /* leaf = the first nbits of the code, reversed */ 147 /* leaf = the first nbits of the code, reversed */
148 reverse = pos >> 16; leaf = 0; fill = nbits; 148 reverse = pos >> 16; leaf = 0; fill = nbits;
149 do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill); 149 do {leaf <<= 1; leaf |= reverse & 1; reverse >>= 1;} while (--fill);
150#endif 150#endif
151 for (fill = 0; fill < (bit_num - nbits); fill++) { 151 for (fill = 0; fill < (bit_num - nbits); fill++) {
152 /* if this path hasn't been taken yet, 'allocate' two entries */ 152 /* if this path hasn't been taken yet, 'allocate' two entries */
153 if (table[leaf] == 0xFFFF) { 153 if (table[leaf] == 0xFFFF) {
154 table[(next_symbol << 1) ] = 0xFFFF; 154 table[(next_symbol << 1) ] = 0xFFFF;
155 table[(next_symbol << 1) + 1 ] = 0xFFFF; 155 table[(next_symbol << 1) + 1 ] = 0xFFFF;
156 table[leaf] = next_symbol++; 156 table[leaf] = next_symbol++;
157 } 157 }
158 158
159 /* follow the path and select either left or right for next bit */ 159 /* follow the path and select either left or right for next bit */
160 leaf = table[leaf] << 1; 160 leaf = table[leaf] << 1;
161 if ((pos >> (15-fill)) & 1) leaf++; 161 if ((pos >> (15-fill)) & 1) leaf++;
162 } 162 }
163 table[leaf] = sym; 163 table[leaf] = sym;
164 164 pos += bit_mask;
165 if ((pos += bit_mask) > table_mask) return 1; /* table overflow */ 165 }
166 } 166 bit_mask >>= 1;
167 bit_mask >>= 1;
168 } 167 }
169 168
170 /* full table? */ 169 /* full table? */
diff --git a/rbutil/rbutilqt/mspack/system-mspack.c b/rbutil/rbutilqt/mspack/system-mspack.c
index 13946576fc..9d4886a8db 100644
--- a/rbutil/rbutilqt/mspack/system-mspack.c
+++ b/rbutil/rbutilqt/mspack/system-mspack.c
@@ -8,7 +8,7 @@
8 */ 8 */
9 9
10#ifdef HAVE_CONFIG_H 10#ifdef HAVE_CONFIG_H
11# include <config.h> 11# include "config.h"
12#endif 12#endif
13 13
14#include "system-mspack.h" 14#include "system-mspack.h"
diff --git a/rbutil/rbutilqt/mspack/system-mspack.h b/rbutil/rbutilqt/mspack/system-mspack.h
index 7a033cb04a..a0e6cf3ca8 100644
--- a/rbutil/rbutilqt/mspack/system-mspack.h
+++ b/rbutil/rbutilqt/mspack/system-mspack.h
@@ -16,7 +16,7 @@ extern "C" {
16 16
17/* ensure config.h is read before mspack.h */ 17/* ensure config.h is read before mspack.h */
18#ifdef HAVE_CONFIG_H 18#ifdef HAVE_CONFIG_H
19# include <config.h> 19# include "config.h"
20#endif 20#endif
21 21
22#include "mspack.h" 22#include "mspack.h"
@@ -61,7 +61,7 @@ extern "C" {
61 (defined(FILESIZEBITS) && FILESIZEBITS >= 64) || \ 61 (defined(FILESIZEBITS) && FILESIZEBITS >= 64) || \
62 (defined(SIZEOF_OFF_T) && SIZEOF_OFF_T >= 8) || \ 62 (defined(SIZEOF_OFF_T) && SIZEOF_OFF_T >= 8) || \
63 defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE)) 63 defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE))
64# define LARGEFILE_SUPPORT 64# define LARGEFILE_SUPPORT 1
65# define LD "lld" 65# define LD "lld"
66# define LU "llu" 66# define LU "llu"
67#else 67#else
diff --git a/rbutil/rbutilqt/mspack/szddd.c b/rbutil/rbutilqt/mspack/szddd.c
index af77f15565..1d6d05f844 100644
--- a/rbutil/rbutilqt/mspack/szddd.c
+++ b/rbutil/rbutilqt/mspack/szddd.c
@@ -66,8 +66,8 @@ void mspack_destroy_szdd_decompressor(struct msszdd_decompressor *base)
66{ 66{
67 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base; 67 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
68 if (self) { 68 if (self) {
69 struct mspack_system *sys = self->system; 69 struct mspack_system *sys = self->system;
70 sys->free(self); 70 sys->free(self);
71 } 71 }
72} 72}
73 73
@@ -77,7 +77,7 @@ void mspack_destroy_szdd_decompressor(struct msszdd_decompressor *base)
77 * opens an SZDD file without decompressing, reads header 77 * opens an SZDD file without decompressing, reads header
78 */ 78 */
79static struct msszddd_header *szddd_open(struct msszdd_decompressor *base, 79static struct msszddd_header *szddd_open(struct msszdd_decompressor *base,
80 const char *filename) 80 const char *filename)
81{ 81{
82 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base; 82 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
83 struct msszddd_header *hdr; 83 struct msszddd_header *hdr;
@@ -90,18 +90,18 @@ static struct msszddd_header *szddd_open(struct msszdd_decompressor *base,
90 fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ); 90 fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
91 hdr = (struct msszddd_header *) sys->alloc(sys, sizeof(struct msszddd_header_p)); 91 hdr = (struct msszddd_header *) sys->alloc(sys, sizeof(struct msszddd_header_p));
92 if (fh && hdr) { 92 if (fh && hdr) {
93 ((struct msszddd_header_p *) hdr)->fh = fh; 93 ((struct msszddd_header_p *) hdr)->fh = fh;
94 self->error = szddd_read_headers(sys, fh, hdr); 94 self->error = szddd_read_headers(sys, fh, hdr);
95 } 95 }
96 else { 96 else {
97 if (!fh) self->error = MSPACK_ERR_OPEN; 97 if (!fh) self->error = MSPACK_ERR_OPEN;
98 if (!hdr) self->error = MSPACK_ERR_NOMEMORY; 98 if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
99 } 99 }
100 100
101 if (self->error) { 101 if (self->error) {
102 if (fh) sys->close(fh); 102 if (fh) sys->close(fh);
103 if (hdr) sys->free(hdr); 103 sys->free(hdr);
104 hdr = NULL; 104 hdr = NULL;
105 } 105 }
106 106
107 return hdr; 107 return hdr;
@@ -113,7 +113,7 @@ static struct msszddd_header *szddd_open(struct msszdd_decompressor *base,
113 * closes an SZDD file 113 * closes an SZDD file
114 */ 114 */
115static void szddd_close(struct msszdd_decompressor *base, 115static void szddd_close(struct msszdd_decompressor *base,
116 struct msszddd_header *hdr) 116 struct msszddd_header *hdr)
117{ 117{
118 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base; 118 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
119 struct msszddd_header_p *hdr_p = (struct msszddd_header_p *) hdr; 119 struct msszddd_header_p *hdr_p = (struct msszddd_header_p *) hdr;
@@ -142,33 +142,33 @@ static unsigned char szdd_signature_qbasic[8] = {
142}; 142};
143 143
144static int szddd_read_headers(struct mspack_system *sys, 144static int szddd_read_headers(struct mspack_system *sys,
145 struct mspack_file *fh, 145 struct mspack_file *fh,
146 struct msszddd_header *hdr) 146 struct msszddd_header *hdr)
147{ 147{
148 unsigned char buf[8]; 148 unsigned char buf[8];
149 149
150 /* read and check signature */ 150 /* read and check signature */
151 if (sys->read(fh, buf, 8) != 8) return MSPACK_ERR_READ; 151 if (sys->read(fh, buf, 8) != 8) return MSPACK_ERR_READ;
152 152
153 if ((mspack_memcmp(buf, szdd_signature_expand, 8) == 0)) { 153 if ((memcmp(buf, szdd_signature_expand, 8) == 0)) {
154 /* common SZDD */ 154 /* common SZDD */
155 hdr->format = MSSZDD_FMT_NORMAL; 155 hdr->format = MSSZDD_FMT_NORMAL;
156 156
157 /* read the rest of the header */ 157 /* read the rest of the header */
158 if (sys->read(fh, buf, 6) != 6) return MSPACK_ERR_READ; 158 if (sys->read(fh, buf, 6) != 6) return MSPACK_ERR_READ;
159 if (buf[0] != 0x41) return MSPACK_ERR_DATAFORMAT; 159 if (buf[0] != 0x41) return MSPACK_ERR_DATAFORMAT;
160 hdr->missing_char = buf[1]; 160 hdr->missing_char = buf[1];
161 hdr->length = EndGetI32(&buf[2]); 161 hdr->length = EndGetI32(&buf[2]);
162 } 162 }
163 else if ((mspack_memcmp(buf, szdd_signature_qbasic, 8) == 0)) { 163 else if ((memcmp(buf, szdd_signature_qbasic, 8) == 0)) {
164 /* special QBasic SZDD */ 164 /* special QBasic SZDD */
165 hdr->format = MSSZDD_FMT_QBASIC; 165 hdr->format = MSSZDD_FMT_QBASIC;
166 if (sys->read(fh, buf, 4) != 4) return MSPACK_ERR_READ; 166 if (sys->read(fh, buf, 4) != 4) return MSPACK_ERR_READ;
167 hdr->missing_char = '\0'; 167 hdr->missing_char = '\0';
168 hdr->length = EndGetI32(buf); 168 hdr->length = EndGetI32(buf);
169 } 169 }
170 else { 170 else {
171 return MSPACK_ERR_SIGNATURE; 171 return MSPACK_ERR_SIGNATURE;
172 } 172 }
173 return MSPACK_ERR_OK; 173 return MSPACK_ERR_OK;
174} 174}
@@ -179,7 +179,7 @@ static int szddd_read_headers(struct mspack_system *sys,
179 * decompresses an SZDD file 179 * decompresses an SZDD file
180 */ 180 */
181static int szddd_extract(struct msszdd_decompressor *base, 181static int szddd_extract(struct msszdd_decompressor *base,
182 struct msszddd_header *hdr, const char *filename) 182 struct msszddd_header *hdr, const char *filename)
183{ 183{
184 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base; 184 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
185 struct mspack_file *fh, *outfh; 185 struct mspack_file *fh, *outfh;
@@ -195,19 +195,19 @@ static int szddd_extract(struct msszdd_decompressor *base,
195 /* seek to the compressed data */ 195 /* seek to the compressed data */
196 data_offset = (hdr->format == MSSZDD_FMT_NORMAL) ? 14 : 12; 196 data_offset = (hdr->format == MSSZDD_FMT_NORMAL) ? 14 : 12;
197 if (sys->seek(fh, data_offset, MSPACK_SYS_SEEK_START)) { 197 if (sys->seek(fh, data_offset, MSPACK_SYS_SEEK_START)) {
198 return self->error = MSPACK_ERR_SEEK; 198 return self->error = MSPACK_ERR_SEEK;
199 } 199 }
200 200
201 /* open file for output */ 201 /* open file for output */
202 if (!(outfh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) { 202 if (!(outfh = sys->open(sys, filename, MSPACK_SYS_OPEN_WRITE))) {
203 return self->error = MSPACK_ERR_OPEN; 203 return self->error = MSPACK_ERR_OPEN;
204 } 204 }
205 205
206 /* decompress the data */ 206 /* decompress the data */
207 self->error = lzss_decompress(sys, fh, outfh, SZDD_INPUT_SIZE, 207 self->error = lzss_decompress(sys, fh, outfh, SZDD_INPUT_SIZE,
208 hdr->format == MSSZDD_FMT_NORMAL 208 hdr->format == MSSZDD_FMT_NORMAL
209 ? LZSS_MODE_EXPAND 209 ? LZSS_MODE_EXPAND
210 : LZSS_MODE_QBASIC); 210 : LZSS_MODE_QBASIC);
211 211
212 /* close output file */ 212 /* close output file */
213 sys->close(outfh); 213 sys->close(outfh);
@@ -221,7 +221,7 @@ static int szddd_extract(struct msszdd_decompressor *base,
221 * unpacks directly from input to output 221 * unpacks directly from input to output
222 */ 222 */
223static int szddd_decompress(struct msszdd_decompressor *base, 223static int szddd_decompress(struct msszdd_decompressor *base,
224 const char *input, const char *output) 224 const char *input, const char *output)
225{ 225{
226 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base; 226 struct msszdd_decompressor_p *self = (struct msszdd_decompressor_p *) base;
227 struct msszddd_header *hdr; 227 struct msszddd_header *hdr;