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.
Files changed (141) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/rake.yml +37 -0
  3. data/.gitignore +2 -0
  4. data/.yardopts +1 -1
  5. data/README.md +1 -1
  6. data/Rakefile +11 -5
  7. data/ext/Rakefile +1 -1
  8. data/ext/libmspack/AUTHORS +1 -0
  9. data/ext/libmspack/ChangeLog +321 -4
  10. data/ext/libmspack/INSTALL +368 -0
  11. data/ext/libmspack/Makefile.am +86 -95
  12. data/ext/libmspack/Makefile.in +1729 -0
  13. data/ext/libmspack/README +30 -30
  14. data/ext/libmspack/acinclude.m4 +99 -0
  15. data/ext/libmspack/aclocal.m4 +1218 -0
  16. data/ext/libmspack/ar-lib +270 -0
  17. data/ext/libmspack/compile +347 -0
  18. data/ext/libmspack/config.guess +1480 -0
  19. data/ext/libmspack/config.h.in +129 -0
  20. data/ext/libmspack/config.sub +1801 -0
  21. data/ext/libmspack/configure +15487 -0
  22. data/ext/libmspack/configure.ac +11 -13
  23. data/ext/libmspack/depcomp +791 -0
  24. data/ext/libmspack/install-sh +508 -0
  25. data/ext/libmspack/libmscabd.la +41 -0
  26. data/ext/libmspack/libmschmd.la +41 -0
  27. data/ext/libmspack/libmspack.la +41 -0
  28. data/ext/libmspack/ltmain.sh +11156 -0
  29. data/ext/libmspack/m4/libtool.m4 +8387 -0
  30. data/ext/libmspack/m4/ltoptions.m4 +437 -0
  31. data/ext/libmspack/m4/ltsugar.m4 +124 -0
  32. data/ext/libmspack/m4/ltversion.m4 +23 -0
  33. data/ext/libmspack/m4/lt~obsolete.m4 +99 -0
  34. data/ext/libmspack/missing +215 -0
  35. data/ext/libmspack/mspack/cab.h +20 -7
  36. data/ext/libmspack/mspack/cabd.c +301 -236
  37. data/ext/libmspack/mspack/chmd.c +304 -319
  38. data/ext/libmspack/mspack/crc32.c +52 -52
  39. data/ext/libmspack/mspack/crc32.h +1 -1
  40. data/ext/libmspack/mspack/kwajd.c +178 -172
  41. data/ext/libmspack/mspack/lzss.h +4 -4
  42. data/ext/libmspack/mspack/lzssd.c +42 -42
  43. data/ext/libmspack/mspack/lzx.h +11 -11
  44. data/ext/libmspack/mspack/lzxd.c +370 -361
  45. data/ext/libmspack/mspack/mspack.h +109 -77
  46. data/ext/libmspack/mspack/mszip.h +6 -6
  47. data/ext/libmspack/mspack/mszipd.c +140 -139
  48. data/ext/libmspack/mspack/oab.h +1 -0
  49. data/ext/libmspack/mspack/oabd.c +71 -73
  50. data/ext/libmspack/mspack/qtm.h +4 -4
  51. data/ext/libmspack/mspack/qtmd.c +118 -117
  52. data/ext/libmspack/mspack/readbits.h +52 -52
  53. data/ext/libmspack/mspack/readhuff.h +61 -61
  54. data/ext/libmspack/mspack/system.c +15 -9
  55. data/ext/libmspack/mspack/system.h +38 -50
  56. data/ext/libmspack/mspack/szddd.c +35 -35
  57. data/ext/libmspack/test-driver +148 -0
  58. data/ext/x86_64-linux/libmspack.so +0 -0
  59. data/ext/x86_64-windows/mspack.dll +0 -0
  60. data/lib/libmspack/version.rb +2 -1
  61. data/lib/libmspack.rb +1 -1
  62. data/libmspack.gemspec +4 -4
  63. data/spec/libmspack_spec.rb +5 -4
  64. metadata +38 -105
  65. data/.travis.yml +0 -5
  66. data/ext/i386-windows/libmspack.dll +0 -0
  67. data/ext/libmspack/cleanup.sh +0 -9
  68. data/ext/libmspack/debian/changelog +0 -6
  69. data/ext/libmspack/debian/control +0 -14
  70. data/ext/libmspack/debian/rules +0 -101
  71. data/ext/libmspack/doc/Doxyfile.in +0 -22
  72. data/ext/libmspack/doc/Makefile.in +0 -14
  73. data/ext/libmspack/doc/szdd_kwaj_format.html +0 -331
  74. data/ext/libmspack/mspack/mspack.def +0 -28
  75. data/ext/libmspack/mspack/qtmc.c +0 -18
  76. data/ext/libmspack/rebuild.sh +0 -8
  77. data/ext/libmspack/test/cabd_c10 +0 -19
  78. data/ext/libmspack/test/cabd_compare +0 -34
  79. data/ext/libmspack/test/cabd_md5.c +0 -161
  80. data/ext/libmspack/test/cabd_memory.c +0 -179
  81. data/ext/libmspack/test/cabd_test.c +0 -386
  82. data/ext/libmspack/test/cabrip.c +0 -81
  83. data/ext/libmspack/test/chmd_compare +0 -38
  84. data/ext/libmspack/test/chmd_find.c +0 -95
  85. data/ext/libmspack/test/chmd_md5.c +0 -67
  86. data/ext/libmspack/test/chmd_order.c +0 -144
  87. data/ext/libmspack/test/chminfo.c +0 -284
  88. data/ext/libmspack/test/chmx.c +0 -216
  89. data/ext/libmspack/test/error.h +0 -22
  90. data/ext/libmspack/test/expand.c +0 -79
  91. data/ext/libmspack/test/md5.c +0 -457
  92. data/ext/libmspack/test/md5.h +0 -165
  93. data/ext/libmspack/test/md5_fh.h +0 -123
  94. data/ext/libmspack/test/msdecompile_md5 +0 -24
  95. data/ext/libmspack/test/msexpand_md5 +0 -39
  96. data/ext/libmspack/test/multifh.c +0 -435
  97. data/ext/libmspack/test/oabx.c +0 -41
  98. data/ext/libmspack/test/test_files/cabd/1.pl +0 -84
  99. data/ext/libmspack/test/test_files/cabd/2.pl +0 -75
  100. data/ext/libmspack/test/test_files/cabd/bad_folderindex.cab +0 -0
  101. data/ext/libmspack/test/test_files/cabd/bad_nofiles.cab +0 -0
  102. data/ext/libmspack/test/test_files/cabd/bad_nofolders.cab +0 -0
  103. data/ext/libmspack/test/test_files/cabd/bad_signature.cab +0 -0
  104. data/ext/libmspack/test/test_files/cabd/multi_basic_pt1.cab +0 -0
  105. data/ext/libmspack/test/test_files/cabd/multi_basic_pt2.cab +0 -0
  106. data/ext/libmspack/test/test_files/cabd/multi_basic_pt3.cab +0 -0
  107. data/ext/libmspack/test/test_files/cabd/multi_basic_pt4.cab +0 -0
  108. data/ext/libmspack/test/test_files/cabd/multi_basic_pt5.cab +0 -0
  109. data/ext/libmspack/test/test_files/cabd/normal_255c_filename.cab +0 -0
  110. data/ext/libmspack/test/test_files/cabd/normal_2files_1folder.cab +0 -0
  111. data/ext/libmspack/test/test_files/cabd/partial_nodata.cab +0 -0
  112. data/ext/libmspack/test/test_files/cabd/partial_nofiles.cab +0 -0
  113. data/ext/libmspack/test/test_files/cabd/partial_nofolder.cab +0 -0
  114. data/ext/libmspack/test/test_files/cabd/partial_shortextheader.cab +0 -0
  115. data/ext/libmspack/test/test_files/cabd/partial_shortfile1.cab +0 -0
  116. data/ext/libmspack/test/test_files/cabd/partial_shortfile2.cab +0 -0
  117. data/ext/libmspack/test/test_files/cabd/partial_shortfolder.cab +0 -0
  118. data/ext/libmspack/test/test_files/cabd/partial_shortheader.cab +0 -0
  119. data/ext/libmspack/test/test_files/cabd/partial_str_nofname.cab +0 -0
  120. data/ext/libmspack/test/test_files/cabd/partial_str_noninfo.cab +0 -0
  121. data/ext/libmspack/test/test_files/cabd/partial_str_nonname.cab +0 -0
  122. data/ext/libmspack/test/test_files/cabd/partial_str_nopinfo.cab +0 -0
  123. data/ext/libmspack/test/test_files/cabd/partial_str_nopname.cab +0 -0
  124. data/ext/libmspack/test/test_files/cabd/partial_str_shortfname.cab +0 -0
  125. data/ext/libmspack/test/test_files/cabd/partial_str_shortninfo.cab +0 -0
  126. data/ext/libmspack/test/test_files/cabd/partial_str_shortnname.cab +0 -0
  127. data/ext/libmspack/test/test_files/cabd/partial_str_shortpinfo.cab +0 -0
  128. data/ext/libmspack/test/test_files/cabd/partial_str_shortpname.cab +0 -0
  129. data/ext/libmspack/test/test_files/cabd/reserve_---.cab +0 -0
  130. data/ext/libmspack/test/test_files/cabd/reserve_--D.cab +0 -0
  131. data/ext/libmspack/test/test_files/cabd/reserve_-F-.cab +0 -0
  132. data/ext/libmspack/test/test_files/cabd/reserve_-FD.cab +0 -0
  133. data/ext/libmspack/test/test_files/cabd/reserve_H--.cab +0 -0
  134. data/ext/libmspack/test/test_files/cabd/reserve_H-D.cab +0 -0
  135. data/ext/libmspack/test/test_files/cabd/reserve_HF-.cab +0 -0
  136. data/ext/libmspack/test/test_files/cabd/reserve_HFD.cab +0 -0
  137. data/ext/libmspack/test/test_files/cabd/search_basic.cab +0 -0
  138. data/ext/libmspack/test/test_files/cabd/search_tricky1.cab +0 -0
  139. data/ext/libmspack/winbuild.sh +0 -26
  140. data/ext/libmspack.h +0 -259
  141. data/ext/x86_64-windows/libmspack.dll +0 -0
@@ -1,5 +1,5 @@
1
1
  /* This file is part of libmspack.
2
- * (C) 2003-2011 Stuart Caie.
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 <assert.h>
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->param[MSCABD_PARAM_SEARCHBUF] = 32768;
158
- self->param[MSCABD_PARAM_FIXMSZIP] = 0;
159
- self->param[MSCABD_PARAM_DECOMPBUF] = 4096;
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
- const char *filename)
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
- cabd_close(base, (struct mscabd_cabinet *) cab);
206
- cab = NULL;
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
- struct mscabd_cabinet *origcab)
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
- if (self->d->infh) sys->close(self->d->infh);
256
- cabd_free_decomp(self);
257
- sys->free(self->d);
258
- self->d = NULL;
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
- ndat = dat->next;
264
- sys->free(dat);
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
- struct mspack_file *fh,
307
- struct mscabd_cabinet_p *cab,
308
- off_t offset, int quiet)
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
- return MSPACK_ERR_SEEK;
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, &x); if (x) return x;
394
- cab->base.previnfo = cabd_read_string(sys, fh, &x); if (x) return x;
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, &x); if (x) return x;
400
- cab->base.nextinfo = cabd_read_string(sys, fh, &x); if (x) return x;
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
- return MSPACK_ERR_SEEK;
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
- x = EndGetI16(&buf[cffile_FolderIndex]);
450
- if (x < cffileCONTINUED_FROM_PREV) {
451
- /* normal folder index; count up to the correct folder. the folder
452
- * pointer will be NULL if folder index is invalid */
453
- struct mscabd_folder *ifol = cab->base.folders;
454
- while (x--) if (ifol) ifol = ifol->next;
455
- file->folder = ifol;
456
-
457
- if (!ifol) {
458
- sys->free(file);
459
- D(("invalid folder index"))
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 ((x == cffileCONTINUED_TO_NEXT) ||
467
- (x == cffileCONTINUED_PREV_AND_NEXT))
473
+ if ((fidx == cffileCONTINUED_TO_NEXT) ||
474
+ (fidx == cffileCONTINUED_PREV_AND_NEXT))
468
475
  {
469
- /* get last folder */
470
- struct mscabd_folder *ifol = cab->base.folders;
471
- while (ifol->next) ifol = ifol->next;
472
- file->folder = ifol;
473
-
474
- /* set "merge next" pointer */
475
- fol = (struct mscabd_folder_p *) ifol;
476
- if (!fol->merge_next) fol->merge_next = file;
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 ((x == cffileCONTINUED_FROM_PREV) ||
480
- (x == cffileCONTINUED_PREV_AND_NEXT))
486
+ if ((fidx == cffileCONTINUED_FROM_PREV) ||
487
+ (fidx == cffileCONTINUED_PREV_AND_NEXT))
481
488
  {
482
- /* get first folder */
483
- file->folder = cab->base.folders;
489
+ /* get first folder */
490
+ file->folder = cab->base.folders;
484
491
 
485
- /* set "merge prev" pointer */
486
- fol = (struct mscabd_folder_p *) file->folder;
487
- if (!fol->merge_prev) fol->merge_prev = file;
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, &x);
505
- if (x) {
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
- return x;
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
- struct mspack_file *fh, int *error)
538
+ struct mspack_file *fh, int *error)
521
539
  {
522
540
  off_t base = sys->tell(fh);
523
541
  char buf[256], *str;
524
- unsigned int len, i, ok;
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
- const char *filename)
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->param[MSCABD_PARAM_SEARCHBUF]);
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
- filelen, &firstlen, &cab);
613
+ filelen, &firstlen, &cab);
590
614
  }
591
615
 
592
616
  /* truncated / extraneous data warning: */
593
617
  if (firstlen && (firstlen != filelen) &&
594
- (!cab || (cab->base.base_offset == 0)))
618
+ (!cab || (cab->base.base_offset == 0)))
595
619
  {
596
620
  if (firstlen < filelen) {
597
- sys->message(fh, "WARNING; possible %" LD
598
- " extra bytes at end of file.",
599
- filelen - firstlen);
621
+ sys->message(fh, "WARNING; possible %" LD
622
+ " extra bytes at end of file.",
623
+ filelen - firstlen);
600
624
  }
601
625
  else {
602
- sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes.",
603
- firstlen - filelen);
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
- struct mspack_file *fh, const char *filename, off_t flen,
621
- off_t *firstlen, struct mscabd_cabinet_p **firstcab)
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
- #ifndef LARGEFILE_SUPPORT
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->param[MSCABD_PARAM_SEARCHBUF]) {
644
- length = self->param[MSCABD_PARAM_SEARCHBUF];
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
- "This is probably an InstallShield file. "
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
- /* starting state */
685
+ /* starting state */
663
686
  case 0:
664
- /* we spend most of our time in this while loop, looking for
665
- * a leading 'M' of the 'MSCF' signature */
666
- while (p < pend && *p != 0x4D) p++;
667
- /* if we found tht 'M', advance state */
668
- if (p++ < pend) state = 1;
669
- break;
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
- /* now we have recieved 20 bytes of potential cab header. work out
692
- * the offset in the file of this potential cabinet */
693
- caboff = offset + (p - &buf[0]) - 20;
694
-
695
- /* should reading cabinet fail, restart search just after 'MSCF' */
696
- offset = caboff + 4;
697
-
698
- /* capture the "length of cabinet" field if there is a cabinet at
699
- * offset 0 in the file, regardless of whether the cabinet can be
700
- * read correctly or not */
701
- if (caboff == 0) *firstlen = (off_t) cablen_u32;
702
-
703
- /* check that the files offset is less than the alleged length of
704
- * the cabinet, and that the offset + the alleged length are
705
- * 'roughly' within the end of overall file length */
706
- if ((foffset_u32 < cablen_u32) &&
707
- ((caboff + (off_t) foffset_u32) < (flen + 32)) &&
708
- ((caboff + (off_t) cablen_u32) < (flen + 32)) )
709
- {
710
- /* likely cabinet found -- try reading it */
711
- if (!(cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) {
712
- return MSPACK_ERR_NOMEMORY;
713
- }
714
- cab->base.filename = filename;
715
- if (cabd_read_headers(sys, fh, cab, caboff, 1)) {
716
- /* destroy the failed cabinet */
717
- cabd_close((struct mscab_decompressor *) self,
718
- (struct mscabd_cabinet *) cab);
719
- false_cabs++;
720
- }
721
- else {
722
- /* cabinet read correctly! */
723
-
724
- /* link the cab into the list */
725
- if (!link) *firstcab = cab;
726
- else link->base.next = (struct mscabd_cabinet *) cab;
727
- link = cab;
728
-
729
- /* cause the search to restart after this cab's data. */
730
- offset = caboff + (off_t) cablen_u32;
731
-
732
- #ifndef LARGEFILE_SUPPORT
733
- /* detect 32-bit off_t overflow */
734
- if (offset < caboff) {
735
- sys->message(fh, largefile_msg);
736
- return MSPACK_ERR_OK;
737
- }
738
- #endif
739
- }
740
- }
741
-
742
- /* restart search */
743
- if (offset >= flen) return MSPACK_ERR_OK;
744
- if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
745
- return MSPACK_ERR_SEEK;
746
- }
747
- length = 0;
748
- p = pend;
749
- state = 0;
750
- break;
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
- p++, state++;
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
- struct mscabd_cabinet *cab,
776
- struct mscabd_cabinet *prevcab)
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
- struct mscabd_cabinet *cab,
783
- struct mscabd_cabinet *nextcab)
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
- struct mscabd_cabinet *lcab,
790
- struct mscabd_cabinet *rcab)
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
- (rfol->merge_next->folder != (struct mscabd_folder *) rfol))
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
- if (lfi) lfi->next = rfi; else lcab->files = rfi;
904
- sys->free(fi->filename);
905
- sys->free(fi);
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
- if (!r || (l->offset != r->offset) || (l->length != r->length)) {
951
- matching = 0;
952
- break;
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
- for (r = rfi; r; r = r->next) {
964
- if (l->offset == r->offset && l->length == r->length) break;
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
- /* check if file can be extracted */
993
- if ((!fol) || (fol->merge_prev) ||
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
- MSPACK_SYS_OPEN_READ);
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 (file->length) {
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
- error = self->d->decompress(self->d->state, bytes);
1066
- self->error = (error == MSPACK_ERR_READ) ? self->read_error : error;
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, (off_t) file->length);
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
- self->param[MSCABD_PARAM_DECOMPBUF],
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
- self->param[MSCABD_PARAM_DECOMPBUF]);
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
- self->param[MSCABD_PARAM_DECOMPBUF], (off_t)0,0);
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->folder || !self->d->state) return;
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->param[MSCABD_PARAM_FIXMSZIP] &&
1165
- ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP);
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
- self->read_error = MSPACK_ERR_DATAFORMAT;
1186
- break;
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, ignore_cksum);
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
- *self->d->i_end++ = 0xFF;
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
- /* last block */
1203
- if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) {
1204
- /* special LZX hack -- on the last block, inform LZX of the
1205
- * size of the output data stream. */
1206
- lzxd_set_output_length((struct lzxd_stream *) self->d->state, (off_t)
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
- struct mscabd_decompress_state *d,
1239
- int *out, int ignore_cksum)
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
- sys->seek(d->infh, (off_t) d->data->cab->block_resv,
1257
- MSPACK_SYS_SEEK_CUR))
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
- if (((d->i_end - d->i_ptr) + len) > CAB_INPUTMAX) {
1265
- D(("block size > CAB_INPUTMAX (%ld + %d)",
1266
- (long)(d->i_end - d->i_ptr), len))
1267
- return MSPACK_ERR_DATAFORMAT;
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
- if (!ignore_cksum) return MSPACK_ERR_CHECKSUM;
1286
- sys->message(d->infh, "WARNING; bad block checksum found");
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
- D(("ran out of splits in cabinet set"))
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
- MSPACK_SYS_OPEN_READ)))
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
- unsigned int cksum)
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
- struct mspack_file *in,
1367
- struct mspack_file *out,
1368
- int bufsize)
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->param[MSCABD_PARAM_SEARCHBUF] = value;
1482
+ self->searchbuf_size = value;
1421
1483
  break;
1422
1484
  case MSCABD_PARAM_FIXMSZIP:
1423
- self->param[MSCABD_PARAM_FIXMSZIP] = value;
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->param[MSCABD_PARAM_DECOMPBUF] = value;
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;