libmspack 0.10.1.2 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/ext/libmspack/ChangeLog +145 -0
  4. data/ext/libmspack/INSTALL +3 -3
  5. data/ext/libmspack/Makefile.am +7 -4
  6. data/ext/libmspack/Makefile.in +265 -147
  7. data/ext/libmspack/README +3 -2
  8. data/ext/libmspack/aclocal.m4 +111 -113
  9. data/ext/libmspack/ar-lib +10 -9
  10. data/ext/libmspack/compile +9 -8
  11. data/ext/libmspack/config.guess +887 -613
  12. data/ext/libmspack/config.h.in +6 -9
  13. data/ext/libmspack/config.sub +1349 -1260
  14. data/ext/libmspack/configure +3035 -2490
  15. data/ext/libmspack/configure.ac +3 -3
  16. data/ext/libmspack/depcomp +4 -4
  17. data/ext/libmspack/install-sh +107 -74
  18. data/ext/libmspack/libmscabd.la +1 -1
  19. data/ext/libmspack/libmschmd.la +1 -1
  20. data/ext/libmspack/libmspack.la +1 -1
  21. data/ext/libmspack/ltmain.sh +156 -61
  22. data/ext/libmspack/m4/libtool.m4 +19 -12
  23. data/ext/libmspack/missing +8 -8
  24. data/ext/libmspack/mspack/cabd.c +21 -19
  25. data/ext/libmspack/mspack/chm.h +3 -2
  26. data/ext/libmspack/mspack/chmd.c +137 -57
  27. data/ext/libmspack/mspack/kwajd.c +29 -29
  28. data/ext/libmspack/mspack/lzx.h +0 -1
  29. data/ext/libmspack/mspack/lzxd.c +30 -154
  30. data/ext/libmspack/mspack/macros.h +64 -0
  31. data/ext/libmspack/mspack/mszipd.c +7 -18
  32. data/ext/libmspack/mspack/qtmd.c +3 -5
  33. data/ext/libmspack/mspack/readbits.h +14 -5
  34. data/ext/libmspack/mspack/readhuff.h +26 -21
  35. data/ext/libmspack/mspack/system.c +0 -5
  36. data/ext/libmspack/mspack/system.h +20 -67
  37. data/ext/libmspack/test-driver +16 -11
  38. data/ext/x86_64-linux/libmspack.so +0 -0
  39. data/ext/x86_64-windows/mspack.dll +0 -0
  40. data/lib/libmspack/version.rb +1 -1
  41. metadata +4 -3
@@ -1,5 +1,5 @@
1
1
  /* This file is part of libmspack.
2
- * (C) 2003-2018 Stuart Caie.
2
+ * (C) 2003-2023 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
@@ -76,7 +76,8 @@ static int cabd_read_headers(
76
76
  struct mspack_system *sys, struct mspack_file *fh,
77
77
  struct mscabd_cabinet_p *cab, off_t offset, int salvage, int quiet);
78
78
  static char *cabd_read_string(
79
- struct mspack_system *sys, struct mspack_file *fh, int *error);
79
+ struct mspack_system *sys, struct mspack_file *fh, int permit_empty,
80
+ int *error);
80
81
 
81
82
  static struct mscabd_cabinet *cabd_search(
82
83
  struct mscab_decompressor *base, const char *filename);
@@ -394,17 +395,17 @@ static int cabd_read_headers(struct mspack_system *sys,
394
395
 
395
396
  /* read name and info of preceeding cabinet in set, if present */
396
397
  if (cab->base.flags & cfheadPREV_CABINET) {
397
- cab->base.prevname = cabd_read_string(sys, fh, &err);
398
+ cab->base.prevname = cabd_read_string(sys, fh, 0, &err);
398
399
  if (err) return err;
399
- cab->base.previnfo = cabd_read_string(sys, fh, &err);
400
+ cab->base.previnfo = cabd_read_string(sys, fh, 1, &err);
400
401
  if (err) return err;
401
402
  }
402
403
 
403
404
  /* read name and info of next cabinet in set, if present */
404
405
  if (cab->base.flags & cfheadNEXT_CABINET) {
405
- cab->base.nextname = cabd_read_string(sys, fh, &err);
406
+ cab->base.nextname = cabd_read_string(sys, fh, 0, &err);
406
407
  if (err) return err;
407
- cab->base.nextinfo = cabd_read_string(sys, fh, &err);
408
+ cab->base.nextinfo = cabd_read_string(sys, fh, 1, &err);
408
409
  if (err) return err;
409
410
  }
410
411
 
@@ -508,7 +509,7 @@ static int cabd_read_headers(struct mspack_system *sys,
508
509
  file->date_y = (x >> 9) + 1980;
509
510
 
510
511
  /* get filename */
511
- file->filename = cabd_read_string(sys, fh, &err);
512
+ file->filename = cabd_read_string(sys, fh, 0, &err);
512
513
 
513
514
  /* if folder index or filename are bad, either skip it or fail */
514
515
  if (err || !file->folder) {
@@ -535,7 +536,8 @@ static int cabd_read_headers(struct mspack_system *sys,
535
536
  }
536
537
 
537
538
  static char *cabd_read_string(struct mspack_system *sys,
538
- struct mspack_file *fh, int *error)
539
+ struct mspack_file *fh, int permit_empty,
540
+ int *error)
539
541
  {
540
542
  off_t base = sys->tell(fh);
541
543
  char buf[256], *str;
@@ -549,8 +551,8 @@ static char *cabd_read_string(struct mspack_system *sys,
549
551
 
550
552
  /* search for a null terminator in the buffer */
551
553
  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
+ /* optionally reject empty strings */
555
+ if (i == 0 && !permit_empty) ok = 0;
554
556
 
555
557
  if (!ok) {
556
558
  *error = MSPACK_ERR_DATAFORMAT;
@@ -651,10 +653,10 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
651
653
  unsigned int cablen_u32 = 0, foffset_u32 = 0;
652
654
  int false_cabs = 0;
653
655
 
654
- #if !LARGEFILE_SUPPORT
656
+ #if SIZEOF_OFF_T < 8
655
657
  /* detect 32-bit off_t overflow */
656
658
  if (flen < 0) {
657
- sys->message(fh, largefile_msg);
659
+ sys->message(fh, "library not compiled to support large files.");
658
660
  return MSPACK_ERR_OK;
659
661
  }
660
662
  #endif
@@ -753,10 +755,10 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf,
753
755
  /* cause the search to restart after this cab's data. */
754
756
  offset = caboff + (off_t) cablen_u32;
755
757
 
756
- #if !LARGEFILE_SUPPORT
758
+ #if SIZEOF_OFF_T < 8
757
759
  /* detect 32-bit off_t overflow */
758
760
  if (offset < caboff) {
759
- sys->message(fh, largefile_msg);
761
+ sys->message(fh, "library not compiled to support large files.");
760
762
  return MSPACK_ERR_OK;
761
763
  }
762
764
  #endif
@@ -1012,7 +1014,7 @@ static int cabd_extract(struct mscab_decompressor *base,
1012
1014
  struct mscabd_folder_p *fol;
1013
1015
  struct mspack_system *sys;
1014
1016
  struct mspack_file *fh;
1015
- off_t filelen;
1017
+ unsigned int filelen;
1016
1018
 
1017
1019
  if (!self) return MSPACK_ERR_ARGS;
1018
1020
  if (!file) return self->error = MSPACK_ERR_ARGS;
@@ -1029,7 +1031,7 @@ static int cabd_extract(struct mscab_decompressor *base,
1029
1031
  * or in salvage mode reduce file length so it fits 2GB limit
1030
1032
  */
1031
1033
  filelen = file->length;
1032
- if (filelen > CAB_LENGTHMAX || (file->offset + filelen) > CAB_LENGTHMAX) {
1034
+ if (filelen > (CAB_LENGTHMAX - file->offset)) {
1033
1035
  if (self->salvage) {
1034
1036
  filelen = CAB_LENGTHMAX - file->offset;
1035
1037
  }
@@ -1049,8 +1051,8 @@ static int cabd_extract(struct mscab_decompressor *base,
1049
1051
  * In salvage mode, don't assume block sizes, just try decoding
1050
1052
  */
1051
1053
  if (!self->salvage) {
1052
- off_t maxlen = fol->base.num_blocks * CAB_BLOCKMAX;
1053
- if ((file->offset + filelen) > maxlen) {
1054
+ unsigned int maxlen = fol->base.num_blocks * CAB_BLOCKMAX;
1055
+ if (file->offset > maxlen || filelen > (maxlen - file->offset)) {
1054
1056
  sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, "
1055
1057
  "cabinet set is incomplete", file->filename);
1056
1058
  return self->error = MSPACK_ERR_DECRUNCH;
@@ -1398,7 +1400,7 @@ static unsigned int cabd_checksum(unsigned char *data, unsigned int bytes,
1398
1400
  unsigned int len, ul = 0;
1399
1401
 
1400
1402
  for (len = bytes >> 2; len--; data += 4) {
1401
- cksum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24));
1403
+ cksum ^= EndGetI32(data);
1402
1404
  }
1403
1405
 
1404
1406
  switch (bytes & 3) {
@@ -1,5 +1,5 @@
1
1
  /* This file is part of libmspack.
2
- * (C) 2003-2004 Stuart Caie.
2
+ * (C) 2003-2023 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
@@ -104,7 +104,8 @@ struct mschm_compressor_p {
104
104
  /* CHM decompression definitions */
105
105
  struct mschmd_decompress_state {
106
106
  struct mschmd_header *chm; /* CHM file being decompressed */
107
- off_t offset; /* uncompressed offset within folder */
107
+ off_t length; /* uncompressed length of LZX stream */
108
+ off_t offset; /* uncompressed offset within stream */
108
109
  off_t inoffset; /* offset in input file */
109
110
  struct lzxd_stream *state; /* LZX decompressor state */
110
111
  struct mspack_system sys; /* special I/O code for decompressor */
@@ -1,5 +1,5 @@
1
1
  /* This file is part of libmspack.
2
- * (C) 2003-2018 Stuart Caie.
2
+ * (C) 2003-2023 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
@@ -58,6 +58,8 @@ static int chmd_error(
58
58
  static int read_off64(
59
59
  off_t *var, unsigned char *mem, struct mspack_system *sys,
60
60
  struct mspack_file *fh);
61
+ static off_t read_encint(
62
+ const unsigned char **p, const unsigned char *end, int *err);
61
63
 
62
64
  /* filenames of the system files used for decompression.
63
65
  * Content and ControlData are essential.
@@ -249,24 +251,15 @@ static const unsigned char guids[32] = {
249
251
  0x9E, 0x0C, 0x00, 0xA0, 0xC9, 0x22, 0xE6, 0xEC
250
252
  };
251
253
 
252
- /* reads an encoded integer into a variable; 7 bits of data per byte,
253
- * the high bit is used to indicate that there is another byte */
254
- #define READ_ENCINT(var) do { \
255
- (var) = 0; \
256
- do { \
257
- if (p >= end) goto chunk_end; \
258
- (var) = ((var) << 7) | (*p & 0x7F); \
259
- } while (*p++ & 0x80); \
260
- } while (0)
261
-
262
254
  static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
263
255
  struct mschmd_header *chm, int entire)
264
256
  {
265
- unsigned int section, name_len, x, errors, num_chunks;
266
- unsigned char buf[0x54], *chunk = NULL, *name, *p, *end;
257
+ unsigned int errors, num_chunks;
258
+ unsigned char buf[0x54], *chunk = NULL;
259
+ const unsigned char *name, *p, *end;
267
260
  struct mschmd_file *fi, *link = NULL;
268
- off_t offset, length;
269
- int num_entries;
261
+ off_t offset_hs0, filelen;
262
+ int num_entries, err = 0;
270
263
 
271
264
  /* initialise pointers */
272
265
  chm->files = NULL;
@@ -312,7 +305,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
312
305
  /* chmhst3_OffsetCS0 does not exist in version 1 or 2 CHM files.
313
306
  * The offset will be corrected later, once HS1 is read.
314
307
  */
315
- if (read_off64(&offset, &buf[chmhst_OffsetHS0], sys, fh) ||
308
+ if (read_off64(&offset_hs0, &buf[chmhst_OffsetHS0], sys, fh) ||
316
309
  read_off64(&chm->dir_offset, &buf[chmhst_OffsetHS1], sys, fh) ||
317
310
  read_off64(&chm->sec0.offset, &buf[chmhst3_OffsetCS0], sys, fh))
318
311
  {
@@ -320,7 +313,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
320
313
  }
321
314
 
322
315
  /* seek to header section 0 */
323
- if (sys->seek(fh, offset, MSPACK_SYS_SEEK_START)) {
316
+ if (sys->seek(fh, offset_hs0, MSPACK_SYS_SEEK_START)) {
324
317
  return MSPACK_ERR_SEEK;
325
318
  }
326
319
 
@@ -332,6 +325,18 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
332
325
  return MSPACK_ERR_DATAFORMAT;
333
326
  }
334
327
 
328
+ /* compare declared CHM file size against actual size */
329
+ if (!mspack_sys_filelen(sys, fh, &filelen)) {
330
+ if (chm->length > filelen) {
331
+ sys->message(fh, "WARNING; file possibly truncated by %" LD " bytes",
332
+ chm->length - filelen);
333
+ }
334
+ else if (chm->length < filelen) {
335
+ sys->message(fh, "WARNING; possible %" LD " extra bytes at end of file",
336
+ filelen - chm->length);
337
+ }
338
+ }
339
+
335
340
  /* seek to header section 1 */
336
341
  if (sys->seek(fh, chm->dir_offset, MSPACK_SYS_SEEK_START)) {
337
342
  return MSPACK_ERR_SEEK;
@@ -412,12 +417,13 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
412
417
  }
413
418
 
414
419
  /* seek to the first PMGL chunk, and reduce the number of chunks to read */
415
- if ((x = chm->first_pmgl) != 0) {
416
- if (sys->seek(fh,(off_t) (x * chm->chunk_size), MSPACK_SYS_SEEK_CUR)) {
420
+ if (chm->first_pmgl != 0) {
421
+ off_t pmgl_offset = (off_t) chm->first_pmgl * (off_t) chm->chunk_size;
422
+ if (sys->seek(fh, pmgl_offset, MSPACK_SYS_SEEK_CUR)) {
417
423
  return MSPACK_ERR_SEEK;
418
424
  }
419
425
  }
420
- num_chunks = chm->last_pmgl - x + 1;
426
+ num_chunks = chm->last_pmgl - chm->first_pmgl + 1;
421
427
 
422
428
  if (!(chunk = (unsigned char *) sys->alloc(sys, (size_t)chm->chunk_size))) {
423
429
  return MSPACK_ERR_NOMEMORY;
@@ -449,12 +455,15 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
449
455
  num_entries = EndGetI16(end);
450
456
 
451
457
  while (num_entries--) {
452
- READ_ENCINT(name_len);
453
- if (name_len > (unsigned int) (end - p)) goto chunk_end;
458
+ unsigned int name_len, section;
459
+ off_t offset, length;
460
+ name_len = read_encint(&p, end, &err);
461
+ if (err || (name_len > (unsigned int) (end - p))) goto encint_err;
454
462
  name = p; p += name_len;
455
- READ_ENCINT(section);
456
- READ_ENCINT(offset);
457
- READ_ENCINT(length);
463
+ section = read_encint(&p, end, &err);
464
+ offset = read_encint(&p, end, &err);
465
+ length = read_encint(&p, end, &err);
466
+ if (err) goto encint_err;
458
467
 
459
468
  /* ignore blank or one-char (e.g. "/") filenames we'd return as blank */
460
469
  if (name_len < 2 || !name[0] || !name[1]) continue;
@@ -482,7 +491,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
482
491
  : (struct mschmd_section *) (&chm->sec1));
483
492
  fi->offset = offset;
484
493
  fi->length = length;
485
- sys->copy(name, fi->filename, (size_t) name_len);
494
+ sys->copy((unsigned char *) name, fi->filename, (size_t) name_len);
486
495
  fi->filename[name_len] = '\0';
487
496
 
488
497
  if (name[0] == ':' && name[1] == ':') {
@@ -510,10 +519,10 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
510
519
  }
511
520
 
512
521
  /* this is reached either when num_entries runs out, or if
513
- * reading data from the chunk reached a premature end of chunk */
514
- chunk_end:
522
+ * an ENCINT is badly encoded */
523
+ encint_err:
515
524
  if (num_entries >= 0) {
516
- D(("chunk ended before all entries could be read"))
525
+ D(("bad encint before all entries could be read"))
517
526
  errors++;
518
527
  }
519
528
 
@@ -572,7 +581,10 @@ static int chmd_fast_find(struct mschm_decompressor *base,
572
581
  }
573
582
 
574
583
  /* found result. loop around for next chunk if this is PMGI */
575
- if (chunk[3] == 0x4C) break; else READ_ENCINT(n);
584
+ if (chunk[3] == 0x4C) break;
585
+
586
+ n = read_encint(&p, end, &err);
587
+ if (err) goto encint_err;
576
588
  }
577
589
  }
578
590
  else {
@@ -599,11 +611,12 @@ static int chmd_fast_find(struct mschm_decompressor *base,
599
611
 
600
612
  /* if we found a file, read it */
601
613
  if (result > 0) {
602
- READ_ENCINT(sec);
614
+ sec = read_encint(&p, end, &err);
603
615
  f_ptr->section = (sec == 0) ? (struct mschmd_section *) &chm->sec0
604
616
  : (struct mschmd_section *) &chm->sec1;
605
- READ_ENCINT(f_ptr->offset);
606
- READ_ENCINT(f_ptr->length);
617
+ f_ptr->offset = read_encint(&p, end, &err);
618
+ f_ptr->length = read_encint(&p, end, &err);
619
+ if (err) goto encint_err;
607
620
  }
608
621
  else if (result < 0) {
609
622
  err = MSPACK_ERR_DATAFORMAT;
@@ -612,8 +625,8 @@ static int chmd_fast_find(struct mschm_decompressor *base,
612
625
  sys->close(fh);
613
626
  return self->error = err;
614
627
 
615
- chunk_end:
616
- D(("read beyond end of chunk entries"))
628
+ encint_err:
629
+ D(("bad encint in PGMI/PGML chunk"))
617
630
  sys->close(fh);
618
631
  return self->error = MSPACK_ERR_DATAFORMAT;
619
632
  }
@@ -697,7 +710,7 @@ static int search_chunk(struct mschmd_header *chm,
697
710
  const unsigned char *start, *end, *p;
698
711
  unsigned int qr_size, num_entries, qr_entries, qr_density, name_len;
699
712
  unsigned int L, R, M, fname_len, entries_off, is_pmgl;
700
- int cmp;
713
+ int cmp, err = 0;
701
714
 
702
715
  fname_len = strlen(filename);
703
716
 
@@ -755,8 +768,8 @@ static int search_chunk(struct mschmd_header *chm,
755
768
 
756
769
  /* compare filename with entry QR points to */
757
770
  p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
758
- READ_ENCINT(name_len);
759
- if (name_len > (unsigned int) (end - p)) goto chunk_end;
771
+ name_len = read_encint(&p, end, &err);
772
+ if (err || (name_len > (unsigned int) (end - p))) goto encint_err;
760
773
  cmp = compare(filename, (char *)p, fname_len, name_len);
761
774
 
762
775
  if (cmp == 0) break;
@@ -792,8 +805,8 @@ static int search_chunk(struct mschmd_header *chm,
792
805
  */
793
806
  *result = NULL;
794
807
  while (num_entries-- > 0) {
795
- READ_ENCINT(name_len);
796
- if (name_len > (unsigned int) (end - p)) goto chunk_end;
808
+ name_len = read_encint(&p, end, &err);
809
+ if (err || (name_len > (unsigned int) (end - p))) goto encint_err;
797
810
  cmp = compare(filename, (char *)p, fname_len, name_len);
798
811
  p += name_len;
799
812
 
@@ -810,21 +823,21 @@ static int search_chunk(struct mschmd_header *chm,
810
823
 
811
824
  /* read and ignore the rest of this entry */
812
825
  if (is_pmgl) {
813
- READ_ENCINT(R); /* skip section */
814
- READ_ENCINT(R); /* skip offset */
815
- READ_ENCINT(R); /* skip length */
826
+ while (p < end && (*p++ & 0x80)); /* skip section ENCINT */
827
+ while (p < end && (*p++ & 0x80)); /* skip offset ENCINT */
828
+ while (p < end && (*p++ & 0x80)); /* skip length ENCINT */
816
829
  }
817
830
  else {
818
831
  *result = p; /* store potential final result */
819
- READ_ENCINT(R); /* skip chunk number */
832
+ while (p < end && (*p++ & 0x80)); /* skip chunk number ENCINT */
820
833
  }
821
834
  }
822
835
 
823
836
  /* PMGL? not found. PMGI? maybe found */
824
837
  return (is_pmgl) ? 0 : (*result ? 1 : 0);
825
838
 
826
- chunk_end:
827
- D(("reached end of chunk data while searching"))
839
+ encint_err:
840
+ D(("bad encint while searching"))
828
841
  return -1;
829
842
  }
830
843
 
@@ -938,14 +951,19 @@ static int chmd_extract(struct mschm_decompressor *base,
938
951
  switch (file->section->id) {
939
952
  case 0: /* Uncompressed section file */
940
953
  /* simple seek + copy */
941
- if (sys->seek(self->d->infh, file->section->chm->sec0.offset
942
- + file->offset, MSPACK_SYS_SEEK_START))
954
+ if (sys->seek(self->d->infh, chm->sec0.offset + file->offset,
955
+ MSPACK_SYS_SEEK_START))
943
956
  {
944
957
  self->error = MSPACK_ERR_SEEK;
945
958
  }
946
959
  else {
947
960
  unsigned char buf[512];
948
961
  off_t length = file->length;
962
+ off_t maxlen = chm->length - sys->tell(self->d->infh);
963
+ if (length > maxlen) {
964
+ sys->message(fh, "WARNING; file is %" LD " bytes longer than CHM file",
965
+ length - maxlen);
966
+ }
949
967
  while (length > 0) {
950
968
  int run = sizeof(buf);
951
969
  if ((off_t)run > length) run = (int)length;
@@ -963,7 +981,7 @@ static int chmd_extract(struct mschm_decompressor *base,
963
981
  break;
964
982
 
965
983
  case 1: /* MSCompressed section file */
966
- /* (re)initialise compression state if we it is not yet initialised,
984
+ /* (re)initialise compression state if not yet initialised,
967
985
  * or we have advanced too far and have to backtrack
968
986
  */
969
987
  if (!self->d->state || (file->offset < self->d->offset)) {
@@ -974,6 +992,12 @@ static int chmd_extract(struct mschm_decompressor *base,
974
992
  if (chmd_init_decomp(self, file)) break;
975
993
  }
976
994
 
995
+ /* check file offset is not impossible */
996
+ if (file->offset > self->d->length) {
997
+ self->error = MSPACK_ERR_DECRUNCH;
998
+ break;
999
+ }
1000
+
977
1001
  /* seek to input data */
978
1002
  if (sys->seek(self->d->infh, self->d->inoffset, MSPACK_SYS_SEEK_START)) {
979
1003
  self->error = MSPACK_ERR_SEEK;
@@ -988,8 +1012,15 @@ static int chmd_extract(struct mschm_decompressor *base,
988
1012
 
989
1013
  /* if getting to the correct offset was error free, unpack file */
990
1014
  if (!self->error) {
1015
+ off_t length = file->length;
1016
+ off_t maxlen = self->d->length - file->offset;
1017
+ if (length > maxlen) {
1018
+ sys->message(fh, "WARNING; file is %" LD " bytes longer than "
1019
+ "compressed section", length - maxlen);
1020
+ length = maxlen + 1; /* should decompress but still error out */
1021
+ }
991
1022
  self->d->outfh = fh;
992
- self->error = lzxd_decompress(self->d->state, file->length);
1023
+ self->error = lzxd_decompress(self->d->state, length);
993
1024
  }
994
1025
 
995
1026
  /* save offset in input source stream, in case there is a section 0
@@ -1052,8 +1083,8 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
1052
1083
  if (err) return self->error = err;
1053
1084
 
1054
1085
  /* read ControlData */
1055
- if (sec->control->length < lzxcd_SIZEOF) {
1056
- D(("ControlData file is too short"))
1086
+ if (sec->control->length != lzxcd_SIZEOF) {
1087
+ D(("ControlData file is wrong size"))
1057
1088
  return self->error = MSPACK_ERR_DATAFORMAT;
1058
1089
  }
1059
1090
  if (!(data = read_sys_file(self, sec->control))) {
@@ -1125,8 +1156,8 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
1125
1156
  entry = 0;
1126
1157
  offset = 0;
1127
1158
  err = read_spaninfo(self, sec, &length);
1159
+ if (err) return self->error = err;
1128
1160
  }
1129
- if (err) return self->error = err;
1130
1161
 
1131
1162
  /* get offset of compressed data stream:
1132
1163
  * = offset of uncompressed section from start of file
@@ -1136,6 +1167,7 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
1136
1167
 
1137
1168
  /* set start offset and overall remaining stream length */
1138
1169
  self->d->offset = entry * LZX_FRAME_SIZE;
1170
+ self->d->length = length;
1139
1171
  length -= self->d->offset;
1140
1172
 
1141
1173
  /* initialise LZX stream */
@@ -1172,6 +1204,11 @@ static int read_reset_table(struct mschm_decompressor_p *self,
1172
1204
  D(("ResetTable file is too short"))
1173
1205
  return 0;
1174
1206
  }
1207
+ if (sec->rtable->length > 1000000) { /* arbitrary upper limit */
1208
+ D(("ResetTable >1MB (%"LD"), report if genuine", sec->rtable->length))
1209
+ return 0;
1210
+ }
1211
+
1175
1212
  if (!(data = read_sys_file(self, sec->rtable))) {
1176
1213
  D(("can't read reset table"))
1177
1214
  return 0;
@@ -1246,6 +1283,12 @@ static int read_spaninfo(struct mschm_decompressor_p *self,
1246
1283
  return MSPACK_ERR_DATAFORMAT;
1247
1284
  }
1248
1285
 
1286
+ /* unconditionally set length here, because gcc -Wuninitialized isn't
1287
+ * clever enough to recognise that read_sys_file() will always set
1288
+ * self->error to a non-zero value if it returns NULL, and gcc warnings
1289
+ * spook humans (even false positives) */
1290
+ *length_ptr = 0;
1291
+
1249
1292
  /* read the SpanInfo file */
1250
1293
  if (!(data = read_sys_file(self, sec->spaninfo))) {
1251
1294
  D(("can't read SpanInfo file"))
@@ -1364,14 +1407,51 @@ static int chmd_error(struct mschm_decompressor *base) {
1364
1407
  static int read_off64(off_t *var, unsigned char *mem,
1365
1408
  struct mspack_system *sys, struct mspack_file *fh)
1366
1409
  {
1367
- #if LARGEFILE_SUPPORT
1410
+ #if SIZEOF_OFF_T >= 8
1368
1411
  *var = EndGetI64(mem);
1369
1412
  #else
1370
- *var = EndGetI32(mem);
1371
- if ((*var & 0x80000000) || EndGetI32(mem+4)) {
1372
- sys->message(fh, (char *)largefile_msg);
1413
+ if ((mem[3] & 0x80) | mem[4] | mem[5] | mem[6] | mem[7]) {
1414
+ sys->message(fh, "library not compiled to support large files.");
1373
1415
  return 1;
1374
1416
  }
1417
+ *var = EndGetI32(mem);
1375
1418
  #endif
1376
1419
  return 0;
1377
1420
  }
1421
+
1422
+ #if SIZEOF_OFF_T >= 8
1423
+ /* 63 bits allowed: 9 * 7 bits/byte, last byte must be 0x00-0x7F */
1424
+ # define ENCINT_MAX_BYTES 9
1425
+ # define ENCINT_BAD_LAST_BYTE 0x80
1426
+ #else
1427
+ /* 31 bits allowed: 5 * 7 bits/byte, last byte must be 0x00-0x07 */
1428
+ # define ENCINT_MAX_BYTES 5
1429
+ # define ENCINT_BAD_LAST_BYTE 0xF1
1430
+ #endif
1431
+
1432
+ /***************************************
1433
+ * READ_ENCINT
1434
+ ***************************************
1435
+ * Reads an ENCINT from memory. If running on a system with a 32-bit off_t,
1436
+ * ENCINTs up to 0x7FFFFFFF are accepted, values beyond that are an error.
1437
+ */
1438
+ static off_t read_encint(const unsigned char **p, const unsigned char *end,
1439
+ int *err)
1440
+ {
1441
+ off_t result = 0;
1442
+ unsigned char c = 0x80;
1443
+ int i = 0;
1444
+ while ((c & 0x80) && (i++ < ENCINT_MAX_BYTES)) {
1445
+ if (*p >= end) {
1446
+ *err = 1;
1447
+ return 0;
1448
+ }
1449
+ c = *(*p)++;
1450
+ result = (result << 7) | (c & 0x7F);
1451
+ }
1452
+ if (i == ENCINT_MAX_BYTES && (c & ENCINT_BAD_LAST_BYTE)) {
1453
+ *err = 1;
1454
+ return 0;
1455
+ }
1456
+ return result;
1457
+ }
@@ -1,5 +1,5 @@
1
1
  /* This file is part of libmspack.
2
- * (C) 2003-2011 Stuart Caie.
2
+ * (C) 2003-2023 Stuart Caie.
3
3
  *
4
4
  * KWAJ is a format very similar to SZDD. KWAJ method 3 (LZH) was
5
5
  * written by Jeff Johnson.
@@ -97,27 +97,30 @@ static struct mskwajd_header *kwajd_open(struct mskwaj_decompressor *base,
97
97
  struct mskwajd_header *hdr;
98
98
  struct mspack_system *sys;
99
99
  struct mspack_file *fh;
100
+ int err;
100
101
 
101
102
  if (!self) return NULL;
102
103
  sys = self->system;
103
104
 
104
- fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
105
- hdr = (struct mskwajd_header *) sys->alloc(sys, sizeof(struct mskwajd_header_p));
106
- if (fh && hdr) {
107
- ((struct mskwajd_header_p *) hdr)->fh = fh;
108
- self->error = kwajd_read_headers(sys, fh, hdr);
109
- }
110
- else {
111
- if (!fh) self->error = MSPACK_ERR_OPEN;
112
- if (!hdr) self->error = MSPACK_ERR_NOMEMORY;
105
+ fh = sys->open(sys, filename, MSPACK_SYS_OPEN_READ);
106
+ if (!fh) {
107
+ self->error = MSPACK_ERR_OPEN;
108
+ return NULL;
113
109
  }
114
-
115
- if (self->error) {
116
- if (fh) sys->close(fh);
117
- sys->free(hdr);
118
- hdr = NULL;
110
+
111
+ hdr = (struct mskwajd_header *) sys->alloc(sys, sizeof(struct mskwajd_header_p));
112
+ if (!hdr) {
113
+ sys->close(fh);
114
+ self->error = MSPACK_ERR_NOMEMORY;
115
+ return NULL;
119
116
  }
120
117
 
118
+ ((struct mskwajd_header_p *) hdr)->fh = fh;
119
+ if ((err = kwajd_read_headers(sys, fh, hdr))) {
120
+ kwajd_close(base, hdr);
121
+ self->error = err;
122
+ return NULL;
123
+ }
121
124
  return hdr;
122
125
  }
123
126
 
@@ -138,6 +141,8 @@ static void kwajd_close(struct mskwaj_decompressor *base,
138
141
  self->system->close(hdr_p->fh);
139
142
 
140
143
  /* free the memory associated */
144
+ self->system->free(hdr->filename);
145
+ self->system->free(hdr->extra);
141
146
  self->system->free(hdr);
142
147
 
143
148
  self->error = MSPACK_ERR_OK;
@@ -200,7 +205,7 @@ static int kwajd_read_headers(struct mspack_system *sys,
200
205
  if (hdr->headers & (MSKWAJ_HDR_HASFILENAME | MSKWAJ_HDR_HASFILEEXT)) {
201
206
  int len;
202
207
  /* allocate memory for maximum length filename */
203
- char *fn = (char *) sys->alloc(sys, (size_t) 13);
208
+ char *fn = (char *) sys->alloc(sys, 13);
204
209
  if (!(hdr->filename = fn)) return MSPACK_ERR_NOMEMORY;
205
210
 
206
211
  /* copy filename if present */
@@ -236,7 +241,7 @@ static int kwajd_read_headers(struct mspack_system *sys,
236
241
  if (hdr->headers & MSKWAJ_HDR_HASEXTRATEXT) {
237
242
  if (sys->read(fh, &buf[0], 2) != 2) return MSPACK_ERR_READ;
238
243
  i = EndGetI16(&buf[0]);
239
- hdr->extra = (char *) sys->alloc(sys, (size_t)i+1);
244
+ hdr->extra = (char *) sys->alloc(sys, i+1);
240
245
  if (! hdr->extra) return MSPACK_ERR_NOMEMORY;
241
246
  if (sys->read(fh, hdr->extra, i) != i) return MSPACK_ERR_READ;
242
247
  hdr->extra[i] = '\0';
@@ -280,7 +285,7 @@ static int kwajd_extract(struct mskwaj_decompressor *base,
280
285
  hdr->comp_type == MSKWAJ_COMP_XOR)
281
286
  {
282
287
  /* NONE is a straight copy. XOR is a copy xored with 0xFF */
283
- unsigned char *buf = (unsigned char *) sys->alloc(sys, (size_t) KWAJ_INPUT_SIZE);
288
+ unsigned char *buf = (unsigned char *) sys->alloc(sys, KWAJ_INPUT_SIZE);
284
289
  if (buf) {
285
290
  int read, i;
286
291
  while ((read = sys->read(fh, buf, KWAJ_INPUT_SIZE)) > 0) {
@@ -301,7 +306,7 @@ static int kwajd_extract(struct mskwaj_decompressor *base,
301
306
  }
302
307
  else if (hdr->comp_type == MSKWAJ_COMP_SZDD) {
303
308
  self->error = lzss_decompress(sys, fh, outfh, KWAJ_INPUT_SIZE,
304
- LZSS_MODE_EXPAND);
309
+ LZSS_MODE_QBASIC);
305
310
  }
306
311
  else if (hdr->comp_type == MSKWAJ_COMP_LZH) {
307
312
  struct kwajd_stream *lzh = lzh_init(sys, fh, outfh);
@@ -435,17 +440,14 @@ static struct kwajd_stream *lzh_init(struct mspack_system *sys,
435
440
 
436
441
  static int lzh_decompress(struct kwajd_stream *lzh)
437
442
  {
438
- register unsigned int bit_buffer;
439
- register int bits_left, i;
440
- register unsigned short sym;
441
- unsigned char *i_ptr, *i_end, lit_run = 0;
442
- int j, pos = 0, len, offset, err;
443
- unsigned int types[6];
443
+ DECLARE_HUFF_VARS;
444
+ unsigned int types[6], i, j, pos = 0, len, offset, lit_run = 0;
445
+ int err;
444
446
 
445
447
  /* reset global state */
446
448
  INIT_BITS;
447
449
  RESTORE_BITS;
448
- memset(&lzh->window[0], LZSS_WINDOW_FILL, (size_t) LZSS_WINDOW_SIZE);
450
+ memset(&lzh->window[0], LZSS_WINDOW_FILL, LZSS_WINDOW_SIZE);
449
451
 
450
452
  /* read 6 encoding types (for byte alignment) but only 5 are needed */
451
453
  for (i = 0; i < 6; i++) READ_BITS_SAFE(types[i], 4);
@@ -501,9 +503,7 @@ static int lzh_read_lens(struct kwajd_stream *lzh,
501
503
  unsigned int type, unsigned int numsyms,
502
504
  unsigned char *lens)
503
505
  {
504
- register unsigned int bit_buffer;
505
- register int bits_left;
506
- unsigned char *i_ptr, *i_end;
506
+ DECLARE_BIT_VARS;
507
507
  unsigned int i, c, sel;
508
508
  int err;
509
509