diff options
author | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2020-06-08 21:44:02 +0200 |
---|---|---|
committer | Dominik Riebeling <Dominik.Riebeling@gmail.com> | 2020-08-07 22:18:41 +0200 |
commit | 729b6e4f33419489415a6111bb98e5d95221a338 (patch) | |
tree | 87e83604959f7d848e80287aa799900cd0a9f989 | |
parent | b0f22620a2dbfb991b10a8e1e8b0c8db5e3ee117 (diff) | |
download | rockbox-729b6e4f33419489415a6111bb98e5d95221a338.tar.gz rockbox-729b6e4f33419489415a6111bb98e5d95221a338.zip |
rbutil: Update libmspack to 0.10.1alpha.
Update to the most recent release. Fix name / include clashes, as has
been done before.
Change-Id: Ia712bb2b5f4b9018b65a46b8bdd04ba42363be8b
-rw-r--r-- | rbutil/rbutilqt/mspack/README.ROCKBOX | 4 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/cab.h | 27 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/cabd.c | 541 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/chmd.c | 667 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/kwajd.c | 365 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/lzss.h | 8 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/lzssd.c | 84 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/lzx.h | 61 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/lzxd.c | 793 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/mspack.h | 316 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/mszip.h | 17 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/mszipd.c | 268 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/qtm.h | 8 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/qtmd.c | 235 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/readbits.h | 104 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/readhuff.h | 129 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/system-mspack.c | 2 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/system-mspack.h | 4 | ||||
-rw-r--r-- | rbutil/rbutilqt/mspack/szddd.c | 70 |
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 @@ | |||
1 | This folder contains the mspack project for MS files compression/decompression. | 1 | This folder contains the mspack project for MS files compression/decompression. |
2 | These files are distributed under the LGPL. | 2 | These files are distributed under the LGPL. |
3 | The source files have been last synced with libmspack-0.3alpha | ||
4 | http://sourceforge.net/projects/libmspack/on January 28, 2013 | ||
5 | 3 | ||
4 | The source files have been last synced with libmspack-0.10.1alpha | ||
5 | https://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 | ||
75 | struct mscab_compressor_p { | 87 | struct 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 | ||
99 | struct mscab_decompressor_p { | 112 | struct 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); |
73 | static int cabd_read_headers( | 75 | static 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); |
76 | static char *cabd_read_string( | 78 | static 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 | ||
80 | static struct mscabd_cabinet *cabd_search( | 81 | static 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); |
111 | static int cabd_sys_read_block( | 112 | static 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); |
114 | static unsigned int cabd_checksum( | 115 | static unsigned int cabd_checksum( |
115 | unsigned char *data, unsigned int bytes, unsigned int cksum); | 116 | unsigned char *data, unsigned int bytes, unsigned int cksum); |
116 | static struct noned_state *noned_init( | 117 | static 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 | */ |
189 | static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base, | 191 | static 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 | */ |
227 | static void cabd_close(struct mscab_decompressor *base, | 229 | static 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 | */ |
306 | static int cabd_read_headers(struct mspack_system *sys, | 308 | static 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 | ||
520 | static char *cabd_read_string(struct mspack_system *sys, | 537 | static 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 | */ |
568 | static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base, | 589 | static 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 | ||
622 | static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf, | 643 | static 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 | */ |
777 | static int cabd_prepend(struct mscab_decompressor *base, | 798 | static 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 | ||
784 | static int cabd_append(struct mscab_decompressor *base, | 805 | static 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 | ||
791 | static int cabd_merge(struct mscab_decompressor *base, | 812 | static 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 | ||
1136 | static void cabd_free_decomp(struct mscab_decompressor_p *self) { | 1191 | static 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 | */ |
1240 | static int cabd_sys_read_block(struct mspack_system *sys, | 1295 | static 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 | ||
1335 | static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes, | 1395 | static 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 | ||
1367 | static struct noned_state *noned_init(struct mspack_system *sys, | 1427 | static 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); |
45 | static int read_reset_table( | 45 | static 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); |
48 | static int read_spaninfo( | 48 | static 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 | */ |
123 | static struct mschmd_header *chmd_open(struct mschm_decompressor *base, | 123 | static 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 | */ |
135 | static struct mschmd_header *chmd_fast_open(struct mschm_decompressor *base, | 135 | static 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 | */ |
148 | static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base, | 148 | static 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 | */ |
194 | static void chmd_close(struct mschm_decompressor *base, | 194 | static 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 | ||
262 | static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh, | 262 | static 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 | */ |
486 | static int chmd_fast_find(struct mschm_decompressor *base, | 534 | static 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 | */ |
568 | static unsigned char *read_chunk(struct mschm_decompressor_p *self, | 624 | static 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 | */ |
635 | static int search_chunk(struct mschmd_header *chm, | 691 | static 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 | */ | ||
790 | static 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 | */ |
863 | static int chmd_extract(struct mschm_decompressor *base, | 887 | static 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 | */ |
1011 | static int chmd_init_decomp(struct mschm_decompressor_p *self, | 1035 | static 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 | */ |
1133 | static int read_reset_table(struct mschm_decompressor_p *self, | 1157 | static 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 | */ |
1207 | static int read_spaninfo(struct mschm_decompressor_p *self, | 1232 | static 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 | */ |
1244 | static int find_sys_file(struct mschm_decompressor_p *self, | 1275 | static 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 | */ |
1282 | static unsigned char *read_sys_file(struct mschm_decompressor_p *self, | 1313 | static 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 | */ |
1333 | static int read_off64(off_t *var, unsigned char *mem, | 1364 | static 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 */ |
19 | static struct mskwajd_header *kwajd_open( | 20 | static struct mskwajd_header *kwajd_open( |
@@ -40,7 +41,7 @@ static void lzh_free( | |||
40 | static int lzh_read_lens( | 41 | static 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); |
44 | static int lzh_read_input( | 45 | static 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 | */ |
92 | static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base, | 93 | static 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 | */ |
128 | static void kwajd_close(struct mskwaj_decompressor *base, | 129 | static 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 | */ |
150 | static int kwajd_read_headers(struct mspack_system *sys, | 151 | static 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 | */ |
246 | static int kwajd_extract(struct mskwaj_decompressor *base, | 253 | static 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 | */ |
319 | static int kwajd_decompress(struct mskwaj_decompressor *base, | 331 | static 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 | ||
411 | static struct kwajd_stream *lzh_init(struct mspack_system *sys, | 422 | static 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 | ||
489 | static int lzh_read_lens(struct kwajd_stream *lzh, | 500 | static 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, | |||
534 | static int lzh_read_input(struct kwajd_stream *lzh) { | 545 | static 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 | */ |
56 | extern int lzss_decompress(struct mspack_system *system, | 56 | extern 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 | ||
37 | int lzss_decompress(struct mspack_system *system, | 37 | int 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 | */ |
141 | extern struct lzxd_stream *lzxd_init(struct mspack_system *system, | 147 | extern 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() */ |
150 | extern void lzxd_set_output_length(struct lzxd_stream *lzx, | 157 | extern 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 | */ | ||
175 | extern 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 | ||
134 | static int lzxd_read_lens(struct lzxd_stream *lzx, unsigned char *lens, | 138 | static 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 | */ |
202 | static const unsigned int position_base[51] = { | 214 | static 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, | 217 | static 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 | }; |
209 | static const unsigned char extra_bits[51] = { | 221 | static 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 | ||
215 | static void lzxd_reset_state(struct lzxd_stream *lzx) { | 262 | static 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 | ||
232 | struct lzxd_stream *lzxd_init(struct mspack_system *system, | 279 | struct 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 | ||
354 | int 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 | |||
295 | void lzxd_set_output_length(struct lzxd_stream *lzx, off_t out_bytes) { | 390 | void 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 | ||
299 | int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { | 394 | int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { |
@@ -304,7 +399,7 @@ int lzxd_decompress(struct lzxd_stream *lzx, off_t out_bytes) { | |||
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); | |||
645 | extern void mspack_destroy_kwaj_decompressor(struct mskwaj_decompressor *self); | 658 | extern 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 | */ | ||
665 | extern 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 | */ | ||
672 | extern 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 | */ | ||
678 | extern 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 | */ | ||
683 | extern 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 */ |
901 | struct mscab_compressor { | 946 | struct 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 | */ | ||
2255 | struct 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 | */ | ||
2307 | struct 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 | ||
45 | struct mszipd_stream { | 45 | struct 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 | */ |
85 | extern struct mszipd_stream *mszipd_init(struct mspack_system *system, | 85 | extern 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 | */ |
109 | extern int mszipd_decompress(struct mszipd_stream *zip, off_t out_bytes); | 109 | extern 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 | */ | ||
114 | extern 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 | */ |
330 | static int mszipd_flush_window(struct mszipd_stream *zip, | 330 | static 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 | ||
342 | struct mszipd_stream *mszipd_init(struct mspack_system *system, | 342 | struct 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 | ||
469 | int 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 | |||
468 | void mszipd_free(struct mszipd_stream *zip) { | 508 | void 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 | */ |
92 | extern struct qtmd_stream *qtmd_init(struct mspack_system *system, | 92 | extern 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 */ |
168 | static void qtmd_init_model(struct qtmd_model *model, | 168 | static 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 | ||
186 | struct qtmd_stream *qtmd_init(struct mspack_system *system, | 186 | struct 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 | ||
183 | static int read_input(BITS_TYPE *p) { | 183 | static 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 | */ |
79 | static int make_decode_table(unsigned int nsyms, unsigned int nbits, | 78 | static 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 | */ |
79 | static struct msszddd_header *szddd_open(struct msszdd_decompressor *base, | 79 | static 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 | */ |
115 | static void szddd_close(struct msszdd_decompressor *base, | 115 | static 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 | ||
144 | static int szddd_read_headers(struct mspack_system *sys, | 144 | static 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 | */ |
181 | static int szddd_extract(struct msszdd_decompressor *base, | 181 | static 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 | */ |
223 | static int szddd_decompress(struct msszdd_decompressor *base, | 223 | static 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; |