summaryrefslogtreecommitdiff
path: root/rbutil/rbutilqt/mspack/cabd.c
diff options
context:
space:
mode:
Diffstat (limited to 'rbutil/rbutilqt/mspack/cabd.c')
-rw-r--r--rbutil/rbutilqt/mspack/cabd.c541
1 files changed, 302 insertions, 239 deletions
diff --git a/rbutil/rbutilqt/mspack/cabd.c b/rbutil/rbutilqt/mspack/cabd.c
index 6549d7b8cf..ae66769b24 100644
--- a/rbutil/rbutilqt/mspack/cabd.c
+++ b/rbutil/rbutilqt/mspack/cabd.c
@@ -1,5 +1,5 @@
1/* This file is part of libmspack. 1/* This file is part of libmspack.
2 * (C) 2003-2011 Stuart Caie. 2 * (C) 2003-2018 Stuart Caie.
3 * 3 *
4 * libmspack is free software; you can redistribute it and/or modify it under 4 * libmspack is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1 5 * the terms of the GNU Lesser General Public License (LGPL) version 2.1
@@ -23,7 +23,9 @@
23 23
24#include "system-mspack.h" 24#include "system-mspack.h"
25#include "cab.h" 25#include "cab.h"
26#include <assert.h> 26#include "mszip.h"
27#include "lzx.h"
28#include "qtm.h"
27 29
28/* Notes on compliance with cabinet specification: 30/* Notes on compliance with cabinet specification:
29 * 31 *
@@ -72,10 +74,9 @@ static void cabd_close(
72 struct mscab_decompressor *base, struct mscabd_cabinet *origcab); 74 struct mscab_decompressor *base, struct mscabd_cabinet *origcab);
73static int cabd_read_headers( 75static int cabd_read_headers(
74 struct mspack_system *sys, struct mspack_file *fh, 76 struct mspack_system *sys, struct mspack_file *fh,
75 struct mscabd_cabinet_p *cab, off_t offset, int quiet); 77 struct mscabd_cabinet_p *cab, off_t offset, int salvage, int quiet);
76static char *cabd_read_string( 78static char *cabd_read_string(
77 struct mspack_system *sys, struct mspack_file *fh, 79 struct mspack_system *sys, struct mspack_file *fh, int *error);
78 struct mscabd_cabinet_p *cab, int *error);
79 80
80static struct mscabd_cabinet *cabd_search( 81static struct mscabd_cabinet *cabd_search(
81 struct mscab_decompressor *base, const char *filename); 82 struct mscab_decompressor *base, const char *filename);
@@ -110,7 +111,7 @@ static int cabd_sys_write(
110 struct mspack_file *file, void *buffer, int bytes); 111 struct mspack_file *file, void *buffer, int bytes);
111static int cabd_sys_read_block( 112static int cabd_sys_read_block(
112 struct mspack_system *sys, struct mscabd_decompress_state *d, int *out, 113 struct mspack_system *sys, struct mscabd_decompress_state *d, int *out,
113 int ignore_cksum); 114 int ignore_cksum, int ignore_blocksize);
114static unsigned int cabd_checksum( 115static unsigned int cabd_checksum(
115 unsigned char *data, unsigned int bytes, unsigned int cksum); 116 unsigned char *data, unsigned int bytes, unsigned int cksum);
116static struct noned_state *noned_init( 117static struct noned_state *noned_init(
@@ -155,9 +156,10 @@ struct mscab_decompressor *
155 self->d = NULL; 156 self->d = NULL;
156 self->error = MSPACK_ERR_OK; 157 self->error = MSPACK_ERR_OK;
157 158
158 self->param[MSCABD_PARAM_SEARCHBUF] = 32768; 159 self->searchbuf_size = 32768;
159 self->param[MSCABD_PARAM_FIXMSZIP] = 0; 160 self->fix_mszip = 0;
160 self->param[MSCABD_PARAM_DECOMPBUF] = 4096; 161 self->buf_size = 4096;
162 self->salvage = 0;
161 } 163 }
162 return (struct mscab_decompressor *) self; 164 return (struct mscab_decompressor *) self;
163} 165}
@@ -171,9 +173,9 @@ void mspack_destroy_cab_decompressor(struct mscab_decompressor *base) {
171 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base; 173 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
172 if (self) { 174 if (self) {
173 struct mspack_system *sys = self->system; 175 struct mspack_system *sys = self->system;
174 cabd_free_decomp(self);
175 if (self->d) { 176 if (self->d) {
176 if (self->d->infh) sys->close(self->d->infh); 177 if (self->d->infh) sys->close(self->d->infh);
178 cabd_free_decomp(self);
177 sys->free(self->d); 179 sys->free(self->d);
178 } 180 }
179 sys->free(self); 181 sys->free(self);
@@ -187,7 +189,7 @@ void mspack_destroy_cab_decompressor(struct mscab_decompressor *base) {
187 * opens a file and tries to read it as a cabinet file 189 * opens a file and tries to read it as a cabinet file
188 */ 190 */
189static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base, 191static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
190 const char *filename) 192 const char *filename)
191{ 193{
192 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base; 194 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
193 struct mscabd_cabinet_p *cab = NULL; 195 struct mscabd_cabinet_p *cab = NULL;
@@ -201,10 +203,10 @@ static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
201 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) { 203 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
202 if ((cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) { 204 if ((cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
203 cab->base.filename = filename; 205 cab->base.filename = filename;
204 error = cabd_read_headers(sys, fh, cab, (off_t) 0, 0); 206 error = cabd_read_headers(sys, fh, cab, (off_t) 0, self->salvage, 0);
205 if (error) { 207 if (error) {
206 cabd_close(base, (struct mscabd_cabinet *) cab); 208 cabd_close(base, (struct mscabd_cabinet *) cab);
207 cab = NULL; 209 cab = NULL;
208 } 210 }
209 self->error = error; 211 self->error = error;
210 } 212 }
@@ -225,7 +227,7 @@ static struct mscabd_cabinet *cabd_open(struct mscab_decompressor *base,
225 * frees all memory associated with a given mscabd_cabinet. 227 * frees all memory associated with a given mscabd_cabinet.
226 */ 228 */
227static void cabd_close(struct mscab_decompressor *base, 229static void cabd_close(struct mscab_decompressor *base,
228 struct mscabd_cabinet *origcab) 230 struct mscabd_cabinet *origcab)
229{ 231{
230 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base; 232 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
231 struct mscabd_folder_data *dat, *ndat; 233 struct mscabd_folder_data *dat, *ndat;
@@ -253,16 +255,16 @@ static void cabd_close(struct mscab_decompressor *base,
253 255
254 /* free folder decompression state if it has been decompressed */ 256 /* free folder decompression state if it has been decompressed */
255 if (self->d && (self->d->folder == (struct mscabd_folder_p *) fol)) { 257 if (self->d && (self->d->folder == (struct mscabd_folder_p *) fol)) {
256 if (self->d->infh) sys->close(self->d->infh); 258 if (self->d->infh) sys->close(self->d->infh);
257 cabd_free_decomp(self); 259 cabd_free_decomp(self);
258 sys->free(self->d); 260 sys->free(self->d);
259 self->d = NULL; 261 self->d = NULL;
260 } 262 }
261 263
262 /* free folder data segments */ 264 /* free folder data segments */
263 for (dat = ((struct mscabd_folder_p *)fol)->data.next; dat; dat = ndat) { 265 for (dat = ((struct mscabd_folder_p *)fol)->data.next; dat; dat = ndat) {
264 ndat = dat->next; 266 ndat = dat->next;
265 sys->free(dat); 267 sys->free(dat);
266 } 268 }
267 sys->free(fol); 269 sys->free(fol);
268 } 270 }
@@ -304,11 +306,11 @@ static void cabd_close(struct mscab_decompressor *base,
304 * for folders and files as necessary 306 * for folders and files as necessary
305 */ 307 */
306static int cabd_read_headers(struct mspack_system *sys, 308static int cabd_read_headers(struct mspack_system *sys,
307 struct mspack_file *fh, 309 struct mspack_file *fh,
308 struct mscabd_cabinet_p *cab, 310 struct mscabd_cabinet_p *cab,
309 off_t offset, int quiet) 311 off_t offset, int salvage, int quiet)
310{ 312{
311 int num_folders, num_files, folder_resv, i, x; 313 int num_folders, num_files, folder_resv, i, x, err, fidx;
312 struct mscabd_folder_p *fol, *linkfol = NULL; 314 struct mscabd_folder_p *fol, *linkfol = NULL;
313 struct mscabd_file *file, *linkfile = NULL; 315 struct mscabd_file *file, *linkfile = NULL;
314 unsigned char buf[64]; 316 unsigned char buf[64];
@@ -364,6 +366,7 @@ static int cabd_read_headers(struct mspack_system *sys,
364 366
365 /* read the reserved-sizes part of header, if present */ 367 /* read the reserved-sizes part of header, if present */
366 cab->base.flags = EndGetI16(&buf[cfhead_Flags]); 368 cab->base.flags = EndGetI16(&buf[cfhead_Flags]);
369
367 if (cab->base.flags & cfheadRESERVE_PRESENT) { 370 if (cab->base.flags & cfheadRESERVE_PRESENT) {
368 if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) { 371 if (sys->read(fh, &buf[0], cfheadext_SIZEOF) != cfheadext_SIZEOF) {
369 return MSPACK_ERR_READ; 372 return MSPACK_ERR_READ;
@@ -379,7 +382,7 @@ static int cabd_read_headers(struct mspack_system *sys,
379 /* skip the reserved header */ 382 /* skip the reserved header */
380 if (cab->base.header_resv) { 383 if (cab->base.header_resv) {
381 if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) { 384 if (sys->seek(fh, (off_t) cab->base.header_resv, MSPACK_SYS_SEEK_CUR)) {
382 return MSPACK_ERR_SEEK; 385 return MSPACK_ERR_SEEK;
383 } 386 }
384 } 387 }
385 } 388 }
@@ -391,14 +394,18 @@ static int cabd_read_headers(struct mspack_system *sys,
391 394
392 /* read name and info of preceeding cabinet in set, if present */ 395 /* read name and info of preceeding cabinet in set, if present */
393 if (cab->base.flags & cfheadPREV_CABINET) { 396 if (cab->base.flags & cfheadPREV_CABINET) {
394 cab->base.prevname = cabd_read_string(sys, fh, cab, &x); if (x) return x; 397 cab->base.prevname = cabd_read_string(sys, fh, &err);
395 cab->base.previnfo = cabd_read_string(sys, fh, cab, &x); if (x) return x; 398 if (err) return err;
399 cab->base.previnfo = cabd_read_string(sys, fh, &err);
400 if (err) return err;
396 } 401 }
397 402
398 /* read name and info of next cabinet in set, if present */ 403 /* read name and info of next cabinet in set, if present */
399 if (cab->base.flags & cfheadNEXT_CABINET) { 404 if (cab->base.flags & cfheadNEXT_CABINET) {
400 cab->base.nextname = cabd_read_string(sys, fh, cab, &x); if (x) return x; 405 cab->base.nextname = cabd_read_string(sys, fh, &err);
401 cab->base.nextinfo = cabd_read_string(sys, fh, cab, &x); if (x) return x; 406 if (err) return err;
407 cab->base.nextinfo = cabd_read_string(sys, fh, &err);
408 if (err) return err;
402 } 409 }
403 410
404 /* read folders */ 411 /* read folders */
@@ -408,7 +415,7 @@ static int cabd_read_headers(struct mspack_system *sys,
408 } 415 }
409 if (folder_resv) { 416 if (folder_resv) {
410 if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) { 417 if (sys->seek(fh, (off_t) folder_resv, MSPACK_SYS_SEEK_CUR)) {
411 return MSPACK_ERR_SEEK; 418 return MSPACK_ERR_SEEK;
412 } 419 }
413 } 420 }
414 421
@@ -447,45 +454,44 @@ static int cabd_read_headers(struct mspack_system *sys,
447 file->offset = EndGetI32(&buf[cffile_FolderOffset]); 454 file->offset = EndGetI32(&buf[cffile_FolderOffset]);
448 455
449 /* set folder pointer */ 456 /* set folder pointer */
450 x = EndGetI16(&buf[cffile_FolderIndex]); 457 fidx = EndGetI16(&buf[cffile_FolderIndex]);
451 if (x < cffileCONTINUED_FROM_PREV) { 458 if (fidx < cffileCONTINUED_FROM_PREV) {
452 /* normal folder index; count up to the correct folder. the folder 459 /* normal folder index; count up to the correct folder */
453 * pointer will be NULL if folder index is invalid */ 460 if (fidx < num_folders) {
454 struct mscabd_folder *ifol = cab->base.folders; 461 struct mscabd_folder *ifol = cab->base.folders;
455 while (x--) if (ifol) ifol = ifol->next; 462 while (fidx--) if (ifol) ifol = ifol->next;
456 file->folder = ifol; 463 file->folder = ifol;
457 464 }
458 if (!ifol) { 465 else {
459 sys->free(file); 466 D(("invalid folder index"))
460 D(("invalid folder index")) 467 file->folder = NULL;
461 return MSPACK_ERR_DATAFORMAT;
462 } 468 }
463 } 469 }
464 else { 470 else {
465 /* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or 471 /* either CONTINUED_TO_NEXT, CONTINUED_FROM_PREV or
466 * CONTINUED_PREV_AND_NEXT */ 472 * CONTINUED_PREV_AND_NEXT */
467 if ((x == cffileCONTINUED_TO_NEXT) || 473 if ((fidx == cffileCONTINUED_TO_NEXT) ||
468 (x == cffileCONTINUED_PREV_AND_NEXT)) 474 (fidx == cffileCONTINUED_PREV_AND_NEXT))
469 { 475 {
470 /* get last folder */ 476 /* get last folder */
471 struct mscabd_folder *ifol = cab->base.folders; 477 struct mscabd_folder *ifol = cab->base.folders;
472 while (ifol->next) ifol = ifol->next; 478 while (ifol->next) ifol = ifol->next;
473 file->folder = ifol; 479 file->folder = ifol;
474 480
475 /* set "merge next" pointer */ 481 /* set "merge next" pointer */
476 fol = (struct mscabd_folder_p *) ifol; 482 fol = (struct mscabd_folder_p *) ifol;
477 if (!fol->merge_next) fol->merge_next = file; 483 if (!fol->merge_next) fol->merge_next = file;
478 } 484 }
479 485
480 if ((x == cffileCONTINUED_FROM_PREV) || 486 if ((fidx == cffileCONTINUED_FROM_PREV) ||
481 (x == cffileCONTINUED_PREV_AND_NEXT)) 487 (fidx == cffileCONTINUED_PREV_AND_NEXT))
482 { 488 {
483 /* get first folder */ 489 /* get first folder */
484 file->folder = cab->base.folders; 490 file->folder = cab->base.folders;
485 491
486 /* set "merge prev" pointer */ 492 /* set "merge prev" pointer */
487 fol = (struct mscabd_folder_p *) file->folder; 493 fol = (struct mscabd_folder_p *) file->folder;
488 if (!fol->merge_prev) fol->merge_prev = file; 494 if (!fol->merge_prev) fol->merge_prev = file;
489 } 495 }
490 } 496 }
491 497
@@ -502,10 +508,14 @@ static int cabd_read_headers(struct mspack_system *sys,
502 file->date_y = (x >> 9) + 1980; 508 file->date_y = (x >> 9) + 1980;
503 509
504 /* get filename */ 510 /* get filename */
505 file->filename = cabd_read_string(sys, fh, cab, &x); 511 file->filename = cabd_read_string(sys, fh, &err);
506 if (x) { 512
513 /* if folder index or filename are bad, either skip it or fail */
514 if (err || !file->folder) {
515 sys->free(file->filename);
507 sys->free(file); 516 sys->free(file);
508 return x; 517 if (salvage) continue;
518 return err ? err : MSPACK_ERR_DATAFORMAT;
509 } 519 }
510 520
511 /* link file entry into file list */ 521 /* link file entry into file list */
@@ -514,23 +524,34 @@ static int cabd_read_headers(struct mspack_system *sys,
514 linkfile = file; 524 linkfile = file;
515 } 525 }
516 526
527 if (cab->base.files == NULL) {
528 /* We never actually added any files to the file list. Something went wrong.
529 * The file header may have been invalid */
530 D(("No files found, even though header claimed to have %d files", num_files))
531 return MSPACK_ERR_DATAFORMAT;
532 }
533
517 return MSPACK_ERR_OK; 534 return MSPACK_ERR_OK;
518} 535}
519 536
520static char *cabd_read_string(struct mspack_system *sys, 537static char *cabd_read_string(struct mspack_system *sys,
521 struct mspack_file *fh, 538 struct mspack_file *fh, int *error)
522 struct mscabd_cabinet_p *cab, int *error)
523{ 539{
524 off_t base = sys->tell(fh); 540 off_t base = sys->tell(fh);
525 char buf[256], *str; 541 char buf[256], *str;
526 unsigned int len, i, ok; 542 int len, i, ok;
527 (void)cab;
528 543
529 /* read up to 256 bytes */ 544 /* read up to 256 bytes */
530 len = sys->read(fh, &buf[0], 256); 545 if ((len = sys->read(fh, &buf[0], 256)) <= 0) {
546 *error = MSPACK_ERR_READ;
547 return NULL;
548 }
531 549
532 /* search for a null terminator in the buffer */ 550 /* search for a null terminator in the buffer */
533 for (i = 0, ok = 0; i < len; i++) if (!buf[i]) { ok = 1; break; } 551 for (i = 0, ok = 0; i < len; i++) if (!buf[i]) { ok = 1; break; }
552 /* reject empty strings */
553 if (i == 0) ok = 0;
554
534 if (!ok) { 555 if (!ok) {
535 *error = MSPACK_ERR_DATAFORMAT; 556 *error = MSPACK_ERR_DATAFORMAT;
536 return NULL; 557 return NULL;
@@ -566,7 +587,7 @@ static char *cabd_read_string(struct mspack_system *sys,
566 * break out of the loop and be sure that all resources are freed 587 * break out of the loop and be sure that all resources are freed
567 */ 588 */
568static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base, 589static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
569 const char *filename) 590 const char *filename)
570{ 591{
571 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base; 592 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
572 struct mscabd_cabinet_p *cab = NULL; 593 struct mscabd_cabinet_p *cab = NULL;
@@ -579,7 +600,7 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
579 sys = self->system; 600 sys = self->system;
580 601
581 /* allocate a search buffer */ 602 /* allocate a search buffer */
582 search_buf = (unsigned char *) sys->alloc(sys, (size_t) self->param[MSCABD_PARAM_SEARCHBUF]); 603 search_buf = (unsigned char *) sys->alloc(sys, (size_t) self->searchbuf_size);
583 if (!search_buf) { 604 if (!search_buf) {
584 self->error = MSPACK_ERR_NOMEMORY; 605 self->error = MSPACK_ERR_NOMEMORY;
585 return NULL; 606 return NULL;
@@ -589,21 +610,21 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
589 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) { 610 if ((fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ))) {
590 if (!(self->error = mspack_sys_filelen(sys, fh, &filelen))) { 611 if (!(self->error = mspack_sys_filelen(sys, fh, &filelen))) {
591 self->error = cabd_find(self, search_buf, fh, filename, 612 self->error = cabd_find(self, search_buf, fh, filename,
592 filelen, &firstlen, &cab); 613 filelen, &firstlen, &cab);
593 } 614 }
594 615
595 /* truncated / extraneous data warning: */ 616 /* truncated / extraneous data warning: */
596 if (firstlen && (firstlen != filelen) && 617 if (firstlen && (firstlen != filelen) &&
597 (!cab || (cab->base.base_offset == 0))) 618 (!cab || (cab->base.base_offset == 0)))
598 { 619 {
599 if (firstlen < filelen) { 620 if (firstlen < filelen) {
600 sys->message(fh, "WARNING; possible %" LD 621 sys->message(fh, "WARNING; possible %" LD
601 " extra bytes at end of file.", 622 " extra bytes at end of file.",
602 filelen - firstlen); 623 filelen - firstlen);
603 } 624 }
604 else { 625 else {
605 sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.", 626 sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.",
606 firstlen - filelen); 627 firstlen - filelen);
607 } 628 }
608 } 629 }
609 630
@@ -620,8 +641,8 @@ static struct mscabd_cabinet *cabd_search(struct mscab_decompressor *base,
620} 641}
621 642
622static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf, 643static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
623 struct mspack_file *fh, const char *filename, off_t flen, 644 struct mspack_file *fh, const char *filename, off_t flen,
624 off_t *firstlen, struct mscabd_cabinet_p **firstcab) 645 off_t *firstlen, struct mscabd_cabinet_p **firstcab)
625{ 646{
626 struct mscabd_cabinet_p *cab, *link = NULL; 647 struct mscabd_cabinet_p *cab, *link = NULL;
627 off_t caboff, offset, length; 648 off_t caboff, offset, length;
@@ -630,7 +651,7 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
630 unsigned int cablen_u32 = 0, foffset_u32 = 0; 651 unsigned int cablen_u32 = 0, foffset_u32 = 0;
631 int false_cabs = 0; 652 int false_cabs = 0;
632 653
633#ifndef LARGEFILE_SUPPORT 654#if !LARGEFILE_SUPPORT
634 /* detect 32-bit off_t overflow */ 655 /* detect 32-bit off_t overflow */
635 if (flen < 0) { 656 if (flen < 0) {
636 sys->message(fh, largefile_msg); 657 sys->message(fh, largefile_msg);
@@ -643,8 +664,8 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
643 /* search length is either the full length of the search buffer, or the 664 /* search length is either the full length of the search buffer, or the
644 * amount of data remaining to the end of the file, whichever is less. */ 665 * amount of data remaining to the end of the file, whichever is less. */
645 length = flen - offset; 666 length = flen - offset;
646 if (length > self->param[MSCABD_PARAM_SEARCHBUF]) { 667 if (length > self->searchbuf_size) {
647 length = self->param[MSCABD_PARAM_SEARCHBUF]; 668 length = self->searchbuf_size;
648 } 669 }
649 670
650 /* fill the search buffer with data from disk */ 671 /* fill the search buffer with data from disk */
@@ -654,22 +675,21 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
654 675
655 /* FAQ avoidance strategy */ 676 /* FAQ avoidance strategy */
656 if ((offset == 0) && (EndGetI32(&buf[0]) == 0x28635349)) { 677 if ((offset == 0) && (EndGetI32(&buf[0]) == 0x28635349)) {
657 sys->message(fh, "WARNING; found InstallShield header. " 678 sys->message(fh, "WARNING; found InstallShield header. Use unshield "
658 "This is probably an InstallShield file. " 679 "(https://github.com/twogood/unshield) to unpack this file");
659 "Use UNSHIELD from www.synce.org to unpack it.");
660 } 680 }
661 681
662 /* read through the entire buffer. */ 682 /* read through the entire buffer. */
663 for (p = &buf[0], pend = &buf[length]; p < pend; ) { 683 for (p = &buf[0], pend = &buf[length]; p < pend; ) {
664 switch (state) { 684 switch (state) {
665 /* starting state */ 685 /* starting state */
666 case 0: 686 case 0:
667 /* we spend most of our time in this while loop, looking for 687 /* we spend most of our time in this while loop, looking for
668 * a leading 'M' of the 'MSCF' signature */ 688 * a leading 'M' of the 'MSCF' signature */
669 while (p < pend && *p != 0x4D) p++; 689 while (p < pend && *p != 0x4D) p++;
670 /* if we found tht 'M', advance state */ 690 /* if we found tht 'M', advance state */
671 if (p++ < pend) state = 1; 691 if (p++ < pend) state = 1;
672 break; 692 break;
673 693
674 /* verify that the next 3 bytes are 'S', 'C' and 'F' */ 694 /* verify that the next 3 bytes are 'S', 'C' and 'F' */
675 case 1: state = (*p++ == 0x53) ? 2 : 0; break; 695 case 1: state = (*p++ == 0x53) ? 2 : 0; break;
@@ -691,70 +711,71 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
691 case 17: foffset_u32 |= *p++ << 8; state++; break; 711 case 17: foffset_u32 |= *p++ << 8; state++; break;
692 case 18: foffset_u32 |= *p++ << 16; state++; break; 712 case 18: foffset_u32 |= *p++ << 16; state++; break;
693 case 19: foffset_u32 |= *p++ << 24; 713 case 19: foffset_u32 |= *p++ << 24;
694 /* now we have recieved 20 bytes of potential cab header. work out 714 /* now we have recieved 20 bytes of potential cab header. work out
695 * the offset in the file of this potential cabinet */ 715 * the offset in the file of this potential cabinet */
696 caboff = offset + (p - &buf[0]) - 20; 716 caboff = offset + (p - &buf[0]) - 20;
697 717
698 /* should reading cabinet fail, restart search just after 'MSCF' */ 718 /* should reading cabinet fail, restart search just after 'MSCF' */
699 offset = caboff + 4; 719 offset = caboff + 4;
700 720
701 /* capture the "length of cabinet" field if there is a cabinet at 721 /* capture the "length of cabinet" field if there is a cabinet at
702 * offset 0 in the file, regardless of whether the cabinet can be 722 * offset 0 in the file, regardless of whether the cabinet can be
703 * read correctly or not */ 723 * read correctly or not */
704 if (caboff == 0) *firstlen = (off_t) cablen_u32; 724 if (caboff == 0) *firstlen = (off_t) cablen_u32;
705 725
706 /* check that the files offset is less than the alleged length of 726 /* check that the files offset is less than the alleged length of
707 * the cabinet, and that the offset + the alleged length are 727 * the cabinet, and that the offset + the alleged length are
708 * 'roughly' within the end of overall file length */ 728 * 'roughly' within the end of overall file length. In salvage
709 if ((foffset_u32 < cablen_u32) && 729 * mode, don't check the alleged length, allow it to be garbage */
710 ((caboff + (off_t) foffset_u32) < (flen + 32)) && 730 if ((foffset_u32 < cablen_u32) &&
711 ((caboff + (off_t) cablen_u32) < (flen + 32)) ) 731 ((caboff + (off_t) foffset_u32) < (flen + 32)) &&
712 { 732 (((caboff + (off_t) cablen_u32) < (flen + 32)) || self->salvage))
713 /* likely cabinet found -- try reading it */ 733 {
714 if (!(cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) { 734 /* likely cabinet found -- try reading it */
715 return MSPACK_ERR_NOMEMORY; 735 if (!(cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
716 } 736 return MSPACK_ERR_NOMEMORY;
717 cab->base.filename = filename; 737 }
718 if (cabd_read_headers(sys, fh, cab, caboff, 1)) { 738 cab->base.filename = filename;
719 /* destroy the failed cabinet */ 739 if (cabd_read_headers(sys, fh, cab, caboff, self->salvage, 1)) {
720 cabd_close((struct mscab_decompressor *) self, 740 /* destroy the failed cabinet */
721 (struct mscabd_cabinet *) cab); 741 cabd_close((struct mscab_decompressor *) self,
722 false_cabs++; 742 (struct mscabd_cabinet *) cab);
723 } 743 false_cabs++;
724 else { 744 }
725 /* cabinet read correctly! */ 745 else {
726 746 /* cabinet read correctly! */
727 /* link the cab into the list */ 747
728 if (!link) *firstcab = cab; 748 /* link the cab into the list */
729 else link->base.next = (struct mscabd_cabinet *) cab; 749 if (!link) *firstcab = cab;
730 link = cab; 750 else link->base.next = (struct mscabd_cabinet *) cab;
731 751 link = cab;
732 /* cause the search to restart after this cab's data. */ 752
733 offset = caboff + (off_t) cablen_u32; 753 /* cause the search to restart after this cab's data. */
734 754 offset = caboff + (off_t) cablen_u32;
735#ifndef LARGEFILE_SUPPORT 755
736 /* detect 32-bit off_t overflow */ 756#if !LARGEFILE_SUPPORT
737 if (offset < caboff) { 757 /* detect 32-bit off_t overflow */
738 sys->message(fh, largefile_msg); 758 if (offset < caboff) {
739 return MSPACK_ERR_OK; 759 sys->message(fh, largefile_msg);
740 } 760 return MSPACK_ERR_OK;
741#endif 761 }
742 } 762#endif
743 } 763 }
744 764 }
745 /* restart search */ 765
746 if (offset >= flen) return MSPACK_ERR_OK; 766 /* restart search */
747 if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) { 767 if (offset >= flen) return MSPACK_ERR_OK;
748 return MSPACK_ERR_SEEK; 768 if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
749 } 769 return MSPACK_ERR_SEEK;
750 length = 0; 770 }
751 p = pend; 771 length = 0;
752 state = 0; 772 p = pend;
753 break; 773 state = 0;
774 break;
754 775
755 /* for bytes 4-7 and 12-15, just advance state/pointer */ 776 /* for bytes 4-7 and 12-15, just advance state/pointer */
756 default: 777 default:
757 p++, state++; 778 p++, state++;
758 } /* switch(state) */ 779 } /* switch(state) */
759 } /* for (... p < pend ...) */ 780 } /* for (... p < pend ...) */
760 } /* for (... offset < length ...) */ 781 } /* for (... offset < length ...) */
@@ -765,7 +786,7 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
765 786
766 return MSPACK_ERR_OK; 787 return MSPACK_ERR_OK;
767} 788}
768 789
769/*************************************** 790/***************************************
770 * CABD_MERGE, CABD_PREPEND, CABD_APPEND 791 * CABD_MERGE, CABD_PREPEND, CABD_APPEND
771 *************************************** 792 ***************************************
@@ -775,22 +796,22 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
775 * merged folder's data parts list. 796 * merged folder's data parts list.
776 */ 797 */
777static int cabd_prepend(struct mscab_decompressor *base, 798static int cabd_prepend(struct mscab_decompressor *base,
778 struct mscabd_cabinet *cab, 799 struct mscabd_cabinet *cab,
779 struct mscabd_cabinet *prevcab) 800 struct mscabd_cabinet *prevcab)
780{ 801{
781 return cabd_merge(base, prevcab, cab); 802 return cabd_merge(base, prevcab, cab);
782} 803}
783 804
784static int cabd_append(struct mscab_decompressor *base, 805static int cabd_append(struct mscab_decompressor *base,
785 struct mscabd_cabinet *cab, 806 struct mscabd_cabinet *cab,
786 struct mscabd_cabinet *nextcab) 807 struct mscabd_cabinet *nextcab)
787{ 808{
788 return cabd_merge(base, cab, nextcab); 809 return cabd_merge(base, cab, nextcab);
789} 810}
790 811
791static int cabd_merge(struct mscab_decompressor *base, 812static int cabd_merge(struct mscab_decompressor *base,
792 struct mscabd_cabinet *lcab, 813 struct mscabd_cabinet *lcab,
793 struct mscabd_cabinet *rcab) 814 struct mscabd_cabinet *rcab)
794{ 815{
795 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base; 816 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) base;
796 struct mscabd_folder_data *data, *ndata; 817 struct mscabd_folder_data *data, *ndata;
@@ -880,7 +901,7 @@ static int cabd_merge(struct mscab_decompressor *base,
880 * instead */ 901 * instead */
881 lfol->base.num_blocks += rfol->base.num_blocks - 1; 902 lfol->base.num_blocks += rfol->base.num_blocks - 1;
882 if ((rfol->merge_next == NULL) || 903 if ((rfol->merge_next == NULL) ||
883 (rfol->merge_next->folder != (struct mscabd_folder *) rfol)) 904 (rfol->merge_next->folder != (struct mscabd_folder *) rfol))
884 { 905 {
885 lfol->merge_next = rfol->merge_next; 906 lfol->merge_next = rfol->merge_next;
886 } 907 }
@@ -903,9 +924,9 @@ static int cabd_merge(struct mscab_decompressor *base,
903 rfi = fi->next; 924 rfi = fi->next;
904 /* if file's folder matches the merge folder, unlink and free it */ 925 /* if file's folder matches the merge folder, unlink and free it */
905 if (fi->folder == (struct mscabd_folder *) rfol) { 926 if (fi->folder == (struct mscabd_folder *) rfol) {
906 if (lfi) lfi->next = rfi; else lcab->files = rfi; 927 if (lfi) lfi->next = rfi; else lcab->files = rfi;
907 sys->free(fi->filename); 928 sys->free(fi->filename);
908 sys->free(fi); 929 sys->free(fi);
909 } 930 }
910 else lfi = fi; 931 else lfi = fi;
911 } 932 }
@@ -940,6 +961,12 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
940 return 0; 961 return 0;
941 } 962 }
942 963
964 /* check there are not too many data blocks after merging */
965 if ((lfol->base.num_blocks + rfol->base.num_blocks) > CAB_FOLDERMAX) {
966 D(("folder merge: too many data blocks in merged folders"))
967 return 0;
968 }
969
943 if (!(lfi = lfol->merge_next) || !(rfi = rfol->merge_prev)) { 970 if (!(lfi = lfol->merge_next) || !(rfi = rfol->merge_prev)) {
944 D(("folder merge: one cabinet has no files to merge")) 971 D(("folder merge: one cabinet has no files to merge"))
945 return 0; 972 return 0;
@@ -950,10 +977,10 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
950 * should be identical in number and order. to verify this, check the 977 * should be identical in number and order. to verify this, check the
951 * offset and length of each file. */ 978 * offset and length of each file. */
952 for (l=lfi, r=rfi; l; l=l->next, r=r->next) { 979 for (l=lfi, r=rfi; l; l=l->next, r=r->next) {
953 if (!r || (l->offset != r->offset) || (l->length != r->length)) { 980 if (!r || (l->offset != r->offset) || (l->length != r->length)) {
954 matching = 0; 981 matching = 0;
955 break; 982 break;
956 } 983 }
957 } 984 }
958 985
959 if (matching) return 1; 986 if (matching) return 1;
@@ -963,9 +990,9 @@ static int cabd_can_merge_folders(struct mspack_system *sys,
963 * the merge with a warning about missing files. */ 990 * the merge with a warning about missing files. */
964 matching = 0; 991 matching = 0;
965 for (l = lfi; l; l = l->next) { 992 for (l = lfi; l; l = l->next) {
966 for (r = rfi; r; r = r->next) { 993 for (r = rfi; r; r = r->next) {
967 if (l->offset == r->offset && l->length == r->length) break; 994 if (l->offset == r->offset && l->length == r->length) break;
968 } 995 }
969 if (r) matching = 1; else sys->message(NULL, 996 if (r) matching = 1; else sys->message(NULL,
970 "WARNING; merged file %s not listed in both cabinets", l->filename); 997 "WARNING; merged file %s not listed in both cabinets", l->filename);
971 } 998 }
@@ -985,6 +1012,7 @@ static int cabd_extract(struct mscab_decompressor *base,
985 struct mscabd_folder_p *fol; 1012 struct mscabd_folder_p *fol;
986 struct mspack_system *sys; 1013 struct mspack_system *sys;
987 struct mspack_file *fh; 1014 struct mspack_file *fh;
1015 off_t filelen;
988 1016
989 if (!self) return MSPACK_ERR_ARGS; 1017 if (!self) return MSPACK_ERR_ARGS;
990 if (!file) return self->error = MSPACK_ERR_ARGS; 1018 if (!file) return self->error = MSPACK_ERR_ARGS;
@@ -992,15 +1020,43 @@ static int cabd_extract(struct mscab_decompressor *base,
992 sys = self->system; 1020 sys = self->system;
993 fol = (struct mscabd_folder_p *) file->folder; 1021 fol = (struct mscabd_folder_p *) file->folder;
994 1022
995 /* check if file can be extracted */ 1023 /* if offset is beyond 2GB, nothing can be extracted */
996 if ((!fol) || (fol->merge_prev) || 1024 if (file->offset > CAB_LENGTHMAX) {
997 (((file->offset + file->length) / CAB_BLOCKMAX) > fol->base.num_blocks))
998 {
999 sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
1000 "cabinet set is incomplete.", file->filename);
1001 return self->error = MSPACK_ERR_DATAFORMAT; 1025 return self->error = MSPACK_ERR_DATAFORMAT;
1002 } 1026 }
1003 1027
1028 /* if file claims to go beyond 2GB either error out,
1029 * or in salvage mode reduce file length so it fits 2GB limit
1030 */
1031 filelen = file->length;
1032 if (filelen > CAB_LENGTHMAX || (file->offset + filelen) > CAB_LENGTHMAX) {
1033 if (self->salvage) {
1034 filelen = CAB_LENGTHMAX - file->offset;
1035 }
1036 else {
1037 return self->error = MSPACK_ERR_DATAFORMAT;
1038 }
1039 }
1040
1041 /* extraction impossible if no folder, or folder needs predecessor */
1042 if (!fol || fol->merge_prev) {
1043 sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
1044 "cabinet set is incomplete", file->filename);
1045 return self->error = MSPACK_ERR_DECRUNCH;
1046 }
1047
1048 /* if file goes beyond what can be decoded, given an error.
1049 * In salvage mode, don't assume block sizes, just try decoding
1050 */
1051 if (!self->salvage) {
1052 off_t maxlen = fol->base.num_blocks * CAB_BLOCKMAX;
1053 if ((file->offset + filelen) > maxlen) {
1054 sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
1055 "cabinet set is incomplete", file->filename);
1056 return self->error = MSPACK_ERR_DECRUNCH;
1057 }
1058 }
1059
1004 /* allocate generic decompression state */ 1060 /* allocate generic decompression state */
1005 if (!self->d) { 1061 if (!self->d) {
1006 self->d = (struct mscabd_decompress_state *) sys->alloc(sys, sizeof(struct mscabd_decompress_state)); 1062 self->d = (struct mscabd_decompress_state *) sys->alloc(sys, sizeof(struct mscabd_decompress_state));
@@ -1016,14 +1072,19 @@ static int cabd_extract(struct mscab_decompressor *base,
1016 } 1072 }
1017 1073
1018 /* do we need to change folder or reset the current folder? */ 1074 /* do we need to change folder or reset the current folder? */
1019 if ((self->d->folder != fol) || (self->d->offset > file->offset)) { 1075 if ((self->d->folder != fol) || (self->d->offset > file->offset) ||
1076 !self->d->state)
1077 {
1078 /* free any existing decompressor */
1079 cabd_free_decomp(self);
1080
1020 /* do we need to open a new cab file? */ 1081 /* do we need to open a new cab file? */
1021 if (!self->d->infh || (fol->data.cab != self->d->incab)) { 1082 if (!self->d->infh || (fol->data.cab != self->d->incab)) {
1022 /* close previous file handle if from a different cab */ 1083 /* close previous file handle if from a different cab */
1023 if (self->d->infh) sys->close(self->d->infh); 1084 if (self->d->infh) sys->close(self->d->infh);
1024 self->d->incab = fol->data.cab; 1085 self->d->incab = fol->data.cab;
1025 self->d->infh = sys->open(sys, fol->data.cab->base.filename, 1086 self->d->infh = sys->open(sys, fol->data.cab->base.filename,
1026 MSPACK_SYS_OPEN_READ); 1087 MSPACK_SYS_OPEN_READ);
1027 if (!self->d->infh) return self->error = MSPACK_ERR_OPEN; 1088 if (!self->d->infh) return self->error = MSPACK_ERR_OPEN;
1028 } 1089 }
1029 /* seek to start of data blocks */ 1090 /* seek to start of data blocks */
@@ -1041,6 +1102,7 @@ static int cabd_extract(struct mscab_decompressor *base,
1041 self->d->data = &fol->data; 1102 self->d->data = &fol->data;
1042 self->d->offset = 0; 1103 self->d->offset = 0;
1043 self->d->block = 0; 1104 self->d->block = 0;
1105 self->d->outlen = 0;
1044 self->d->i_ptr = self->d->i_end = &self->d->input[0]; 1106 self->d->i_ptr = self->d->i_end = &self->d->input[0];
1045 1107
1046 /* read_error lasts for the lifetime of a decompressor */ 1108 /* read_error lasts for the lifetime of a decompressor */
@@ -1055,7 +1117,7 @@ static int cabd_extract(struct mscab_decompressor *base,
1055 self->error = MSPACK_ERR_OK; 1117 self->error = MSPACK_ERR_OK;
1056 1118
1057 /* if file has more than 0 bytes */ 1119 /* if file has more than 0 bytes */
1058 if (file->length) { 1120 if (filelen) {
1059 off_t bytes; 1121 off_t bytes;
1060 int error; 1122 int error;
1061 /* get to correct offset. 1123 /* get to correct offset.
@@ -1065,14 +1127,14 @@ static int cabd_extract(struct mscab_decompressor *base,
1065 */ 1127 */
1066 self->d->outfh = NULL; 1128 self->d->outfh = NULL;
1067 if ((bytes = file->offset - self->d->offset)) { 1129 if ((bytes = file->offset - self->d->offset)) {
1068 error = self->d->decompress(self->d->state, bytes); 1130 error = self->d->decompress(self->d->state, bytes);
1069 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error; 1131 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
1070 } 1132 }
1071 1133
1072 /* if getting to the correct offset was error free, unpack file */ 1134 /* if getting to the correct offset was error free, unpack file */
1073 if (!self->error) { 1135 if (!self->error) {
1074 self->d->outfh = fh; 1136 self->d->outfh = fh;
1075 error = self->d->decompress(self->d->state, (off_t) file->length); 1137 error = self->d->decompress(self->d->state, filelen);
1076 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error; 1138 self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
1077 } 1139 }
1078 } 1140 }
@@ -1098,34 +1160,27 @@ static int cabd_init_decomp(struct mscab_decompressor_p *self, unsigned int ct)
1098{ 1160{
1099 struct mspack_file *fh = (struct mspack_file *) self; 1161 struct mspack_file *fh = (struct mspack_file *) self;
1100 1162
1101 assert(self && self->d);
1102
1103 /* free any existing decompressor */
1104 cabd_free_decomp(self);
1105
1106 self->d->comp_type = ct; 1163 self->d->comp_type = ct;
1107 1164
1108 switch (ct & cffoldCOMPTYPE_MASK) { 1165 switch (ct & cffoldCOMPTYPE_MASK) {
1109 case cffoldCOMPTYPE_NONE: 1166 case cffoldCOMPTYPE_NONE:
1110 self->d->decompress = (int (*)(void *, off_t)) &noned_decompress; 1167 self->d->decompress = (int (*)(void *, off_t)) &noned_decompress;
1111 self->d->state = noned_init(&self->d->sys, fh, fh, 1168 self->d->state = noned_init(&self->d->sys, fh, fh, self->buf_size);
1112 self->param[MSCABD_PARAM_DECOMPBUF]);
1113 break; 1169 break;
1114 case cffoldCOMPTYPE_MSZIP: 1170 case cffoldCOMPTYPE_MSZIP:
1115 self->d->decompress = (int (*)(void *, off_t)) &mszipd_decompress; 1171 self->d->decompress = (int (*)(void *, off_t)) &mszipd_decompress;
1116 self->d->state = mszipd_init(&self->d->sys, fh, fh, 1172 self->d->state = mszipd_init(&self->d->sys, fh, fh, self->buf_size,
1117 self->param[MSCABD_PARAM_DECOMPBUF], 1173 self->fix_mszip);
1118 self->param[MSCABD_PARAM_FIXMSZIP]);
1119 break; 1174 break;
1120 case cffoldCOMPTYPE_QUANTUM: 1175 case cffoldCOMPTYPE_QUANTUM:
1121 self->d->decompress = (int (*)(void *, off_t)) &qtmd_decompress; 1176 self->d->decompress = (int (*)(void *, off_t)) &qtmd_decompress;
1122 self->d->state = qtmd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f, 1177 self->d->state = qtmd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f,
1123 self->param[MSCABD_PARAM_DECOMPBUF]); 1178 self->buf_size);
1124 break; 1179 break;
1125 case cffoldCOMPTYPE_LZX: 1180 case cffoldCOMPTYPE_LZX:
1126 self->d->decompress = (int (*)(void *, off_t)) &lzxd_decompress; 1181 self->d->decompress = (int (*)(void *, off_t)) &lzxd_decompress;
1127 self->d->state = lzxd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f, 0, 1182 self->d->state = lzxd_init(&self->d->sys, fh, fh, (int) (ct >> 8) & 0x1f, 0,
1128 self->param[MSCABD_PARAM_DECOMPBUF], (off_t) 0); 1183 self->buf_size, (off_t)0,0);
1129 break; 1184 break;
1130 default: 1185 default:
1131 return self->error = MSPACK_ERR_DATAFORMAT; 1186 return self->error = MSPACK_ERR_DATAFORMAT;
@@ -1134,7 +1189,7 @@ static int cabd_init_decomp(struct mscab_decompressor_p *self, unsigned int ct)
1134} 1189}
1135 1190
1136static void cabd_free_decomp(struct mscab_decompressor_p *self) { 1191static void cabd_free_decomp(struct mscab_decompressor_p *self) {
1137 if (!self || !self->d || !self->d->folder || !self->d->state) return; 1192 if (!self || !self->d || !self->d->state) return;
1138 1193
1139 switch (self->d->comp_type & cffoldCOMPTYPE_MASK) { 1194 switch (self->d->comp_type & cffoldCOMPTYPE_MASK) {
1140 case cffoldCOMPTYPE_NONE: noned_free((struct noned_state *) self->d->state); break; 1195 case cffoldCOMPTYPE_NONE: noned_free((struct noned_state *) self->d->state); break;
@@ -1162,10 +1217,12 @@ static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) {
1162 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file; 1217 struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file;
1163 unsigned char *buf = (unsigned char *) buffer; 1218 unsigned char *buf = (unsigned char *) buffer;
1164 struct mspack_system *sys = self->system; 1219 struct mspack_system *sys = self->system;
1165 int avail, todo, outlen, ignore_cksum; 1220 int avail, todo, outlen, ignore_cksum, ignore_blocksize;
1166 1221
1167 ignore_cksum = self->param[MSCABD_PARAM_FIXMSZIP] && 1222 ignore_cksum = self->salvage ||
1168 ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP); 1223 (self->fix_mszip &&
1224 ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP));
1225 ignore_blocksize = self->salvage;
1169 1226
1170 todo = bytes; 1227 todo = bytes;
1171 while (todo > 0) { 1228 while (todo > 0) {
@@ -1185,37 +1242,35 @@ static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) {
1185 1242
1186 /* check if we're out of input blocks, advance block counter */ 1243 /* check if we're out of input blocks, advance block counter */
1187 if (self->d->block++ >= self->d->folder->base.num_blocks) { 1244 if (self->d->block++ >= self->d->folder->base.num_blocks) {
1188 self->read_error = MSPACK_ERR_DATAFORMAT; 1245 if (!self->salvage) {
1189 break; 1246 self->read_error = MSPACK_ERR_DATAFORMAT;
1247 }
1248 else {
1249 D(("Ran out of CAB input blocks prematurely"))
1250 }
1251 break;
1190 } 1252 }
1191 1253
1192 /* read a block */ 1254 /* read a block */
1193 self->read_error = cabd_sys_read_block(sys, self->d, &outlen, ignore_cksum); 1255 self->read_error = cabd_sys_read_block(sys, self->d, &outlen,
1256 ignore_cksum, ignore_blocksize);
1194 if (self->read_error) return -1; 1257 if (self->read_error) return -1;
1258 self->d->outlen += outlen;
1195 1259
1196 /* special Quantum hack -- trailer byte to allow the decompressor 1260 /* special Quantum hack -- trailer byte to allow the decompressor
1197 * to realign itself. CAB Quantum blocks, unlike LZX blocks, can have 1261 * to realign itself. CAB Quantum blocks, unlike LZX blocks, can have
1198 * anything from 0 to 4 trailing null bytes. */ 1262 * anything from 0 to 4 trailing null bytes. */
1199 if ((self->d->comp_type & cffoldCOMPTYPE_MASK)==cffoldCOMPTYPE_QUANTUM) { 1263 if ((self->d->comp_type & cffoldCOMPTYPE_MASK)==cffoldCOMPTYPE_QUANTUM) {
1200 *self->d->i_end++ = 0xFF; 1264 *self->d->i_end++ = 0xFF;
1201 } 1265 }
1202 1266
1203 /* is this the last block? */ 1267 /* is this the last block? */
1204 if (self->d->block >= self->d->folder->base.num_blocks) { 1268 if (self->d->block >= self->d->folder->base.num_blocks) {
1205 /* last block */ 1269 if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) {
1206 if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) { 1270 /* special LZX hack -- on the last block, inform LZX of the
1207 /* special LZX hack -- on the last block, inform LZX of the 1271 * size of the output data stream. */
1208 * size of the output data stream. */ 1272 lzxd_set_output_length((struct lzxd_stream *) self->d->state, self->d->outlen);
1209 lzxd_set_output_length((struct lzxd_stream *) self->d->state, (off_t) 1273 }
1210 ((self->d->block-1) * CAB_BLOCKMAX + outlen));
1211 }
1212 }
1213 else {
1214 /* not the last block */
1215 if (outlen != CAB_BLOCKMAX) {
1216 self->system->message(self->d->infh,
1217 "WARNING; non-maximal data block");
1218 }
1219 } 1274 }
1220 } /* if (avail) */ 1275 } /* if (avail) */
1221 } /* while (todo > 0) */ 1276 } /* while (todo > 0) */
@@ -1238,12 +1293,13 @@ static int cabd_sys_write(struct mspack_file *file, void *buffer, int bytes) {
1238 * one cab file, if it does then the fragments will be reassembled 1293 * one cab file, if it does then the fragments will be reassembled
1239 */ 1294 */
1240static int cabd_sys_read_block(struct mspack_system *sys, 1295static int cabd_sys_read_block(struct mspack_system *sys,
1241 struct mscabd_decompress_state *d, 1296 struct mscabd_decompress_state *d,
1242 int *out, int ignore_cksum) 1297 int *out, int ignore_cksum,
1298 int ignore_blocksize)
1243{ 1299{
1244 unsigned char hdr[cfdata_SIZEOF]; 1300 unsigned char hdr[cfdata_SIZEOF];
1245 unsigned int cksum; 1301 unsigned int cksum;
1246 int len; 1302 int len, full_len;
1247 1303
1248 /* reset the input block pointer and end of block pointer */ 1304 /* reset the input block pointer and end of block pointer */
1249 d->i_ptr = d->i_end = &d->input[0]; 1305 d->i_ptr = d->i_end = &d->input[0];
@@ -1256,23 +1312,27 @@ static int cabd_sys_read_block(struct mspack_system *sys,
1256 1312
1257 /* skip any reserved block headers */ 1313 /* skip any reserved block headers */
1258 if (d->data->cab->block_resv && 1314 if (d->data->cab->block_resv &&
1259 sys->seek(d->infh, (off_t) d->data->cab->block_resv, 1315 sys->seek(d->infh, (off_t) d->data->cab->block_resv,
1260 MSPACK_SYS_SEEK_CUR)) 1316 MSPACK_SYS_SEEK_CUR))
1261 { 1317 {
1262 return MSPACK_ERR_SEEK; 1318 return MSPACK_ERR_SEEK;
1263 } 1319 }
1264 1320
1265 /* blocks must not be over CAB_INPUTMAX in size */ 1321 /* blocks must not be over CAB_INPUTMAX in size */
1266 len = EndGetI16(&hdr[cfdata_CompressedSize]); 1322 len = EndGetI16(&hdr[cfdata_CompressedSize]);
1267 if (((d->i_end - d->i_ptr) + len) > CAB_INPUTMAX) { 1323 full_len = (d->i_end - d->i_ptr) + len; /* include cab-spanning blocks */
1268 D(("block size > CAB_INPUTMAX (%ld + %d)", d->i_end - d->i_ptr, len)) 1324 if (full_len > CAB_INPUTMAX) {
1269 return MSPACK_ERR_DATAFORMAT; 1325 D(("block size %d > CAB_INPUTMAX", full_len));
1326 /* in salvage mode, blocks can be 65535 bytes but no more than that */
1327 if (!ignore_blocksize || full_len > CAB_INPUTMAX_SALVAGE) {
1328 return MSPACK_ERR_DATAFORMAT;
1329 }
1270 } 1330 }
1271 1331
1272 /* blocks must not expand to more than CAB_BLOCKMAX */ 1332 /* blocks must not expand to more than CAB_BLOCKMAX */
1273 if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) { 1333 if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) {
1274 D(("block size > CAB_BLOCKMAX")) 1334 D(("block size > CAB_BLOCKMAX"))
1275 return MSPACK_ERR_DATAFORMAT; 1335 if (!ignore_blocksize) return MSPACK_ERR_DATAFORMAT;
1276 } 1336 }
1277 1337
1278 /* read the block data */ 1338 /* read the block data */
@@ -1284,8 +1344,8 @@ static int cabd_sys_read_block(struct mspack_system *sys,
1284 if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) { 1344 if ((cksum = EndGetI32(&hdr[cfdata_CheckSum]))) {
1285 unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0); 1345 unsigned int sum2 = cabd_checksum(d->i_end, (unsigned int) len, 0);
1286 if (cabd_checksum(&hdr[4], 4, sum2) != cksum) { 1346 if (cabd_checksum(&hdr[4], 4, sum2) != cksum) {
1287 if (!ignore_cksum) return MSPACK_ERR_CHECKSUM; 1347 if (!ignore_cksum) return MSPACK_ERR_CHECKSUM;
1288 sys->message(d->infh, "WARNING; bad block checksum found"); 1348 sys->message(d->infh, "WARNING; bad block checksum found");
1289 } 1349 }
1290 } 1350 }
1291 1351
@@ -1310,14 +1370,14 @@ static int cabd_sys_read_block(struct mspack_system *sys,
1310 1370
1311 /* advance to next member in the cabinet set */ 1371 /* advance to next member in the cabinet set */
1312 if (!(d->data = d->data->next)) { 1372 if (!(d->data = d->data->next)) {
1313 D(("ran out of splits in cabinet set")) 1373 sys->message(d->infh, "WARNING; ran out of cabinets in set. Are any missing?");
1314 return MSPACK_ERR_DATAFORMAT; 1374 return MSPACK_ERR_DATAFORMAT;
1315 } 1375 }
1316 1376
1317 /* open next cab file */ 1377 /* open next cab file */
1318 d->incab = d->data->cab; 1378 d->incab = d->data->cab;
1319 if (!(d->infh = sys->open(sys, d->incab->base.filename, 1379 if (!(d->infh = sys->open(sys, d->incab->base.filename,
1320 MSPACK_SYS_OPEN_READ))) 1380 MSPACK_SYS_OPEN_READ)))
1321 { 1381 {
1322 return MSPACK_ERR_OPEN; 1382 return MSPACK_ERR_OPEN;
1323 } 1383 }
@@ -1333,7 +1393,7 @@ static int cabd_sys_read_block(struct mspack_system *sys,
1333} 1393}
1334 1394
1335static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes, 1395static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
1336 unsigned int cksum) 1396 unsigned int cksum)
1337{ 1397{
1338 unsigned int len, ul = 0; 1398 unsigned int len, ul = 0;
1339 1399
@@ -1342,8 +1402,8 @@ static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
1342 } 1402 }
1343 1403
1344 switch (bytes & 3) { 1404 switch (bytes & 3) {
1345 case 3: ul |= *data++ << 16; 1405 case 3: ul |= *data++ << 16; /*@fallthrough@*/
1346 case 2: ul |= *data++ << 8; 1406 case 2: ul |= *data++ << 8; /*@fallthrough@*/
1347 case 1: ul |= *data; 1407 case 1: ul |= *data;
1348 } 1408 }
1349 cksum ^= ul; 1409 cksum ^= ul;
@@ -1365,9 +1425,9 @@ struct noned_state {
1365}; 1425};
1366 1426
1367static struct noned_state *noned_init(struct mspack_system *sys, 1427static struct noned_state *noned_init(struct mspack_system *sys,
1368 struct mspack_file *in, 1428 struct mspack_file *in,
1369 struct mspack_file *out, 1429 struct mspack_file *out,
1370 int bufsize) 1430 int bufsize)
1371{ 1431{
1372 struct noned_state *state = (struct noned_state *) sys->alloc(sys, sizeof(struct noned_state)); 1432 struct noned_state *state = (struct noned_state *) sys->alloc(sys, sizeof(struct noned_state));
1373 unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) bufsize); 1433 unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) bufsize);
@@ -1419,14 +1479,17 @@ static int cabd_param(struct mscab_decompressor *base, int param, int value) {
1419 switch (param) { 1479 switch (param) {
1420 case MSCABD_PARAM_SEARCHBUF: 1480 case MSCABD_PARAM_SEARCHBUF:
1421 if (value < 4) return MSPACK_ERR_ARGS; 1481 if (value < 4) return MSPACK_ERR_ARGS;
1422 self->param[MSCABD_PARAM_SEARCHBUF] = value; 1482 self->searchbuf_size = value;
1423 break; 1483 break;
1424 case MSCABD_PARAM_FIXMSZIP: 1484 case MSCABD_PARAM_FIXMSZIP:
1425 self->param[MSCABD_PARAM_FIXMSZIP] = value; 1485 self->fix_mszip = value;
1426 break; 1486 break;
1427 case MSCABD_PARAM_DECOMPBUF: 1487 case MSCABD_PARAM_DECOMPBUF:
1428 if (value < 4) return MSPACK_ERR_ARGS; 1488 if (value < 4) return MSPACK_ERR_ARGS;
1429 self->param[MSCABD_PARAM_DECOMPBUF] = value; 1489 self->buf_size = value;
1490 break;
1491 case MSCABD_PARAM_SALVAGE:
1492 self->salvage = value;
1430 break; 1493 break;
1431 default: 1494 default:
1432 return MSPACK_ERR_ARGS; 1495 return MSPACK_ERR_ARGS;