libmspack 0.0.5 → 0.10.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/rake.yml +37 -0
- data/.gitignore +2 -0
- data/.yardopts +1 -1
- data/README.md +1 -1
- data/Rakefile +11 -5
- data/ext/Rakefile +1 -1
- data/ext/libmspack/AUTHORS +1 -0
- data/ext/libmspack/ChangeLog +321 -4
- data/ext/libmspack/INSTALL +368 -0
- data/ext/libmspack/Makefile.am +86 -95
- data/ext/libmspack/Makefile.in +1729 -0
- data/ext/libmspack/README +30 -30
- data/ext/libmspack/acinclude.m4 +99 -0
- data/ext/libmspack/aclocal.m4 +1218 -0
- data/ext/libmspack/ar-lib +270 -0
- data/ext/libmspack/compile +347 -0
- data/ext/libmspack/config.guess +1480 -0
- data/ext/libmspack/config.h.in +129 -0
- data/ext/libmspack/config.sub +1801 -0
- data/ext/libmspack/configure +15487 -0
- data/ext/libmspack/configure.ac +11 -13
- data/ext/libmspack/depcomp +791 -0
- data/ext/libmspack/install-sh +508 -0
- data/ext/libmspack/libmscabd.la +41 -0
- data/ext/libmspack/libmschmd.la +41 -0
- data/ext/libmspack/libmspack.la +41 -0
- data/ext/libmspack/ltmain.sh +11156 -0
- data/ext/libmspack/m4/libtool.m4 +8387 -0
- data/ext/libmspack/m4/ltoptions.m4 +437 -0
- data/ext/libmspack/m4/ltsugar.m4 +124 -0
- data/ext/libmspack/m4/ltversion.m4 +23 -0
- data/ext/libmspack/m4/lt~obsolete.m4 +99 -0
- data/ext/libmspack/missing +215 -0
- data/ext/libmspack/mspack/cab.h +20 -7
- data/ext/libmspack/mspack/cabd.c +301 -236
- data/ext/libmspack/mspack/chmd.c +304 -319
- data/ext/libmspack/mspack/crc32.c +52 -52
- data/ext/libmspack/mspack/crc32.h +1 -1
- data/ext/libmspack/mspack/kwajd.c +178 -172
- data/ext/libmspack/mspack/lzss.h +4 -4
- data/ext/libmspack/mspack/lzssd.c +42 -42
- data/ext/libmspack/mspack/lzx.h +11 -11
- data/ext/libmspack/mspack/lzxd.c +370 -361
- data/ext/libmspack/mspack/mspack.h +109 -77
- data/ext/libmspack/mspack/mszip.h +6 -6
- data/ext/libmspack/mspack/mszipd.c +140 -139
- data/ext/libmspack/mspack/oab.h +1 -0
- data/ext/libmspack/mspack/oabd.c +71 -73
- data/ext/libmspack/mspack/qtm.h +4 -4
- data/ext/libmspack/mspack/qtmd.c +118 -117
- data/ext/libmspack/mspack/readbits.h +52 -52
- data/ext/libmspack/mspack/readhuff.h +61 -61
- data/ext/libmspack/mspack/system.c +15 -9
- data/ext/libmspack/mspack/system.h +38 -50
- data/ext/libmspack/mspack/szddd.c +35 -35
- data/ext/libmspack/test-driver +148 -0
- data/ext/x86_64-linux/libmspack.so +0 -0
- data/ext/x86_64-windows/mspack.dll +0 -0
- data/lib/libmspack/version.rb +2 -1
- data/lib/libmspack.rb +1 -1
- data/libmspack.gemspec +4 -4
- data/spec/libmspack_spec.rb +5 -4
- metadata +38 -105
- data/.travis.yml +0 -5
- data/ext/i386-windows/libmspack.dll +0 -0
- data/ext/libmspack/cleanup.sh +0 -9
- data/ext/libmspack/debian/changelog +0 -6
- data/ext/libmspack/debian/control +0 -14
- data/ext/libmspack/debian/rules +0 -101
- data/ext/libmspack/doc/Doxyfile.in +0 -22
- data/ext/libmspack/doc/Makefile.in +0 -14
- data/ext/libmspack/doc/szdd_kwaj_format.html +0 -331
- data/ext/libmspack/mspack/mspack.def +0 -28
- data/ext/libmspack/mspack/qtmc.c +0 -18
- data/ext/libmspack/rebuild.sh +0 -8
- data/ext/libmspack/test/cabd_c10 +0 -19
- data/ext/libmspack/test/cabd_compare +0 -34
- data/ext/libmspack/test/cabd_md5.c +0 -161
- data/ext/libmspack/test/cabd_memory.c +0 -179
- data/ext/libmspack/test/cabd_test.c +0 -386
- data/ext/libmspack/test/cabrip.c +0 -81
- data/ext/libmspack/test/chmd_compare +0 -38
- data/ext/libmspack/test/chmd_find.c +0 -95
- data/ext/libmspack/test/chmd_md5.c +0 -67
- data/ext/libmspack/test/chmd_order.c +0 -144
- data/ext/libmspack/test/chminfo.c +0 -284
- data/ext/libmspack/test/chmx.c +0 -216
- data/ext/libmspack/test/error.h +0 -22
- data/ext/libmspack/test/expand.c +0 -79
- data/ext/libmspack/test/md5.c +0 -457
- data/ext/libmspack/test/md5.h +0 -165
- data/ext/libmspack/test/md5_fh.h +0 -123
- data/ext/libmspack/test/msdecompile_md5 +0 -24
- data/ext/libmspack/test/msexpand_md5 +0 -39
- data/ext/libmspack/test/multifh.c +0 -435
- data/ext/libmspack/test/oabx.c +0 -41
- data/ext/libmspack/test/test_files/cabd/1.pl +0 -84
- data/ext/libmspack/test/test_files/cabd/2.pl +0 -75
- data/ext/libmspack/test/test_files/cabd/bad_folderindex.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_nofiles.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_nofolders.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_signature.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt1.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt2.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt3.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt4.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt5.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/normal_255c_filename.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/normal_2files_1folder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nodata.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nofiles.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nofolder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortextheader.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfile1.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfile2.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfolder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortheader.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nofname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_noninfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nonname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nopinfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nopname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortfname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortninfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortnname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortpinfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortpname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_---.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_--D.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_-F-.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_-FD.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_H--.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_H-D.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_HF-.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_HFD.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/search_basic.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/search_tricky1.cab +0 -0
- data/ext/libmspack/winbuild.sh +0 -26
- data/ext/libmspack.h +0 -259
- data/ext/x86_64-windows/libmspack.dll +0 -0
data/ext/libmspack/mspack/cabd.c
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* This file is part of libmspack.
|
|
2
|
-
* (C) 2003-
|
|
2
|
+
* (C) 2003-2018 Stuart Caie.
|
|
3
3
|
*
|
|
4
4
|
* libmspack is free software; you can redistribute it and/or modify it under
|
|
5
5
|
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
|
|
24
24
|
#include <system.h>
|
|
25
25
|
#include <cab.h>
|
|
26
|
-
#include <
|
|
26
|
+
#include <mszip.h>
|
|
27
|
+
#include <lzx.h>
|
|
28
|
+
#include <qtm.h>
|
|
27
29
|
|
|
28
30
|
/* Notes on compliance with cabinet specification:
|
|
29
31
|
*
|
|
@@ -72,7 +74,7 @@ static void cabd_close(
|
|
|
72
74
|
struct mscab_decompressor *base, struct mscabd_cabinet *origcab);
|
|
73
75
|
static int cabd_read_headers(
|
|
74
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
78
|
static char *cabd_read_string(
|
|
77
79
|
struct mspack_system *sys, struct mspack_file *fh, int *error);
|
|
78
80
|
|
|
@@ -109,7 +111,7 @@ static int cabd_sys_write(
|
|
|
109
111
|
struct mspack_file *file, void *buffer, int bytes);
|
|
110
112
|
static int cabd_sys_read_block(
|
|
111
113
|
struct mspack_system *sys, struct mscabd_decompress_state *d, int *out,
|
|
112
|
-
int ignore_cksum);
|
|
114
|
+
int ignore_cksum, int ignore_blocksize);
|
|
113
115
|
static unsigned int cabd_checksum(
|
|
114
116
|
unsigned char *data, unsigned int bytes, unsigned int cksum);
|
|
115
117
|
static struct noned_state *noned_init(
|
|
@@ -154,9 +156,10 @@ struct mscab_decompressor *
|
|
|
154
156
|
self->d = NULL;
|
|
155
157
|
self->error = MSPACK_ERR_OK;
|
|
156
158
|
|
|
157
|
-
self->
|
|
158
|
-
self->
|
|
159
|
-
self->
|
|
159
|
+
self->searchbuf_size = 32768;
|
|
160
|
+
self->fix_mszip = 0;
|
|
161
|
+
self->buf_size = 4096;
|
|
162
|
+
self->salvage = 0;
|
|
160
163
|
}
|
|
161
164
|
return (struct mscab_decompressor *) self;
|
|
162
165
|
}
|
|
@@ -170,9 +173,9 @@ void mspack_destroy_cab_decompressor(struct mscab_decompressor *base) {
|
|
|
170
173
|
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
|
|
171
174
|
if (self) {
|
|
172
175
|
struct mspack_system *sys = self->system;
|
|
173
|
-
cabd_free_decomp(self);
|
|
174
176
|
if (self->d) {
|
|
175
177
|
if (self->d->infh) sys->close(self->d->infh);
|
|
178
|
+
cabd_free_decomp(self);
|
|
176
179
|
sys->free(self->d);
|
|
177
180
|
}
|
|
178
181
|
sys->free(self);
|
|
@@ -186,7 +189,7 @@ void mspack_destroy_cab_decompressor(struct mscab_decompressor *base) {
|
|
|
186
189
|
* opens a file and tries to read it as a cabinet file
|
|
187
190
|
*/
|
|
188
191
|
static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
|
|
189
|
-
|
|
192
|
+
const char *filename)
|
|
190
193
|
{
|
|
191
194
|
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
|
|
192
195
|
struct mscabd_cabinet_p *cab = NULL;
|
|
@@ -200,10 +203,10 @@ static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
|
|
|
200
203
|
if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
|
|
201
204
|
if ((cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
|
|
202
205
|
cab->base.filename = filename;
|
|
203
|
-
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);
|
|
204
207
|
if (error) {
|
|
205
|
-
|
|
206
|
-
|
|
208
|
+
cabd_close(base, (struct mscabd_cabinet *) cab);
|
|
209
|
+
cab = NULL;
|
|
207
210
|
}
|
|
208
211
|
self->error = error;
|
|
209
212
|
}
|
|
@@ -224,7 +227,7 @@ static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
|
|
|
224
227
|
* frees all memory associated with a given mscabd_cabinet.
|
|
225
228
|
*/
|
|
226
229
|
static void cabd_close(struct mscab_decompressor *base,
|
|
227
|
-
|
|
230
|
+
struct mscabd_cabinet *origcab)
|
|
228
231
|
{
|
|
229
232
|
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
|
|
230
233
|
struct mscabd_folder_data *dat, *ndat;
|
|
@@ -252,16 +255,16 @@ static void cabd_close(struct mscab_decompressor *base,
|
|
|
252
255
|
|
|
253
256
|
/* free folder decompression state if it has been decompressed */
|
|
254
257
|
if (self->d && (self->d->folder == (struct mscabd_folder_p *) fol)) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
258
|
+
if (self->d->infh) sys->close(self->d->infh);
|
|
259
|
+
cabd_free_decomp(self);
|
|
260
|
+
sys->free(self->d);
|
|
261
|
+
self->d = NULL;
|
|
259
262
|
}
|
|
260
263
|
|
|
261
264
|
/* free folder data segments */
|
|
262
265
|
for (dat = ((struct mscabd_folder_p *)fol)->data.next; dat; dat = ndat) {
|
|
263
|
-
|
|
264
|
-
|
|
266
|
+
ndat = dat->next;
|
|
267
|
+
sys->free(dat);
|
|
265
268
|
}
|
|
266
269
|
sys->free(fol);
|
|
267
270
|
}
|
|
@@ -303,11 +306,11 @@ static void cabd_close(struct mscab_decompressor *base,
|
|
|
303
306
|
* for folders and files as necessary
|
|
304
307
|
*/
|
|
305
308
|
static int cabd_read_headers(struct mspack_system *sys,
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
+
struct mspack_file *fh,
|
|
310
|
+
struct mscabd_cabinet_p *cab,
|
|
311
|
+
off_t offset, int salvage, int quiet)
|
|
309
312
|
{
|
|
310
|
-
int num_folders, num_files, folder_resv, i, x;
|
|
313
|
+
int num_folders, num_files, folder_resv, i, x, err, fidx;
|
|
311
314
|
struct mscabd_folder_p *fol, *linkfol = NULL;
|
|
312
315
|
struct mscabd_file *file, *linkfile = NULL;
|
|
313
316
|
unsigned char buf[64];
|
|
@@ -363,6 +366,7 @@ static int cabd_read_headers(struct mspack_system *sys,
|
|
|
363
366
|
|
|
364
367
|
/* read the reserved-sizes part of header, if present */
|
|
365
368
|
cab->base.flags = EndGetI16(&buf[cfhead_Flags]);
|
|
369
|
+
|
|
366
370
|
if (cab->base.flags & cfheadRESERVE_PRESENT) {
|
|
367
371
|
if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) {
|
|
368
372
|
return MSPACK_ERR_READ;
|
|
@@ -378,7 +382,7 @@ static int cabd_read_headers(struct mspack_system *sys,
|
|
|
378
382
|
/* skip the reserved header */
|
|
379
383
|
if (cab->base.header_resv) {
|
|
380
384
|
if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) {
|
|
381
|
-
|
|
385
|
+
return MSPACK_ERR_SEEK;
|
|
382
386
|
}
|
|
383
387
|
}
|
|
384
388
|
}
|
|
@@ -390,14 +394,18 @@ static int cabd_read_headers(struct mspack_system *sys,
|
|
|
390
394
|
|
|
391
395
|
/* read name and info of preceeding cabinet in set, if present */
|
|
392
396
|
if (cab->base.flags & cfheadPREV_CABINET) {
|
|
393
|
-
cab->base.prevname = cabd_read_string(sys, fh, &
|
|
394
|
-
|
|
397
|
+
cab->base.prevname = cabd_read_string(sys, fh, &err);
|
|
398
|
+
if (err) return err;
|
|
399
|
+
cab->base.previnfo = cabd_read_string(sys, fh, &err);
|
|
400
|
+
if (err) return err;
|
|
395
401
|
}
|
|
396
402
|
|
|
397
403
|
/* read name and info of next cabinet in set, if present */
|
|
398
404
|
if (cab->base.flags & cfheadNEXT_CABINET) {
|
|
399
|
-
cab->base.nextname = cabd_read_string(sys, fh, &
|
|
400
|
-
|
|
405
|
+
cab->base.nextname = cabd_read_string(sys, fh, &err);
|
|
406
|
+
if (err) return err;
|
|
407
|
+
cab->base.nextinfo = cabd_read_string(sys, fh, &err);
|
|
408
|
+
if (err) return err;
|
|
401
409
|
}
|
|
402
410
|
|
|
403
411
|
/* read folders */
|
|
@@ -407,7 +415,7 @@ static int cabd_read_headers(struct mspack_system *sys,
|
|
|
407
415
|
}
|
|
408
416
|
if (folder_resv) {
|
|
409
417
|
if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) {
|
|
410
|
-
|
|
418
|
+
return MSPACK_ERR_SEEK;
|
|
411
419
|
}
|
|
412
420
|
}
|
|
413
421
|
|
|
@@ -446,45 +454,44 @@ static int cabd_read_headers(struct mspack_system *sys,
|
|
|
446
454
|
file->offset = EndGetI32(&buf[cffile_FolderOffset]);
|
|
447
455
|
|
|
448
456
|
/* set folder pointer */
|
|
449
|
-
|
|
450
|
-
if (
|
|
451
|
-
/* normal folder index; count up to the correct folder
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
return MSPACK_ERR_DATAFORMAT;
|
|
457
|
+
fidx = EndGetI16(&buf[cffile_FolderIndex]);
|
|
458
|
+
if (fidx < cffileCONTINUED_FROM_PREV) {
|
|
459
|
+
/* normal folder index; count up to the correct folder */
|
|
460
|
+
if (fidx < num_folders) {
|
|
461
|
+
struct mscabd_folder *ifol = cab->base.folders;
|
|
462
|
+
while (fidx--) if (ifol) ifol = ifol->next;
|
|
463
|
+
file->folder = ifol;
|
|
464
|
+
}
|
|
465
|
+
else {
|
|
466
|
+
D(("invalid folder index"))
|
|
467
|
+
file->folder = NULL;
|
|
461
468
|
}
|
|
462
469
|
}
|
|
463
470
|
else {
|
|
464
471
|
/* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or
|
|
465
472
|
* CONTINUED_PREV_AND_NEXT */
|
|
466
|
-
if ((
|
|
467
|
-
|
|
473
|
+
if ((fidx == cffileCONTINUED_TO_NEXT) ||
|
|
474
|
+
(fidx == cffileCONTINUED_PREV_AND_NEXT))
|
|
468
475
|
{
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
476
|
+
/* get last folder */
|
|
477
|
+
struct mscabd_folder *ifol = cab->base.folders;
|
|
478
|
+
while (ifol->next) ifol = ifol->next;
|
|
479
|
+
file->folder = ifol;
|
|
480
|
+
|
|
481
|
+
/* set "merge next" pointer */
|
|
482
|
+
fol = (struct mscabd_folder_p *) ifol;
|
|
483
|
+
if (!fol->merge_next) fol->merge_next = file;
|
|
477
484
|
}
|
|
478
485
|
|
|
479
|
-
if ((
|
|
480
|
-
|
|
486
|
+
if ((fidx == cffileCONTINUED_FROM_PREV) ||
|
|
487
|
+
(fidx == cffileCONTINUED_PREV_AND_NEXT))
|
|
481
488
|
{
|
|
482
|
-
|
|
483
|
-
|
|
489
|
+
/* get first folder */
|
|
490
|
+
file->folder = cab->base.folders;
|
|
484
491
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
492
|
+
/* set "merge prev" pointer */
|
|
493
|
+
fol = (struct mscabd_folder_p *) file->folder;
|
|
494
|
+
if (!fol->merge_prev) fol->merge_prev = file;
|
|
488
495
|
}
|
|
489
496
|
}
|
|
490
497
|
|
|
@@ -501,10 +508,14 @@ static int cabd_read_headers(struct mspack_system *sys,
|
|
|
501
508
|
file->date_y = (x >> 9) + 1980;
|
|
502
509
|
|
|
503
510
|
/* get filename */
|
|
504
|
-
file->filename = cabd_read_string(sys, fh, &
|
|
505
|
-
|
|
511
|
+
file->filename = cabd_read_string(sys, fh, &err);
|
|
512
|
+
|
|
513
|
+
/* if folder index or filename are bad, either skip it or fail */
|
|
514
|
+
if (err || !file->folder) {
|
|
515
|
+
sys->free(file->filename);
|
|
506
516
|
sys->free(file);
|
|
507
|
-
|
|
517
|
+
if (salvage) continue;
|
|
518
|
+
return err ? err : MSPACK_ERR_DATAFORMAT;
|
|
508
519
|
}
|
|
509
520
|
|
|
510
521
|
/* link file entry into file list */
|
|
@@ -513,21 +524,34 @@ static int cabd_read_headers(struct mspack_system *sys,
|
|
|
513
524
|
linkfile = file;
|
|
514
525
|
}
|
|
515
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
|
+
|
|
516
534
|
return MSPACK_ERR_OK;
|
|
517
535
|
}
|
|
518
536
|
|
|
519
537
|
static char *cabd_read_string(struct mspack_system *sys,
|
|
520
|
-
|
|
538
|
+
struct mspack_file *fh, int *error)
|
|
521
539
|
{
|
|
522
540
|
off_t base = sys->tell(fh);
|
|
523
541
|
char buf[256], *str;
|
|
524
|
-
|
|
542
|
+
int len, i, ok;
|
|
525
543
|
|
|
526
544
|
/* read up to 256 bytes */
|
|
527
|
-
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
|
+
}
|
|
528
549
|
|
|
529
550
|
/* search for a null terminator in the buffer */
|
|
530
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
|
+
|
|
531
555
|
if (!ok) {
|
|
532
556
|
*error = MSPACK_ERR_DATAFORMAT;
|
|
533
557
|
return NULL;
|
|
@@ -563,7 +587,7 @@ static char *cabd_read_string(struct mspack_system *sys,
|
|
|
563
587
|
* break out of the loop and be sure that all resources are freed
|
|
564
588
|
*/
|
|
565
589
|
static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
|
|
566
|
-
|
|
590
|
+
const char *filename)
|
|
567
591
|
{
|
|
568
592
|
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
|
|
569
593
|
struct mscabd_cabinet_p *cab = NULL;
|
|
@@ -576,7 +600,7 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
|
|
|
576
600
|
sys = self->system;
|
|
577
601
|
|
|
578
602
|
/* allocate a search buffer */
|
|
579
|
-
search_buf = (unsigned char *) sys->alloc(sys, (size_t) self->
|
|
603
|
+
search_buf = (unsigned char *) sys->alloc(sys, (size_t) self->searchbuf_size);
|
|
580
604
|
if (!search_buf) {
|
|
581
605
|
self->error = MSPACK_ERR_NOMEMORY;
|
|
582
606
|
return NULL;
|
|
@@ -586,21 +610,21 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
|
|
|
586
610
|
if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
|
|
587
611
|
if (!(self->error = mspack_sys_filelen(sys, fh, &filelen))) {
|
|
588
612
|
self->error = cabd_find(self, search_buf, fh, filename,
|
|
589
|
-
|
|
613
|
+
filelen, &firstlen, &cab);
|
|
590
614
|
}
|
|
591
615
|
|
|
592
616
|
/* truncated / extraneous data warning: */
|
|
593
617
|
if (firstlen && (firstlen != filelen) &&
|
|
594
|
-
|
|
618
|
+
(!cab || (cab->base.base_offset == 0)))
|
|
595
619
|
{
|
|
596
620
|
if (firstlen < filelen) {
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
621
|
+
sys->message(fh, "WARNING; possible %" LD
|
|
622
|
+
" extra bytes at end of file.",
|
|
623
|
+
filelen - firstlen);
|
|
600
624
|
}
|
|
601
625
|
else {
|
|
602
|
-
|
|
603
|
-
|
|
626
|
+
sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.",
|
|
627
|
+
firstlen - filelen);
|
|
604
628
|
}
|
|
605
629
|
}
|
|
606
630
|
|
|
@@ -617,8 +641,8 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
|
|
|
617
641
|
}
|
|
618
642
|
|
|
619
643
|
static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
|
|
620
|
-
|
|
621
|
-
|
|
644
|
+
struct mspack_file *fh, const char *filename, off_t flen,
|
|
645
|
+
off_t *firstlen, struct mscabd_cabinet_p **firstcab)
|
|
622
646
|
{
|
|
623
647
|
struct mscabd_cabinet_p *cab, *link = NULL;
|
|
624
648
|
off_t caboff, offset, length;
|
|
@@ -627,7 +651,7 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
|
|
|
627
651
|
unsigned int cablen_u32 = 0, foffset_u32 = 0;
|
|
628
652
|
int false_cabs = 0;
|
|
629
653
|
|
|
630
|
-
#
|
|
654
|
+
#if !LARGEFILE_SUPPORT
|
|
631
655
|
/* detect 32-bit off_t overflow */
|
|
632
656
|
if (flen < 0) {
|
|
633
657
|
sys->message(fh, largefile_msg);
|
|
@@ -640,8 +664,8 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
|
|
|
640
664
|
/* search length is either the full length of the search buffer, or the
|
|
641
665
|
* amount of data remaining to the end of the file, whichever is less. */
|
|
642
666
|
length = flen - offset;
|
|
643
|
-
if (length > self->
|
|
644
|
-
length = self->
|
|
667
|
+
if (length > self->searchbuf_size) {
|
|
668
|
+
length = self->searchbuf_size;
|
|
645
669
|
}
|
|
646
670
|
|
|
647
671
|
/* fill the search buffer with data from disk */
|
|
@@ -651,22 +675,21 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
|
|
|
651
675
|
|
|
652
676
|
/* FAQ avoidance strategy */
|
|
653
677
|
if ((offset == 0) && (EndGetI32(&buf[0]) == 0x28635349)) {
|
|
654
|
-
sys->message(fh, "WARNING; found InstallShield header. "
|
|
655
|
-
|
|
656
|
-
"Use UNSHIELD from www.synce.org to unpack it.");
|
|
678
|
+
sys->message(fh, "WARNING; found InstallShield header. Use unshield "
|
|
679
|
+
"(https://github.com/twogood/unshield) to unpack this file");
|
|
657
680
|
}
|
|
658
681
|
|
|
659
682
|
/* read through the entire buffer. */
|
|
660
683
|
for (p = &buf[0], pend = &buf[length]; p < pend; ) {
|
|
661
684
|
switch (state) {
|
|
662
|
-
|
|
685
|
+
/* starting state */
|
|
663
686
|
case 0:
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
687
|
+
/* we spend most of our time in this while loop, looking for
|
|
688
|
+
* a leading 'M' of the 'MSCF' signature */
|
|
689
|
+
while (p < pend && *p != 0x4D) p++;
|
|
690
|
+
/* if we found tht 'M', advance state */
|
|
691
|
+
if (p++ < pend) state = 1;
|
|
692
|
+
break;
|
|
670
693
|
|
|
671
694
|
/* verify that the next 3 bytes are 'S', 'C' and 'F' */
|
|
672
695
|
case 1: state = (*p++ == 0x53) ? 2 : 0; break;
|
|
@@ -688,70 +711,71 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
|
|
|
688
711
|
case 17: foffset_u32 |= *p++ << 8; state++; break;
|
|
689
712
|
case 18: foffset_u32 |= *p++ << 16; state++; break;
|
|
690
713
|
case 19: foffset_u32 |= *p++ << 24;
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
714
|
+
/* now we have recieved 20 bytes of potential cab header. work out
|
|
715
|
+
* the offset in the file of this potential cabinet */
|
|
716
|
+
caboff = offset + (p - &buf[0]) - 20;
|
|
717
|
+
|
|
718
|
+
/* should reading cabinet fail, restart search just after 'MSCF' */
|
|
719
|
+
offset = caboff + 4;
|
|
720
|
+
|
|
721
|
+
/* capture the "length of cabinet" field if there is a cabinet at
|
|
722
|
+
* offset 0 in the file, regardless of whether the cabinet can be
|
|
723
|
+
* read correctly or not */
|
|
724
|
+
if (caboff == 0) *firstlen = (off_t) cablen_u32;
|
|
725
|
+
|
|
726
|
+
/* check that the files offset is less than the alleged length of
|
|
727
|
+
* the cabinet, and that the offset + the alleged length are
|
|
728
|
+
* 'roughly' within the end of overall file length. In salvage
|
|
729
|
+
* mode, don't check the alleged length, allow it to be garbage */
|
|
730
|
+
if ((foffset_u32 < cablen_u32) &&
|
|
731
|
+
((caboff + (off_t) foffset_u32) < (flen + 32)) &&
|
|
732
|
+
(((caboff + (off_t) cablen_u32) < (flen + 32)) || self->salvage))
|
|
733
|
+
{
|
|
734
|
+
/* likely cabinet found -- try reading it */
|
|
735
|
+
if (!(cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
|
|
736
|
+
return MSPACK_ERR_NOMEMORY;
|
|
737
|
+
}
|
|
738
|
+
cab->base.filename = filename;
|
|
739
|
+
if (cabd_read_headers(sys, fh, cab, caboff, self->salvage, 1)) {
|
|
740
|
+
/* destroy the failed cabinet */
|
|
741
|
+
cabd_close((struct mscab_decompressor *) self,
|
|
742
|
+
(struct mscabd_cabinet *) cab);
|
|
743
|
+
false_cabs++;
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
/* cabinet read correctly! */
|
|
747
|
+
|
|
748
|
+
/* link the cab into the list */
|
|
749
|
+
if (!link) *firstcab = cab;
|
|
750
|
+
else link->base.next = (struct mscabd_cabinet *) cab;
|
|
751
|
+
link = cab;
|
|
752
|
+
|
|
753
|
+
/* cause the search to restart after this cab's data. */
|
|
754
|
+
offset = caboff + (off_t) cablen_u32;
|
|
755
|
+
|
|
756
|
+
#if !LARGEFILE_SUPPORT
|
|
757
|
+
/* detect 32-bit off_t overflow */
|
|
758
|
+
if (offset < caboff) {
|
|
759
|
+
sys->message(fh, largefile_msg);
|
|
760
|
+
return MSPACK_ERR_OK;
|
|
761
|
+
}
|
|
762
|
+
#endif
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/* restart search */
|
|
767
|
+
if (offset >= flen) return MSPACK_ERR_OK;
|
|
768
|
+
if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
|
|
769
|
+
return MSPACK_ERR_SEEK;
|
|
770
|
+
}
|
|
771
|
+
length = 0;
|
|
772
|
+
p = pend;
|
|
773
|
+
state = 0;
|
|
774
|
+
break;
|
|
751
775
|
|
|
752
776
|
/* for bytes 4-7 and 12-15, just advance state/pointer */
|
|
753
777
|
default:
|
|
754
|
-
|
|
778
|
+
p++, state++;
|
|
755
779
|
} /* switch(state) */
|
|
756
780
|
} /* for (... p < pend ...) */
|
|
757
781
|
} /* for (... offset < length ...) */
|
|
@@ -762,7 +786,7 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
|
|
|
762
786
|
|
|
763
787
|
return MSPACK_ERR_OK;
|
|
764
788
|
}
|
|
765
|
-
|
|
789
|
+
|
|
766
790
|
/***************************************
|
|
767
791
|
* CABD_MERGE, CABD_PREPEND, CABD_APPEND
|
|
768
792
|
***************************************
|
|
@@ -772,22 +796,22 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
|
|
|
772
796
|
* merged folder's data parts list.
|
|
773
797
|
*/
|
|
774
798
|
static int cabd_prepend(struct mscab_decompressor *base,
|
|
775
|
-
|
|
776
|
-
|
|
799
|
+
struct mscabd_cabinet *cab,
|
|
800
|
+
struct mscabd_cabinet *prevcab)
|
|
777
801
|
{
|
|
778
802
|
return cabd_merge(base, prevcab, cab);
|
|
779
803
|
}
|
|
780
804
|
|
|
781
805
|
static int cabd_append(struct mscab_decompressor *base,
|
|
782
|
-
|
|
783
|
-
|
|
806
|
+
struct mscabd_cabinet *cab,
|
|
807
|
+
struct mscabd_cabinet *nextcab)
|
|
784
808
|
{
|
|
785
809
|
return cabd_merge(base, cab, nextcab);
|
|
786
810
|
}
|
|
787
811
|
|
|
788
812
|
static int cabd_merge(struct mscab_decompressor *base,
|
|
789
|
-
|
|
790
|
-
|
|
813
|
+
struct mscabd_cabinet *lcab,
|
|
814
|
+
struct mscabd_cabinet *rcab)
|
|
791
815
|
{
|
|
792
816
|
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
|
|
793
817
|
struct mscabd_folder_data *data, *ndata;
|
|
@@ -877,7 +901,7 @@ static int cabd_merge(struct mscab_decompressor *base,
|
|
|
877
901
|
* instead */
|
|
878
902
|
lfol->base.num_blocks += rfol->base.num_blocks - 1;
|
|
879
903
|
if ((rfol->merge_next == NULL) ||
|
|
880
|
-
|
|
904
|
+
(rfol->merge_next->folder != (struct mscabd_folder *) rfol))
|
|
881
905
|
{
|
|
882
906
|
lfol->merge_next = rfol->merge_next;
|
|
883
907
|
}
|
|
@@ -900,9 +924,9 @@ static int cabd_merge(struct mscab_decompressor *base,
|
|
|
900
924
|
rfi = fi->next;
|
|
901
925
|
/* if file's folder matches the merge folder, unlink and free it */
|
|
902
926
|
if (fi->folder == (struct mscabd_folder *) rfol) {
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
927
|
+
if (lfi) lfi->next = rfi; else lcab->files = rfi;
|
|
928
|
+
sys->free(fi->filename);
|
|
929
|
+
sys->free(fi);
|
|
906
930
|
}
|
|
907
931
|
else lfi = fi;
|
|
908
932
|
}
|
|
@@ -937,6 +961,12 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
|
|
|
937
961
|
return 0;
|
|
938
962
|
}
|
|
939
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
|
+
|
|
940
970
|
if (!(lfi = lfol->merge_next) || !(rfi = rfol->merge_prev)) {
|
|
941
971
|
D(("folder merge: one cabinet has no files to merge"))
|
|
942
972
|
return 0;
|
|
@@ -947,10 +977,10 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
|
|
|
947
977
|
* should be identical in number and order. to verify this, check the
|
|
948
978
|
* offset and length of each file. */
|
|
949
979
|
for (l=lfi, r=rfi; l; l=l->next, r=r->next) {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
980
|
+
if (!r || (l->offset != r->offset) || (l->length != r->length)) {
|
|
981
|
+
matching = 0;
|
|
982
|
+
break;
|
|
983
|
+
}
|
|
954
984
|
}
|
|
955
985
|
|
|
956
986
|
if (matching) return 1;
|
|
@@ -960,9 +990,9 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
|
|
|
960
990
|
* the merge with a warning about missing files. */
|
|
961
991
|
matching = 0;
|
|
962
992
|
for (l = lfi; l; l = l->next) {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
993
|
+
for (r = rfi; r; r = r->next) {
|
|
994
|
+
if (l->offset == r->offset && l->length == r->length) break;
|
|
995
|
+
}
|
|
966
996
|
if (r) matching = 1; else sys->message(NULL,
|
|
967
997
|
"WARNING; merged file %s not listed in both cabinets", l->filename);
|
|
968
998
|
}
|
|
@@ -982,6 +1012,7 @@ static int cabd_extract(struct mscab_decompressor *base,
|
|
|
982
1012
|
struct mscabd_folder_p *fol;
|
|
983
1013
|
struct mspack_system *sys;
|
|
984
1014
|
struct mspack_file *fh;
|
|
1015
|
+
off_t filelen;
|
|
985
1016
|
|
|
986
1017
|
if (!self) return MSPACK_ERR_ARGS;
|
|
987
1018
|
if (!file) return self->error = MSPACK_ERR_ARGS;
|
|
@@ -989,15 +1020,43 @@ static int cabd_extract(struct mscab_decompressor *base,
|
|
|
989
1020
|
sys = self->system;
|
|
990
1021
|
fol = (struct mscabd_folder_p *) file->folder;
|
|
991
1022
|
|
|
992
|
-
/*
|
|
993
|
-
if (
|
|
994
|
-
(((file->offset + file->length) / CAB_BLOCKMAX) > fol->base.num_blocks))
|
|
995
|
-
{
|
|
996
|
-
sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
|
|
997
|
-
"cabinet set is incomplete.", file->filename);
|
|
1023
|
+
/* if offset is beyond 2GB, nothing can be extracted */
|
|
1024
|
+
if (file->offset > CAB_LENGTHMAX) {
|
|
998
1025
|
return self->error = MSPACK_ERR_DATAFORMAT;
|
|
999
1026
|
}
|
|
1000
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
|
+
|
|
1001
1060
|
/* allocate generic decompression state */
|
|
1002
1061
|
if (!self->d) {
|
|
1003
1062
|
self->d = (struct mscabd_decompress_state *) sys->alloc(sys, sizeof(struct mscabd_decompress_state));
|
|
@@ -1013,14 +1072,19 @@ static int cabd_extract(struct mscab_decompressor *base,
|
|
|
1013
1072
|
}
|
|
1014
1073
|
|
|
1015
1074
|
/* do we need to change folder or reset the current folder? */
|
|
1016
|
-
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
|
+
|
|
1017
1081
|
/* do we need to open a new cab file? */
|
|
1018
1082
|
if (!self->d->infh || (fol->data.cab != self->d->incab)) {
|
|
1019
1083
|
/* close previous file handle if from a different cab */
|
|
1020
1084
|
if (self->d->infh) sys->close(self->d->infh);
|
|
1021
1085
|
self->d->incab = fol->data.cab;
|
|
1022
1086
|
self->d->infh = sys->open(sys, fol->data.cab->base.filename,
|
|
1023
|
-
|
|
1087
|
+
MSPACK_SYS_OPEN_READ);
|
|
1024
1088
|
if (!self->d->infh) return self->error = MSPACK_ERR_OPEN;
|
|
1025
1089
|
}
|
|
1026
1090
|
/* seek to start of data blocks */
|
|
@@ -1038,6 +1102,7 @@ static int cabd_extract(struct mscab_decompressor *base,
|
|
|
1038
1102
|
self->d->data = &fol->data;
|
|
1039
1103
|
self->d->offset = 0;
|
|
1040
1104
|
self->d->block = 0;
|
|
1105
|
+
self->d->outlen = 0;
|
|
1041
1106
|
self->d->i_ptr = self->d->i_end = &self->d->input[0];
|
|
1042
1107
|
|
|
1043
1108
|
/* read_error lasts for the lifetime of a decompressor */
|
|
@@ -1052,7 +1117,7 @@ static int cabd_extract(struct mscab_decompressor *base,
|
|
|
1052
1117
|
self->error = MSPACK_ERR_OK;
|
|
1053
1118
|
|
|
1054
1119
|
/* if file has more than 0 bytes */
|
|
1055
|
-
if (
|
|
1120
|
+
if (filelen) {
|
|
1056
1121
|
off_t bytes;
|
|
1057
1122
|
int error;
|
|
1058
1123
|
/* get to correct offset.
|
|
@@ -1062,14 +1127,14 @@ static int cabd_extract(struct mscab_decompressor *base,
|
|
|
1062
1127
|
*/
|
|
1063
1128
|
self->d->outfh = NULL;
|
|
1064
1129
|
if ((bytes = file->offset - self->d->offset)) {
|
|
1065
|
-
|
|
1066
|
-
|
|
1130
|
+
error = self->d->decompress(self->d->state, bytes);
|
|
1131
|
+
self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
|
|
1067
1132
|
}
|
|
1068
1133
|
|
|
1069
1134
|
/* if getting to the correct offset was error free, unpack file */
|
|
1070
1135
|
if (!self->error) {
|
|
1071
1136
|
self->d->outfh = fh;
|
|
1072
|
-
error = self->d->decompress(self->d->state,
|
|
1137
|
+
error = self->d->decompress(self->d->state, filelen);
|
|
1073
1138
|
self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
|
|
1074
1139
|
}
|
|
1075
1140
|
}
|
|
@@ -1095,34 +1160,27 @@ static int cabd_init_decomp(struct mscab_decompressor_p *self, unsigned int ct)
|
|
|
1095
1160
|
{
|
|
1096
1161
|
struct mspack_file *fh = (struct mspack_file *) self;
|
|
1097
1162
|
|
|
1098
|
-
assert(self && self->d);
|
|
1099
|
-
|
|
1100
|
-
/* free any existing decompressor */
|
|
1101
|
-
cabd_free_decomp(self);
|
|
1102
|
-
|
|
1103
1163
|
self->d->comp_type = ct;
|
|
1104
1164
|
|
|
1105
1165
|
switch (ct & cffoldCOMPTYPE_MASK) {
|
|
1106
1166
|
case cffoldCOMPTYPE_NONE:
|
|
1107
1167
|
self->d->decompress = (int (*)(void *, off_t)) &noned_decompress;
|
|
1108
|
-
self->d->state = noned_init(&self->d->sys, fh, fh,
|
|
1109
|
-
self->param[MSCABD_PARAM_DECOMPBUF]);
|
|
1168
|
+
self->d->state = noned_init(&self->d->sys, fh, fh, self->buf_size);
|
|
1110
1169
|
break;
|
|
1111
1170
|
case cffoldCOMPTYPE_MSZIP:
|
|
1112
1171
|
self->d->decompress = (int (*)(void *, off_t)) &mszipd_decompress;
|
|
1113
|
-
self->d->state = mszipd_init(&self->d->sys, fh, fh,
|
|
1114
|
-
|
|
1115
|
-
self->param[MSCABD_PARAM_FIXMSZIP]);
|
|
1172
|
+
self->d->state = mszipd_init(&self->d->sys, fh, fh, self->buf_size,
|
|
1173
|
+
self->fix_mszip);
|
|
1116
1174
|
break;
|
|
1117
1175
|
case cffoldCOMPTYPE_QUANTUM:
|
|
1118
1176
|
self->d->decompress = (int (*)(void *, off_t)) &qtmd_decompress;
|
|
1119
1177
|
self->d->state = qtmd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f,
|
|
1120
|
-
|
|
1178
|
+
self->buf_size);
|
|
1121
1179
|
break;
|
|
1122
1180
|
case cffoldCOMPTYPE_LZX:
|
|
1123
1181
|
self->d->decompress = (int (*)(void *, off_t)) &lzxd_decompress;
|
|
1124
1182
|
self->d->state = lzxd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f, 0,
|
|
1125
|
-
|
|
1183
|
+
self->buf_size, (off_t)0,0);
|
|
1126
1184
|
break;
|
|
1127
1185
|
default:
|
|
1128
1186
|
return self->error = MSPACK_ERR_DATAFORMAT;
|
|
@@ -1131,7 +1189,7 @@ static int cabd_init_decomp(struct mscab_decompressor_p *self, unsigned int ct)
|
|
|
1131
1189
|
}
|
|
1132
1190
|
|
|
1133
1191
|
static void cabd_free_decomp(struct mscab_decompressor_p *self) {
|
|
1134
|
-
if (!self || !self->d || !self->d->
|
|
1192
|
+
if (!self || !self->d || !self->d->state) return;
|
|
1135
1193
|
|
|
1136
1194
|
switch (self->d->comp_type & cffoldCOMPTYPE_MASK) {
|
|
1137
1195
|
case cffoldCOMPTYPE_NONE: noned_free((struct noned_state *) self->d->state); break;
|
|
@@ -1159,10 +1217,12 @@ static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) {
|
|
|
1159
1217
|
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file;
|
|
1160
1218
|
unsigned char *buf = (unsigned char *) buffer;
|
|
1161
1219
|
struct mspack_system *sys = self->system;
|
|
1162
|
-
int avail, todo, outlen, ignore_cksum;
|
|
1220
|
+
int avail, todo, outlen, ignore_cksum, ignore_blocksize;
|
|
1163
1221
|
|
|
1164
|
-
ignore_cksum = self->
|
|
1165
|
-
(
|
|
1222
|
+
ignore_cksum = self->salvage ||
|
|
1223
|
+
(self->fix_mszip &&
|
|
1224
|
+
((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP));
|
|
1225
|
+
ignore_blocksize = self->salvage;
|
|
1166
1226
|
|
|
1167
1227
|
todo = bytes;
|
|
1168
1228
|
while (todo > 0) {
|
|
@@ -1182,37 +1242,35 @@ static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) {
|
|
|
1182
1242
|
|
|
1183
1243
|
/* check if we're out of input blocks, advance block counter */
|
|
1184
1244
|
if (self->d->block++ >= self->d->folder->base.num_blocks) {
|
|
1185
|
-
|
|
1186
|
-
|
|
1245
|
+
if (!self->salvage) {
|
|
1246
|
+
self->read_error = MSPACK_ERR_DATAFORMAT;
|
|
1247
|
+
}
|
|
1248
|
+
else {
|
|
1249
|
+
D(("Ran out of CAB input blocks prematurely"))
|
|
1250
|
+
}
|
|
1251
|
+
break;
|
|
1187
1252
|
}
|
|
1188
1253
|
|
|
1189
1254
|
/* read a block */
|
|
1190
|
-
self->read_error = cabd_sys_read_block(sys, self->d, &outlen,
|
|
1255
|
+
self->read_error = cabd_sys_read_block(sys, self->d, &outlen,
|
|
1256
|
+
ignore_cksum, ignore_blocksize);
|
|
1191
1257
|
if (self->read_error) return -1;
|
|
1258
|
+
self->d->outlen += outlen;
|
|
1192
1259
|
|
|
1193
1260
|
/* special Quantum hack -- trailer byte to allow the decompressor
|
|
1194
1261
|
* to realign itself. CAB Quantum blocks, unlike LZX blocks, can have
|
|
1195
1262
|
* anything from 0 to 4 trailing null bytes. */
|
|
1196
1263
|
if ((self->d->comp_type & cffoldCOMPTYPE_MASK)==cffoldCOMPTYPE_QUANTUM) {
|
|
1197
|
-
|
|
1264
|
+
*self->d->i_end++ = 0xFF;
|
|
1198
1265
|
}
|
|
1199
1266
|
|
|
1200
1267
|
/* is this the last block? */
|
|
1201
1268
|
if (self->d->block >= self->d->folder->base.num_blocks) {
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
((self->d->block-1) * CAB_BLOCKMAX + outlen));
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
else {
|
|
1211
|
-
/* not the last block */
|
|
1212
|
-
if (outlen != CAB_BLOCKMAX) {
|
|
1213
|
-
self->system->message(self->d->infh,
|
|
1214
|
-
"WARNING; non-maximal data block");
|
|
1215
|
-
}
|
|
1269
|
+
if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) {
|
|
1270
|
+
/* special LZX hack -- on the last block, inform LZX of the
|
|
1271
|
+
* size of the output data stream. */
|
|
1272
|
+
lzxd_set_output_length((struct lzxd_stream *) self->d->state, self->d->outlen);
|
|
1273
|
+
}
|
|
1216
1274
|
}
|
|
1217
1275
|
} /* if (avail) */
|
|
1218
1276
|
} /* while (todo > 0) */
|
|
@@ -1235,12 +1293,13 @@ static int cabd_sys_write(struct mspack_file *file, void *buffer, int bytes) {
|
|
|
1235
1293
|
* one cab file, if it does then the fragments will be reassembled
|
|
1236
1294
|
*/
|
|
1237
1295
|
static int cabd_sys_read_block(struct mspack_system *sys,
|
|
1238
|
-
|
|
1239
|
-
|
|
1296
|
+
struct mscabd_decompress_state *d,
|
|
1297
|
+
int *out, int ignore_cksum,
|
|
1298
|
+
int ignore_blocksize)
|
|
1240
1299
|
{
|
|
1241
1300
|
unsigned char hdr[cfdata_SIZEOF];
|
|
1242
1301
|
unsigned int cksum;
|
|
1243
|
-
int len;
|
|
1302
|
+
int len, full_len;
|
|
1244
1303
|
|
|
1245
1304
|
/* reset the input block pointer and end of block pointer */
|
|
1246
1305
|
d->i_ptr = d->i_end = &d->input[0];
|
|
@@ -1253,24 +1312,27 @@ static int cabd_sys_read_block(struct mspack_system *sys,
|
|
|
1253
1312
|
|
|
1254
1313
|
/* skip any reserved block headers */
|
|
1255
1314
|
if (d->data->cab->block_resv &&
|
|
1256
|
-
|
|
1257
|
-
|
|
1315
|
+
sys->seek(d->infh, (off_t) d->data->cab->block_resv,
|
|
1316
|
+
MSPACK_SYS_SEEK_CUR))
|
|
1258
1317
|
{
|
|
1259
1318
|
return MSPACK_ERR_SEEK;
|
|
1260
1319
|
}
|
|
1261
1320
|
|
|
1262
1321
|
/* blocks must not be over CAB_INPUTMAX in size */
|
|
1263
1322
|
len = EndGetI16(&hdr[cfdata_CompressedSize]);
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1323
|
+
full_len = (d->i_end - d->i_ptr) + len; /* include cab-spanning blocks */
|
|
1324
|
+
if (full_len > CAB_INPUTMAX) {
|
|
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
|
+
}
|
|
1268
1330
|
}
|
|
1269
1331
|
|
|
1270
1332
|
/* blocks must not expand to more than CAB_BLOCKMAX */
|
|
1271
1333
|
if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) {
|
|
1272
1334
|
D(("block size > CAB_BLOCKMAX"))
|
|
1273
|
-
return MSPACK_ERR_DATAFORMAT;
|
|
1335
|
+
if (!ignore_blocksize) return MSPACK_ERR_DATAFORMAT;
|
|
1274
1336
|
}
|
|
1275
1337
|
|
|
1276
1338
|
/* read the block data */
|
|
@@ -1282,8 +1344,8 @@ static int cabd_sys_read_block(struct mspack_system *sys,
|
|
|
1282
1344
|
if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) {
|
|
1283
1345
|
unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0);
|
|
1284
1346
|
if (cabd_checksum(&hdr[4], 4, sum2) != cksum) {
|
|
1285
|
-
|
|
1286
|
-
|
|
1347
|
+
if (!ignore_cksum) return MSPACK_ERR_CHECKSUM;
|
|
1348
|
+
sys->message(d->infh, "WARNING; bad block checksum found");
|
|
1287
1349
|
}
|
|
1288
1350
|
}
|
|
1289
1351
|
|
|
@@ -1308,14 +1370,14 @@ static int cabd_sys_read_block(struct mspack_system *sys,
|
|
|
1308
1370
|
|
|
1309
1371
|
/* advance to next member in the cabinet set */
|
|
1310
1372
|
if (!(d->data = d->data->next)) {
|
|
1311
|
-
|
|
1373
|
+
sys->message(d->infh, "WARNING; ran out of cabinets in set. Are any missing?");
|
|
1312
1374
|
return MSPACK_ERR_DATAFORMAT;
|
|
1313
1375
|
}
|
|
1314
1376
|
|
|
1315
1377
|
/* open next cab file */
|
|
1316
1378
|
d->incab = d->data->cab;
|
|
1317
1379
|
if (!(d->infh = sys->open(sys, d->incab->base.filename,
|
|
1318
|
-
|
|
1380
|
+
MSPACK_SYS_OPEN_READ)))
|
|
1319
1381
|
{
|
|
1320
1382
|
return MSPACK_ERR_OPEN;
|
|
1321
1383
|
}
|
|
@@ -1331,7 +1393,7 @@ static int cabd_sys_read_block(struct mspack_system *sys,
|
|
|
1331
1393
|
}
|
|
1332
1394
|
|
|
1333
1395
|
static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
|
|
1334
|
-
|
|
1396
|
+
unsigned int cksum)
|
|
1335
1397
|
{
|
|
1336
1398
|
unsigned int len, ul = 0;
|
|
1337
1399
|
|
|
@@ -1340,8 +1402,8 @@ static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
|
|
|
1340
1402
|
}
|
|
1341
1403
|
|
|
1342
1404
|
switch (bytes & 3) {
|
|
1343
|
-
case 3: ul |= *data++ << 16;
|
|
1344
|
-
case 2: ul |= *data++ << 8;
|
|
1405
|
+
case 3: ul |= *data++ << 16; /*@fallthrough@*/
|
|
1406
|
+
case 2: ul |= *data++ << 8; /*@fallthrough@*/
|
|
1345
1407
|
case 1: ul |= *data;
|
|
1346
1408
|
}
|
|
1347
1409
|
cksum ^= ul;
|
|
@@ -1363,9 +1425,9 @@ struct noned_state {
|
|
|
1363
1425
|
};
|
|
1364
1426
|
|
|
1365
1427
|
static struct noned_state *noned_init(struct mspack_system *sys,
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1428
|
+
struct mspack_file *in,
|
|
1429
|
+
struct mspack_file *out,
|
|
1430
|
+
int bufsize)
|
|
1369
1431
|
{
|
|
1370
1432
|
struct noned_state *state = (struct noned_state *) sys->alloc(sys, sizeof(struct noned_state));
|
|
1371
1433
|
unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) bufsize);
|
|
@@ -1417,14 +1479,17 @@ static int cabd_param(struct mscab_decompressor *base, int param, int value) {
|
|
|
1417
1479
|
switch (param) {
|
|
1418
1480
|
case MSCABD_PARAM_SEARCHBUF:
|
|
1419
1481
|
if (value < 4) return MSPACK_ERR_ARGS;
|
|
1420
|
-
self->
|
|
1482
|
+
self->searchbuf_size = value;
|
|
1421
1483
|
break;
|
|
1422
1484
|
case MSCABD_PARAM_FIXMSZIP:
|
|
1423
|
-
self->
|
|
1485
|
+
self->fix_mszip = value;
|
|
1424
1486
|
break;
|
|
1425
1487
|
case MSCABD_PARAM_DECOMPBUF:
|
|
1426
1488
|
if (value < 4) return MSPACK_ERR_ARGS;
|
|
1427
|
-
self->
|
|
1489
|
+
self->buf_size = value;
|
|
1490
|
+
break;
|
|
1491
|
+
case MSCABD_PARAM_SALVAGE:
|
|
1492
|
+
self->salvage = value;
|
|
1428
1493
|
break;
|
|
1429
1494
|
default:
|
|
1430
1495
|
return MSPACK_ERR_ARGS;
|