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
@@ -44,7 +44,7 @@ static int chmd_init_decomp(
44
44
  struct mschm_decompressor_p *self, struct mschmd_file *file);
45
45
  static int read_reset_table(
46
46
  struct mschm_decompressor_p *self, struct mschmd_sec_mscompressed *sec,
47
- int entry, off_t *length_ptr, off_t *offset_ptr);
47
+ unsigned int entry, off_t *length_ptr, off_t *offset_ptr);
48
48
  static int read_spaninfo(
49
49
  struct mschm_decompressor_p *self, struct mschmd_sec_mscompressed *sec,
50
50
  off_t *length_ptr);
@@ -121,7 +121,7 @@ void mspack_destroy_chm_decompressor(struct mschm_decompressor *base) {
121
121
  * Calls chmd_real_open() with entire=1.
122
122
  */
123
123
  static struct mschmd_header *chmd_open(struct mschm_decompressor *base,
124
- const char *filename)
124
+ const char *filename)
125
125
  {
126
126
  return chmd_real_open(base, filename, 1);
127
127
  }
@@ -133,7 +133,7 @@ static struct mschmd_header *chmd_open(struct mschm_decompressor *base,
133
133
  * the file headers. Calls chmd_real_open() with entire=0
134
134
  */
135
135
  static struct mschmd_header *chmd_fast_open(struct mschm_decompressor *base,
136
- const char *filename)
136
+ const char *filename)
137
137
  {
138
138
  return chmd_real_open(base, filename, 0);
139
139
  }
@@ -146,7 +146,7 @@ static struct mschmd_header *chmd_fast_open(struct mschm_decompressor *base,
146
146
  * either read all headers, or a bare mininum.
147
147
  */
148
148
  static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base,
149
- const char *filename, int entire)
149
+ const char *filename, int entire)
150
150
  {
151
151
  struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
152
152
  struct mschmd_header *chm = NULL;
@@ -162,16 +162,16 @@ static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base,
162
162
  chm->filename = filename;
163
163
  error = chmd_read_headers(sys, fh, chm, entire);
164
164
  if (error) {
165
- /* if the error is DATAFORMAT, and there are some results, return
166
- * partial results with a warning, rather than nothing */
167
- if (error == MSPACK_ERR_DATAFORMAT && (chm->files || chm->sysfiles)) {
168
- sys->message(fh, "WARNING; contents are corrupt");
169
- error = MSPACK_ERR_OK;
170
- }
171
- else {
172
- chmd_close(base, chm);
173
- chm = NULL;
174
- }
165
+ /* if the error is DATAFORMAT, and there are some results, return
166
+ * partial results with a warning, rather than nothing */
167
+ if (error == MSPACK_ERR_DATAFORMAT && (chm->files || chm->sysfiles)) {
168
+ sys->message(fh, "WARNING; contents are corrupt");
169
+ error = MSPACK_ERR_OK;
170
+ }
171
+ else {
172
+ chmd_close(base, chm);
173
+ chm = NULL;
174
+ }
175
175
  }
176
176
  self->error = error;
177
177
  }
@@ -192,7 +192,7 @@ static struct mschmd_header *chmd_real_open(struct mschm_decompressor *base,
192
192
  * frees all memory associated with a given mschmd_header
193
193
  */
194
194
  static void chmd_close(struct mschm_decompressor *base,
195
- struct mschmd_header *chm)
195
+ struct mschmd_header *chm)
196
196
  {
197
197
  struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
198
198
  struct mschmd_file *fi, *nfi;
@@ -251,16 +251,16 @@ static const unsigned char guids[32] = {
251
251
 
252
252
  /* reads an encoded integer into a variable; 7 bits of data per byte,
253
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); \
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
260
  } while (0)
261
261
 
262
262
  static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
263
- struct mschmd_header *chm, int entire)
263
+ struct mschmd_header *chm, int entire)
264
264
  {
265
265
  unsigned int section, name_len, x, errors, num_chunks;
266
266
  unsigned char buf[0x54], *chunk = NULL, *name, *p, *end;
@@ -292,7 +292,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
292
292
  }
293
293
 
294
294
  /* check both header GUIDs */
295
- if (mspack_memcmp(&buf[chmhead_GUID1], &guids[0], 32L) != 0) {
295
+ if (memcmp(&buf[chmhead_GUID1], &guids[0], 32L) != 0) {
296
296
  D(("incorrect GUIDs"))
297
297
  return MSPACK_ERR_SIGNATURE;
298
298
  }
@@ -380,15 +380,19 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
380
380
  if (chm->num_chunks > 100000) {
381
381
  D(("more than 100,000 chunks"))
382
382
  return MSPACK_ERR_DATAFORMAT;
383
- }
383
+ }
384
+ if (chm->chunk_size > 8192) {
385
+ D(("chunk size over 8192 (get in touch if this is valid)"))
386
+ return MSPACK_ERR_DATAFORMAT;
387
+ }
384
388
  if ((off_t)chm->chunk_size * (off_t)chm->num_chunks > chm->length) {
385
389
  D(("chunks larger than entire file"))
386
390
  return MSPACK_ERR_DATAFORMAT;
387
391
  }
388
392
 
389
393
  /* common sense checks on header section 1 fields */
390
- if ((chm->chunk_size & (chm->chunk_size - 1)) != 0) {
391
- sys->message(fh, "WARNING; chunk size is not a power of two");
394
+ if (chm->chunk_size != 4096) {
395
+ sys->message(fh, "WARNING; chunk size is not 4096");
392
396
  }
393
397
  if (chm->first_pmgl != 0) {
394
398
  sys->message(fh, "WARNING; first PMGL chunk is not zero");
@@ -397,7 +401,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
397
401
  D(("first pmgl chunk is after last pmgl chunk"))
398
402
  return MSPACK_ERR_DATAFORMAT;
399
403
  }
400
- if (chm->index_root != 0xFFFFFFFF && chm->index_root > chm->num_chunks) {
404
+ if (chm->index_root != 0xFFFFFFFF && chm->index_root >= chm->num_chunks) {
401
405
  D(("index_root outside valid range"))
402
406
  return MSPACK_ERR_DATAFORMAT;
403
407
  }
@@ -435,7 +439,7 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
435
439
  sys->message(fh, "WARNING; PMGL quickref area is too small");
436
440
  }
437
441
  if (EndGetI32(&chunk[pmgl_QuickRefSize]) >
438
- ((int)chm->chunk_size - pmgl_Entries))
442
+ (chm->chunk_size - pmgl_Entries))
439
443
  {
440
444
  sys->message(fh, "WARNING; PMGL quickref area is too large");
441
445
  }
@@ -445,60 +449,63 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
445
449
  num_entries = EndGetI16(end);
446
450
 
447
451
  while (num_entries--) {
448
- READ_ENCINT(name_len); name = p; p += name_len;
452
+ READ_ENCINT(name_len);
453
+ if (name_len > (unsigned int) (end - p)) goto chunk_end;
454
+ name = p; p += name_len;
449
455
  READ_ENCINT(section);
450
456
  READ_ENCINT(offset);
451
457
  READ_ENCINT(length);
452
458
 
459
+ /* ignore blank or one-char (e.g. "/") filenames we'd return as blank */
460
+ if (name_len < 2 || !name[0] || !name[1]) continue;
461
+
453
462
  /* empty files and directory names are stored as a file entry at
454
463
  * offset 0 with length 0. We want to keep empty files, but not
455
464
  * directory names, which end with a "/" */
456
465
  if ((offset == 0) && (length == 0)) {
457
- if ((name_len > 0) && (name[name_len-1] == '/')) continue;
466
+ if ((name_len > 0) && (name[name_len-1] == '/')) continue;
458
467
  }
459
468
 
460
469
  if (section > 1) {
461
- sys->message(fh, "invalid section number '%u'.", section);
462
- continue;
470
+ sys->message(fh, "invalid section number '%u'.", section);
471
+ continue;
463
472
  }
464
473
 
465
474
  if (!(fi = (struct mschmd_file *) sys->alloc(sys, sizeof(struct mschmd_file) + name_len + 1))) {
466
- sys->free(chunk);
467
- return MSPACK_ERR_NOMEMORY;
475
+ sys->free(chunk);
476
+ return MSPACK_ERR_NOMEMORY;
468
477
  }
469
478
 
470
479
  fi->next = NULL;
471
480
  fi->filename = (char *) &fi[1];
472
481
  fi->section = ((section == 0) ? (struct mschmd_section *) (&chm->sec0)
473
- : (struct mschmd_section *) (&chm->sec1));
482
+ : (struct mschmd_section *) (&chm->sec1));
474
483
  fi->offset = offset;
475
484
  fi->length = length;
476
485
  sys->copy(name, fi->filename, (size_t) name_len);
477
486
  fi->filename[name_len] = '\0';
478
487
 
479
488
  if (name[0] == ':' && name[1] == ':') {
480
- /* system file */
481
- if (mspack_memcmp(&name[2], &content_name[2], 31L) == 0) {
482
- if (mspack_memcmp(&name[33], &content_name[33], 8L) == 0) {
483
- chm->sec1.content = fi;
484
- }
485
- else if (mspack_memcmp(&name[33], &control_name[33], 11L) == 0) {
486
- chm->sec1.control = fi;
487
- }
488
- else if (mspack_memcmp(&name[33], &spaninfo_name[33], 8L) == 0) {
489
- chm->sec1.spaninfo = fi;
490
- }
491
- else if (mspack_memcmp(&name[33], &rtable_name[33], 72L) == 0) {
492
- chm->sec1.rtable = fi;
493
- }
494
- }
495
- fi->next = chm->sysfiles;
496
- chm->sysfiles = fi;
489
+ /* system file */
490
+ if (name_len == 40 && memcmp(name, content_name, 40) == 0) {
491
+ chm->sec1.content = fi;
492
+ }
493
+ else if (name_len == 44 && memcmp(name, control_name, 44) == 0) {
494
+ chm->sec1.control = fi;
495
+ }
496
+ else if (name_len == 41 && memcmp(name, spaninfo_name, 41) == 0) {
497
+ chm->sec1.spaninfo = fi;
498
+ }
499
+ else if (name_len == 105 && memcmp(name, rtable_name, 105) == 0) {
500
+ chm->sec1.rtable = fi;
501
+ }
502
+ fi->next = chm->sysfiles;
503
+ chm->sysfiles = fi;
497
504
  }
498
505
  else {
499
- /* normal file */
500
- if (link) link->next = fi; else chm->files = fi;
501
- link = fi;
506
+ /* normal file */
507
+ if (link) link->next = fi; else chm->files = fi;
508
+ link = fi;
502
509
  }
503
510
  }
504
511
 
@@ -522,21 +529,24 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh,
522
529
  * directly from the on-disk index.
523
530
  *
524
531
  * TODO: protect against infinite loops in chunks (where pgml_NextChunk
525
- * or a PGMI index entry point to an already visited chunk)
532
+ * or a PMGI index entry point to an already visited chunk)
526
533
  */
527
534
  static int chmd_fast_find(struct mschm_decompressor *base,
528
- struct mschmd_header *chm, const char *filename,
529
- struct mschmd_file *f_ptr, int f_size)
535
+ struct mschmd_header *chm, const char *filename,
536
+ struct mschmd_file *f_ptr, int f_size)
530
537
  {
531
538
  struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
532
539
  struct mspack_system *sys;
533
540
  struct mspack_file *fh;
534
- const unsigned char *chunk, *p, *end;
541
+ /* p and end are initialised to prevent MSVC warning about "potentially"
542
+ * uninitialised usage. This is provably untrue, but MS won't fix:
543
+ * https://developercommunity.visualstudio.com/content/problem/363489/c4701-false-positive-warning.html */
544
+ const unsigned char *chunk, *p = NULL, *end = NULL;
535
545
  int err = MSPACK_ERR_OK, result = -1;
536
546
  unsigned int n, sec;
537
547
 
538
548
  if (!self || !chm || !f_ptr || (f_size != sizeof(struct mschmd_file))) {
539
- return MSPACK_ERR_ARGS;
549
+ return MSPACK_ERR_ARGS;
540
550
  }
541
551
  sys = self->system;
542
552
 
@@ -544,59 +554,59 @@ static int chmd_fast_find(struct mschm_decompressor *base,
544
554
  memset(f_ptr, 0, f_size);
545
555
 
546
556
  if (!(fh = sys->open(sys, chm->filename, MSPACK_SYS_OPEN_READ))) {
547
- return MSPACK_ERR_OPEN;
557
+ return MSPACK_ERR_OPEN;
548
558
  }
549
559
 
550
560
  /* go through PMGI chunk hierarchy to reach PMGL chunk */
551
561
  if (chm->index_root < chm->num_chunks) {
552
- n = chm->index_root;
553
- for (;;) {
554
- if (!(chunk = read_chunk(self, chm, fh, n))) {
555
- sys->close(fh);
556
- return self->error;
557
- }
558
-
559
- /* search PMGI/PMGL chunk. exit early if no entry found */
560
- if ((result = search_chunk(chm, chunk, filename, &p, &end)) <= 0) {
561
- break;
562
- }
563
-
564
- /* found result. loop around for next chunk if this is PMGI */
565
- if (chunk[3] == 0x4C) break; else READ_ENCINT(n);
566
- }
562
+ n = chm->index_root;
563
+ for (;;) {
564
+ if (!(chunk = read_chunk(self, chm, fh, n))) {
565
+ sys->close(fh);
566
+ return self->error;
567
+ }
568
+
569
+ /* search PMGI/PMGL chunk. exit early if no entry found */
570
+ if ((result = search_chunk(chm, chunk, filename, &p, &end)) <= 0) {
571
+ break;
572
+ }
573
+
574
+ /* found result. loop around for next chunk if this is PMGI */
575
+ if (chunk[3] == 0x4C) break; else READ_ENCINT(n);
576
+ }
567
577
  }
568
578
  else {
569
- /* PMGL chunks only, search from first_pmgl to last_pmgl */
570
- for (n = chm->first_pmgl; n <= chm->last_pmgl;
571
- n = EndGetI32(&chunk[pmgl_NextChunk]))
572
- {
573
- if (!(chunk = read_chunk(self, chm, fh, n))) {
574
- err = self->error;
575
- break;
576
- }
577
-
578
- /* search PMGL chunk. exit if file found */
579
- if ((result = search_chunk(chm, chunk, filename, &p, &end)) > 0) {
580
- break;
581
- }
579
+ /* PMGL chunks only, search from first_pmgl to last_pmgl */
580
+ for (n = chm->first_pmgl; n <= chm->last_pmgl;
581
+ n = EndGetI32(&chunk[pmgl_NextChunk]))
582
+ {
583
+ if (!(chunk = read_chunk(self, chm, fh, n))) {
584
+ err = self->error;
585
+ break;
586
+ }
587
+
588
+ /* search PMGL chunk. exit if file found */
589
+ if ((result = search_chunk(chm, chunk, filename, &p, &end)) > 0) {
590
+ break;
591
+ }
582
592
 
583
593
  /* stop simple infinite loops: can't visit the same chunk twice */
584
- if ((int)n == EndGetI32(&chunk[pmgl_NextChunk])) {
594
+ if (n == EndGetI32(&chunk[pmgl_NextChunk])) {
585
595
  break;
586
596
  }
587
- }
597
+ }
588
598
  }
589
599
 
590
600
  /* if we found a file, read it */
591
601
  if (result > 0) {
592
- READ_ENCINT(sec);
593
- f_ptr->section = (sec == 0) ? (struct mschmd_section *) &chm->sec0
594
- : (struct mschmd_section *) &chm->sec1;
595
- READ_ENCINT(f_ptr->offset);
596
- READ_ENCINT(f_ptr->length);
602
+ READ_ENCINT(sec);
603
+ f_ptr->section = (sec == 0) ? (struct mschmd_section *) &chm->sec0
604
+ : (struct mschmd_section *) &chm->sec1;
605
+ READ_ENCINT(f_ptr->offset);
606
+ READ_ENCINT(f_ptr->length);
597
607
  }
598
608
  else if (result < 0) {
599
- err = MSPACK_ERR_DATAFORMAT;
609
+ err = MSPACK_ERR_DATAFORMAT;
600
610
  }
601
611
 
602
612
  sys->close(fh);
@@ -612,24 +622,24 @@ static int chmd_fast_find(struct mschm_decompressor *base,
612
622
  * so it doesn't need to be read from disk more than once
613
623
  */
614
624
  static unsigned char *read_chunk(struct mschm_decompressor_p *self,
615
- struct mschmd_header *chm,
616
- struct mspack_file *fh,
617
- unsigned int chunk_num)
625
+ struct mschmd_header *chm,
626
+ struct mspack_file *fh,
627
+ unsigned int chunk_num)
618
628
  {
619
629
  struct mspack_system *sys = self->system;
620
630
  unsigned char *buf;
621
631
 
622
632
  /* check arguments - most are already checked by chmd_fast_find */
623
- if (chunk_num > chm->num_chunks) return NULL;
633
+ if (chunk_num >= chm->num_chunks) return NULL;
624
634
 
625
635
  /* ensure chunk cache is available */
626
636
  if (!chm->chunk_cache) {
627
- size_t size = sizeof(unsigned char *) * chm->num_chunks;
628
- if (!(chm->chunk_cache = (unsigned char **) sys->alloc(sys, size))) {
629
- self->error = MSPACK_ERR_NOMEMORY;
630
- return NULL;
631
- }
632
- memset(chm->chunk_cache, 0, size);
637
+ size_t size = sizeof(unsigned char *) * chm->num_chunks;
638
+ if (!(chm->chunk_cache = (unsigned char **) sys->alloc(sys, size))) {
639
+ self->error = MSPACK_ERR_NOMEMORY;
640
+ return NULL;
641
+ }
642
+ memset(chm->chunk_cache, 0, size);
633
643
  }
634
644
 
635
645
  /* try to answer out of chunk cache */
@@ -637,31 +647,31 @@ static unsigned char *read_chunk(struct mschm_decompressor_p *self,
637
647
 
638
648
  /* need to read chunk - allocate memory for it */
639
649
  if (!(buf = (unsigned char *) sys->alloc(sys, chm->chunk_size))) {
640
- self->error = MSPACK_ERR_NOMEMORY;
641
- return NULL;
650
+ self->error = MSPACK_ERR_NOMEMORY;
651
+ return NULL;
642
652
  }
643
653
 
644
654
  /* seek to block and read it */
645
655
  if (sys->seek(fh, (off_t) (chm->dir_offset + (chunk_num * chm->chunk_size)),
646
- MSPACK_SYS_SEEK_START))
656
+ MSPACK_SYS_SEEK_START))
647
657
  {
648
- self->error = MSPACK_ERR_SEEK;
649
- sys->free(buf);
650
- return NULL;
658
+ self->error = MSPACK_ERR_SEEK;
659
+ sys->free(buf);
660
+ return NULL;
651
661
  }
652
662
  if (sys->read(fh, buf, (int)chm->chunk_size) != (int)chm->chunk_size) {
653
- self->error = MSPACK_ERR_READ;
654
- sys->free(buf);
655
- return NULL;
663
+ self->error = MSPACK_ERR_READ;
664
+ sys->free(buf);
665
+ return NULL;
656
666
  }
657
667
 
658
668
  /* check the signature. Is is PMGL or PMGI? */
659
669
  if (!((buf[0] == 0x50) && (buf[1] == 0x4D) && (buf[2] == 0x47) &&
660
- ((buf[3] == 0x4C) || (buf[3] == 0x49))))
670
+ ((buf[3] == 0x4C) || (buf[3] == 0x49))))
661
671
  {
662
- self->error = MSPACK_ERR_SEEK;
663
- sys->free(buf);
664
- return NULL;
672
+ self->error = MSPACK_ERR_SEEK;
673
+ sys->free(buf);
674
+ return NULL;
665
675
  }
666
676
 
667
677
  /* all OK. Store chunk in cache and return it */
@@ -679,10 +689,10 @@ static unsigned char *read_chunk(struct mschm_decompressor_p *self,
679
689
  * chunk that may eventually contain that entry has been found.
680
690
  */
681
691
  static int search_chunk(struct mschmd_header *chm,
682
- const unsigned char *chunk,
683
- const char *filename,
684
- const unsigned char **result,
685
- const unsigned char **result_end)
692
+ const unsigned char *chunk,
693
+ const char *filename,
694
+ const unsigned char **result,
695
+ const unsigned char **result_end)
686
696
  {
687
697
  const unsigned char *start, *end, *p;
688
698
  unsigned int qr_size, num_entries, qr_entries, qr_density, name_len;
@@ -694,12 +704,12 @@ static int search_chunk(struct mschmd_header *chm,
694
704
  /* PMGL chunk or PMGI chunk? (note: read_chunk() has already
695
705
  * checked the rest of the characters in the chunk signature) */
696
706
  if (chunk[3] == 0x4C) {
697
- is_pmgl = 1;
698
- entries_off = pmgl_Entries;
707
+ is_pmgl = 1;
708
+ entries_off = pmgl_Entries;
699
709
  }
700
710
  else {
701
- is_pmgl = 0;
702
- entries_off = pmgi_Entries;
711
+ is_pmgl = 0;
712
+ entries_off = pmgi_Entries;
703
713
  }
704
714
 
705
715
  /* Step 1: binary search first filename of each QR entry
@@ -720,55 +730,55 @@ static int search_chunk(struct mschmd_header *chm,
720
730
  qr_entries = (num_entries + qr_density-1) / qr_density;
721
731
 
722
732
  if (num_entries == 0) {
723
- D(("chunk has no entries"))
724
- return -1;
733
+ D(("chunk has no entries"))
734
+ return -1;
725
735
  }
726
736
 
727
737
  if (qr_size > chm->chunk_size) {
728
- D(("quickref size > chunk size"))
729
- return -1;
738
+ D(("quickref size > chunk size"))
739
+ return -1;
730
740
  }
731
741
 
732
742
  *result_end = end;
733
743
 
734
744
  if (((int)qr_entries * 2) > (start - end)) {
735
- D(("WARNING; more quickrefs than quickref space"))
736
- qr_entries = 0; /* but we can live with it */
745
+ D(("WARNING; more quickrefs than quickref space"))
746
+ qr_entries = 0; /* but we can live with it */
737
747
  }
738
748
 
739
749
  if (qr_entries > 0) {
740
- L = 0;
741
- R = qr_entries - 1;
742
- do {
743
- /* pick new midpoint */
744
- M = (L + R) >> 1;
745
-
746
- /* compare filename with entry QR points to */
747
- p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
748
- READ_ENCINT(name_len);
749
- if (p + name_len > end) goto chunk_end;
750
- cmp = compare(filename, (char *)p, fname_len, name_len);
751
-
752
- if (cmp == 0) break;
753
- else if (cmp < 0) { if (M) R = M - 1; else return 0; }
754
- else if (cmp > 0) L = M + 1;
755
- } while (L <= R);
756
- M = (L + R) >> 1;
757
-
758
- if (cmp == 0) {
759
- /* exact match! */
760
- p += name_len;
761
- *result = p;
762
- return 1;
763
- }
764
-
765
- /* otherwise, read the group of entries for QR entry M */
766
- p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
767
- num_entries -= (M * qr_density);
768
- if (num_entries > qr_density) num_entries = qr_density;
750
+ L = 0;
751
+ R = qr_entries - 1;
752
+ do {
753
+ /* pick new midpoint */
754
+ M = (L + R) >> 1;
755
+
756
+ /* compare filename with entry QR points to */
757
+ 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;
760
+ cmp = compare(filename, (char *)p, fname_len, name_len);
761
+
762
+ if (cmp == 0) break;
763
+ else if (cmp < 0) { if (M) R = M - 1; else return 0; }
764
+ else if (cmp > 0) L = M + 1;
765
+ } while (L <= R);
766
+ M = (L + R) >> 1;
767
+
768
+ if (cmp == 0) {
769
+ /* exact match! */
770
+ p += name_len;
771
+ *result = p;
772
+ return 1;
773
+ }
774
+
775
+ /* otherwise, read the group of entries for QR entry M */
776
+ p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)];
777
+ num_entries -= (M * qr_density);
778
+ if (num_entries > qr_density) num_entries = qr_density;
769
779
  }
770
780
  else {
771
- p = &chunk[entries_off];
781
+ p = &chunk[entries_off];
772
782
  }
773
783
 
774
784
  /* Step 2: linear search through the set of entries reached in step 1.
@@ -782,32 +792,32 @@ static int search_chunk(struct mschmd_header *chm,
782
792
  */
783
793
  *result = NULL;
784
794
  while (num_entries-- > 0) {
785
- READ_ENCINT(name_len);
786
- if (p + name_len > end) goto chunk_end;
787
- cmp = compare(filename, (char *)p, fname_len, name_len);
788
- p += name_len;
789
-
790
- if (cmp == 0) {
791
- /* entry found */
792
- *result = p;
793
- return 1;
794
- }
795
-
796
- if (cmp < 0) {
797
- /* entry not found (PMGL) / maybe found (PMGI) */
798
- break;
799
- }
800
-
801
- /* read and ignore the rest of this entry */
802
- if (is_pmgl) {
803
- READ_ENCINT(R); /* skip section */
804
- READ_ENCINT(R); /* skip offset */
805
- READ_ENCINT(R); /* skip length */
806
- }
807
- else {
808
- *result = p; /* store potential final result */
809
- READ_ENCINT(R); /* skip chunk number */
810
- }
795
+ READ_ENCINT(name_len);
796
+ if (name_len > (unsigned int) (end - p)) goto chunk_end;
797
+ cmp = compare(filename, (char *)p, fname_len, name_len);
798
+ p += name_len;
799
+
800
+ if (cmp == 0) {
801
+ /* entry found */
802
+ *result = p;
803
+ return 1;
804
+ }
805
+
806
+ if (cmp < 0) {
807
+ /* entry not found (PMGL) / maybe found (PMGI) */
808
+ break;
809
+ }
810
+
811
+ /* read and ignore the rest of this entry */
812
+ if (is_pmgl) {
813
+ READ_ENCINT(R); /* skip section */
814
+ READ_ENCINT(R); /* skip offset */
815
+ READ_ENCINT(R); /* skip length */
816
+ }
817
+ else {
818
+ *result = p; /* store potential final result */
819
+ READ_ENCINT(R); /* skip chunk number */
820
+ }
811
821
  }
812
822
 
813
823
  /* PMGL? not found. PMGI? maybe found */
@@ -819,66 +829,34 @@ static int search_chunk(struct mschmd_header *chm,
819
829
  }
820
830
 
821
831
  #if HAVE_TOWLOWER
822
- # if HAVE_WCTYPE_H
823
- # include <wctype.h>
824
- # endif
832
+ # include <wctype.h>
825
833
  # define TOLOWER(x) towlower(x)
826
- #elif HAVE_TOLOWER
827
- # if HAVE_CTYPE_H
828
- # include <ctype.h>
829
- # endif
830
- # define TOLOWER(x) tolower(x)
831
834
  #else
832
- # define TOLOWER(x) (((x)<0||(x)>256)?(x):mspack_tolower_map[(x)])
833
- /* Map of char -> lowercase char for the first 256 chars. Generated with:
834
- * LC_CTYPE=en_GB.utf-8 perl -Mlocale -le 'print map{ord(lc chr).","} 0..255'
835
- */
836
- static const unsigned char mspack_tolower_map[256] = {
837
- 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,
838
- 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,
839
- 53,54,55,56,57,58,59,60,61,62,63,64,97,98,99,100,101,102,103,104,105,106,
840
- 107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,91,92,93,94,
841
- 95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,
842
- 115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,
843
- 134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,
844
- 153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,
845
- 172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,
846
- 191,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,
847
- 242,243,244,245,246,215,248,249,250,251,252,253,254,223,224,225,226,227,228,
848
- 229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,
849
- 248,249,250,251,252,253,254,255
850
- };
835
+ # include <ctype.h>
836
+ # define TOLOWER(x) tolower(x)
851
837
  #endif
852
838
 
853
- /* decodes a UTF-8 character from s[] into c. Will not read past e. */
854
- #define GET_UTF8_CHAR(s, e, c) do { \
855
- unsigned char x = *s++; \
856
- if (x < 0x80) c = x; \
857
- else if (x < 0xC0) c = -1; \
858
- else if (x < 0xE0) { \
859
- c = (s >= e) ? -1 : ((x & 0x1F) << 6) | (*s++ & 0x3F); \
860
- } \
861
- else if (x < 0xF0) { \
862
- c = (s+2 > e) ? -1 : ((x & 0x0F) << 12) | ((s[0] & 0x3F) << 6) \
863
- | (s[1] & 0x3F); \
864
- s += 2; \
865
- } \
866
- else if (x < 0xF8) { \
867
- c = (s+3 > e) ? -1 : ((x & 0x07) << 18) | ((s[0] & 0x3F) << 12) \
868
- | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F); \
869
- s += 3; \
870
- } \
871
- else if (x < 0xFC) { \
872
- c = (s+4 > e) ? -1 : ((x & 0x03) << 24) | ((s[0] & 0x3F) << 18) \
873
- | ((s[1] & 0x3F) << 12)|((s[2] & 0x3F) << 6)|(s[3] & 0x3F); \
874
- s += 4; \
875
- } \
876
- else if (x < 0xFE) { \
877
- c = (s+5>e)?-1:((x&1)<<30)|((s[0]&0x3F)<<24)|((s[1]&0x3F)<<18)| \
878
- ((s[2] & 0x3F) << 12) | ((s[3] & 0x3F) << 6)|(s[4] & 0x3F); \
879
- s += 5; \
880
- } \
881
- else c = -1; \
839
+ /* decodes a UTF-8 character from s[] into c. Will not read past e.
840
+ * doesn't test that extension bytes are %10xxxxxx.
841
+ * allows some overlong encodings.
842
+ */
843
+ #define GET_UTF8_CHAR(s, e, c) do { \
844
+ unsigned char x = *s++; \
845
+ if (x < 0x80) c = x; \
846
+ else if (x >= 0xC2 && x < 0xE0 && s < e) { \
847
+ c = (x & 0x1F) << 6 | (*s++ & 0x3F); \
848
+ } \
849
+ else if (x >= 0xE0 && x < 0xF0 && s+1 < e) { \
850
+ c = (x & 0x0F) << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); \
851
+ s += 2; \
852
+ } \
853
+ else if (x >= 0xF0 && x <= 0xF5 && s+2 < e) { \
854
+ c = (x & 0x07) << 18 | (s[0] & 0x3F) << 12 | \
855
+ (s[1] & 0x3F) << 6 | (s[2] & 0x3F); \
856
+ if (c > 0x10FFFF) c = 0xFFFD; \
857
+ s += 3; \
858
+ } \
859
+ else c = 0xFFFD; \
882
860
  } while (0)
883
861
 
884
862
  /* case-insensitively compares two UTF8 encoded strings. String length for
@@ -890,12 +868,12 @@ static inline int compare(const char *s1, const char *s2, int l1, int l2) {
890
868
  int c1, c2;
891
869
 
892
870
  while (p1 < e1 && p2 < e2) {
893
- GET_UTF8_CHAR(p1, e1, c1);
894
- GET_UTF8_CHAR(p2, e2, c2);
895
- if (c1 == c2) continue;
896
- c1 = TOLOWER(c1);
897
- c2 = TOLOWER(c2);
898
- if (c1 != c2) return c1 - c2;
871
+ GET_UTF8_CHAR(p1, e1, c1);
872
+ GET_UTF8_CHAR(p2, e2, c2);
873
+ if (c1 == c2) continue;
874
+ c1 = TOLOWER(c1);
875
+ c2 = TOLOWER(c2);
876
+ if (c1 != c2) return c1 - c2;
899
877
  }
900
878
  return l1 - l2;
901
879
  }
@@ -907,7 +885,7 @@ static inline int compare(const char *s1, const char *s2, int l1, int l2) {
907
885
  * extracts a file from a CHM helpfile
908
886
  */
909
887
  static int chmd_extract(struct mschm_decompressor *base,
910
- struct mschmd_file *file, const char *filename)
888
+ struct mschmd_file *file, const char *filename)
911
889
  {
912
890
  struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base;
913
891
  struct mspack_system *sys;
@@ -961,7 +939,7 @@ static int chmd_extract(struct mschm_decompressor *base,
961
939
  case 0: /* Uncompressed section file */
962
940
  /* simple seek + copy */
963
941
  if (sys->seek(self->d->infh, file->section->chm->sec0.offset
964
- + file->offset, MSPACK_SYS_SEEK_START))
942
+ + file->offset, MSPACK_SYS_SEEK_START))
965
943
  {
966
944
  self->error = MSPACK_ERR_SEEK;
967
945
  }
@@ -969,17 +947,17 @@ static int chmd_extract(struct mschm_decompressor *base,
969
947
  unsigned char buf[512];
970
948
  off_t length = file->length;
971
949
  while (length > 0) {
972
- int run = sizeof(buf);
973
- if ((off_t)run > length) run = (int)length;
974
- if (sys->read(self->d->infh, &buf[0], run) != run) {
975
- self->error = MSPACK_ERR_READ;
976
- break;
977
- }
978
- if (sys->write(fh, &buf[0], run) != run) {
979
- self->error = MSPACK_ERR_WRITE;
980
- break;
981
- }
982
- length -= run;
950
+ int run = sizeof(buf);
951
+ if ((off_t)run > length) run = (int)length;
952
+ if (sys->read(self->d->infh, &buf[0], run) != run) {
953
+ self->error = MSPACK_ERR_READ;
954
+ break;
955
+ }
956
+ if (sys->write(fh, &buf[0], run) != run) {
957
+ self->error = MSPACK_ERR_WRITE;
958
+ break;
959
+ }
960
+ length -= run;
983
961
  }
984
962
  }
985
963
  break;
@@ -990,8 +968,8 @@ static int chmd_extract(struct mschm_decompressor *base,
990
968
  */
991
969
  if (!self->d->state || (file->offset < self->d->offset)) {
992
970
  if (self->d->state) {
993
- lzxd_free(self->d->state);
994
- self->d->state = NULL;
971
+ lzxd_free(self->d->state);
972
+ self->d->state = NULL;
995
973
  }
996
974
  if (chmd_init_decomp(self, file)) break;
997
975
  }
@@ -1055,7 +1033,7 @@ static int chmd_sys_write(struct mspack_file *file, void *buffer, int bytes) {
1055
1033
  * file.
1056
1034
  */
1057
1035
  static int chmd_init_decomp(struct mschm_decompressor_p *self,
1058
- struct mschmd_file *file)
1036
+ struct mschmd_file *file)
1059
1037
  {
1060
1038
  int window_size, window_bits, reset_interval, entry, err;
1061
1039
  struct mspack_system *sys = self->system;
@@ -1123,7 +1101,7 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
1123
1101
  }
1124
1102
 
1125
1103
  /* validate reset_interval */
1126
- if (reset_interval % LZX_FRAME_SIZE) {
1104
+ if (reset_interval == 0 || reset_interval % LZX_FRAME_SIZE) {
1127
1105
  D(("bad controldata reset interval"))
1128
1106
  return self->error = MSPACK_ERR_DATAFORMAT;
1129
1107
  }
@@ -1162,9 +1140,9 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
1162
1140
 
1163
1141
  /* initialise LZX stream */
1164
1142
  self->d->state = lzxd_init(&self->d->sys, self->d->infh,
1165
- (struct mspack_file *) self, window_bits,
1166
- reset_interval / LZX_FRAME_SIZE,
1167
- 4096, length, 0);
1143
+ (struct mspack_file *) self, window_bits,
1144
+ reset_interval / LZX_FRAME_SIZE,
1145
+ 4096, length, 0);
1168
1146
  if (!self->d->state) self->error = MSPACK_ERR_NOMEMORY;
1169
1147
  return self->error;
1170
1148
  }
@@ -1177,8 +1155,9 @@ static int chmd_init_decomp(struct mschm_decompressor_p *self,
1177
1155
  * Returns non-zero for success, zero for failure.
1178
1156
  */
1179
1157
  static int read_reset_table(struct mschm_decompressor_p *self,
1180
- struct mschmd_sec_mscompressed *sec,
1181
- int entry, off_t *length_ptr, off_t *offset_ptr)
1158
+ struct mschmd_sec_mscompressed *sec,
1159
+ unsigned int entry,
1160
+ off_t *length_ptr, off_t *offset_ptr)
1182
1161
  {
1183
1162
  struct mspack_system *sys = self->system;
1184
1163
  unsigned char *data;
@@ -1190,25 +1169,25 @@ static int read_reset_table(struct mschm_decompressor_p *self,
1190
1169
 
1191
1170
  /* read ResetTable file */
1192
1171
  if (sec->rtable->length < lzxrt_headerSIZEOF) {
1193
- D(("ResetTable file is too short"))
1194
- return 0;
1172
+ D(("ResetTable file is too short"))
1173
+ return 0;
1195
1174
  }
1196
1175
  if (!(data = read_sys_file(self, sec->rtable))) {
1197
- D(("can't read reset table"))
1198
- return 0;
1176
+ D(("can't read reset table"))
1177
+ return 0;
1199
1178
  }
1200
1179
 
1201
1180
  /* check sanity of reset table */
1202
1181
  if (EndGetI32(&data[lzxrt_FrameLen]) != LZX_FRAME_SIZE) {
1203
- D(("bad reset table frame length"))
1204
- sys->free(data);
1205
- return 0;
1182
+ D(("bad reset table frame length"))
1183
+ sys->free(data);
1184
+ return 0;
1206
1185
  }
1207
1186
 
1208
1187
  /* get the uncompressed length of the LZX stream */
1209
1188
  if (read_off64(length_ptr, &data[lzxrt_UncompLen], sys, self->d->infh)) {
1210
- sys->free(data);
1211
- return 0;
1189
+ sys->free(data);
1190
+ return 0;
1212
1191
  }
1213
1192
 
1214
1193
  entrysize = EndGetI32(&data[lzxrt_EntrySize]);
@@ -1216,25 +1195,25 @@ static int read_reset_table(struct mschm_decompressor_p *self,
1216
1195
 
1217
1196
  /* ensure reset table entry for this offset exists */
1218
1197
  if (entry < EndGetI32(&data[lzxrt_NumEntries]) &&
1219
- pos <= (sec->rtable->length - entrysize))
1198
+ pos <= (sec->rtable->length - entrysize))
1220
1199
  {
1221
- switch (entrysize) {
1222
- case 4:
1223
- *offset_ptr = EndGetI32(&data[pos]);
1224
- err = 0;
1225
- break;
1226
- case 8:
1227
- err = read_off64(offset_ptr, &data[pos], sys, self->d->infh);
1228
- break;
1229
- default:
1230
- D(("reset table entry size neither 4 nor 8"))
1231
- err = 1;
1232
- break;
1233
- }
1200
+ switch (entrysize) {
1201
+ case 4:
1202
+ *offset_ptr = EndGetI32(&data[pos]);
1203
+ err = 0;
1204
+ break;
1205
+ case 8:
1206
+ err = read_off64(offset_ptr, &data[pos], sys, self->d->infh);
1207
+ break;
1208
+ default:
1209
+ D(("reset table entry size neither 4 nor 8"))
1210
+ err = 1;
1211
+ break;
1212
+ }
1234
1213
  }
1235
1214
  else {
1236
- D(("bad reset interval"))
1237
- err = 1;
1215
+ D(("bad reset interval"))
1216
+ err = 1;
1238
1217
  }
1239
1218
 
1240
1219
  /* free the reset table */
@@ -1251,8 +1230,8 @@ static int read_reset_table(struct mschm_decompressor_p *self,
1251
1230
  * Returns zero for success or a non-zero error code for failure.
1252
1231
  */
1253
1232
  static int read_spaninfo(struct mschm_decompressor_p *self,
1254
- struct mschmd_sec_mscompressed *sec,
1255
- off_t *length_ptr)
1233
+ struct mschmd_sec_mscompressed *sec,
1234
+ off_t *length_ptr)
1256
1235
  {
1257
1236
  struct mspack_system *sys = self->system;
1258
1237
  unsigned char *data;
@@ -1263,21 +1242,27 @@ static int read_spaninfo(struct mschm_decompressor_p *self,
1263
1242
 
1264
1243
  /* check it's large enough */
1265
1244
  if (sec->spaninfo->length != 8) {
1266
- D(("SpanInfo file is wrong size"))
1267
- return MSPACK_ERR_DATAFORMAT;
1245
+ D(("SpanInfo file is wrong size"))
1246
+ return MSPACK_ERR_DATAFORMAT;
1268
1247
  }
1269
1248
 
1270
1249
  /* read the SpanInfo file */
1271
1250
  if (!(data = read_sys_file(self, sec->spaninfo))) {
1272
- D(("can't read SpanInfo file"))
1273
- return self->error;
1251
+ D(("can't read SpanInfo file"))
1252
+ return self->error;
1274
1253
  }
1275
1254
 
1276
1255
  /* get the uncompressed length of the LZX stream */
1277
1256
  err = read_off64(length_ptr, data, sys, self->d->infh);
1278
-
1279
1257
  sys->free(data);
1280
- return (err) ? MSPACK_ERR_DATAFORMAT : MSPACK_ERR_OK;
1258
+ if (err) return MSPACK_ERR_DATAFORMAT;
1259
+
1260
+ if (*length_ptr <= 0) {
1261
+ D(("output length is invalid"))
1262
+ return MSPACK_ERR_DATAFORMAT;
1263
+ }
1264
+
1265
+ return MSPACK_ERR_OK;
1281
1266
  }
1282
1267
 
1283
1268
  /***************************************
@@ -1288,8 +1273,8 @@ static int read_spaninfo(struct mschm_decompressor_p *self,
1288
1273
  * for success, non-zero for both failure and the file not existing.
1289
1274
  */
1290
1275
  static int find_sys_file(struct mschm_decompressor_p *self,
1291
- struct mschmd_sec_mscompressed *sec,
1292
- struct mschmd_file **f_ptr, const char *name)
1276
+ struct mschmd_sec_mscompressed *sec,
1277
+ struct mschmd_file **f_ptr, const char *name)
1293
1278
  {
1294
1279
  struct mspack_system *sys = self->system;
1295
1280
  struct mschmd_file result;
@@ -1300,13 +1285,13 @@ static int find_sys_file(struct mschm_decompressor_p *self,
1300
1285
  /* try using fast_find to find the file - return DATAFORMAT error if
1301
1286
  * it fails, or successfully doesn't find the file */
1302
1287
  if (chmd_fast_find((struct mschm_decompressor *) self, sec->base.chm,
1303
- name, &result, (int)sizeof(result)) || !result.section)
1288
+ name, &result, (int)sizeof(result)) || !result.section)
1304
1289
  {
1305
- return MSPACK_ERR_DATAFORMAT;
1290
+ return MSPACK_ERR_DATAFORMAT;
1306
1291
  }
1307
1292
 
1308
1293
  if (!(*f_ptr = (struct mschmd_file *) sys->alloc(sys, sizeof(result)))) {
1309
- return MSPACK_ERR_NOMEMORY;
1294
+ return MSPACK_ERR_NOMEMORY;
1310
1295
  }
1311
1296
 
1312
1297
  /* copy result */
@@ -1326,7 +1311,7 @@ static int find_sys_file(struct mschm_decompressor_p *self,
1326
1311
  * memory.
1327
1312
  */
1328
1313
  static unsigned char *read_sys_file(struct mschm_decompressor_p *self,
1329
- struct mschmd_file *file)
1314
+ struct mschmd_file *file)
1330
1315
  {
1331
1316
  struct mspack_system *sys = self->system;
1332
1317
  unsigned char *data = NULL;
@@ -1344,7 +1329,7 @@ static unsigned char *read_sys_file(struct mschm_decompressor_p *self,
1344
1329
  return NULL;
1345
1330
  }
1346
1331
  if (sys->seek(self->d->infh, file->section->chm->sec0.offset
1347
- + file->offset, MSPACK_SYS_SEEK_START))
1332
+ + file->offset, MSPACK_SYS_SEEK_START))
1348
1333
  {
1349
1334
  self->error = MSPACK_ERR_SEEK;
1350
1335
  sys->free(data);
@@ -1377,15 +1362,15 @@ static int chmd_error(struct mschm_decompressor *base) {
1377
1362
  * are accepted, offsets beyond that cause an error message.
1378
1363
  */
1379
1364
  static int read_off64(off_t *var, unsigned char *mem,
1380
- struct mspack_system *sys, struct mspack_file *fh)
1365
+ struct mspack_system *sys, struct mspack_file *fh)
1381
1366
  {
1382
- #ifdef LARGEFILE_SUPPORT
1367
+ #if LARGEFILE_SUPPORT
1383
1368
  *var = EndGetI64(mem);
1384
1369
  #else
1385
1370
  *var = EndGetI32(mem);
1386
1371
  if ((*var & 0x80000000) || EndGetI32(mem+4)) {
1387
- sys->message(fh, (char *)largefile_msg);
1388
- return 1;
1372
+ sys->message(fh, (char *)largefile_msg);
1373
+ return 1;
1389
1374
  }
1390
1375
  #endif
1391
1376
  return 0;