libmspack 0.0.5 → 0.10.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.github/workflows/rake.yml +37 -0
- data/.gitignore +2 -0
- data/.yardopts +1 -1
- data/README.md +1 -1
- data/Rakefile +11 -5
- data/ext/Rakefile +1 -1
- data/ext/libmspack/AUTHORS +1 -0
- data/ext/libmspack/ChangeLog +321 -4
- data/ext/libmspack/INSTALL +368 -0
- data/ext/libmspack/Makefile.am +86 -95
- data/ext/libmspack/Makefile.in +1729 -0
- data/ext/libmspack/README +30 -30
- data/ext/libmspack/acinclude.m4 +99 -0
- data/ext/libmspack/aclocal.m4 +1218 -0
- data/ext/libmspack/ar-lib +270 -0
- data/ext/libmspack/compile +347 -0
- data/ext/libmspack/config.guess +1480 -0
- data/ext/libmspack/config.h.in +129 -0
- data/ext/libmspack/config.sub +1801 -0
- data/ext/libmspack/configure +15487 -0
- data/ext/libmspack/configure.ac +11 -13
- data/ext/libmspack/depcomp +791 -0
- data/ext/libmspack/install-sh +508 -0
- data/ext/libmspack/libmscabd.la +41 -0
- data/ext/libmspack/libmschmd.la +41 -0
- data/ext/libmspack/libmspack.la +41 -0
- data/ext/libmspack/ltmain.sh +11156 -0
- data/ext/libmspack/m4/libtool.m4 +8387 -0
- data/ext/libmspack/m4/ltoptions.m4 +437 -0
- data/ext/libmspack/m4/ltsugar.m4 +124 -0
- data/ext/libmspack/m4/ltversion.m4 +23 -0
- data/ext/libmspack/m4/lt~obsolete.m4 +99 -0
- data/ext/libmspack/missing +215 -0
- data/ext/libmspack/mspack/cab.h +20 -7
- data/ext/libmspack/mspack/cabd.c +301 -236
- data/ext/libmspack/mspack/chmd.c +304 -319
- data/ext/libmspack/mspack/crc32.c +52 -52
- data/ext/libmspack/mspack/crc32.h +1 -1
- data/ext/libmspack/mspack/kwajd.c +178 -172
- data/ext/libmspack/mspack/lzss.h +4 -4
- data/ext/libmspack/mspack/lzssd.c +42 -42
- data/ext/libmspack/mspack/lzx.h +11 -11
- data/ext/libmspack/mspack/lzxd.c +370 -361
- data/ext/libmspack/mspack/mspack.h +109 -77
- data/ext/libmspack/mspack/mszip.h +6 -6
- data/ext/libmspack/mspack/mszipd.c +140 -139
- data/ext/libmspack/mspack/oab.h +1 -0
- data/ext/libmspack/mspack/oabd.c +71 -73
- data/ext/libmspack/mspack/qtm.h +4 -4
- data/ext/libmspack/mspack/qtmd.c +118 -117
- data/ext/libmspack/mspack/readbits.h +52 -52
- data/ext/libmspack/mspack/readhuff.h +61 -61
- data/ext/libmspack/mspack/system.c +15 -9
- data/ext/libmspack/mspack/system.h +38 -50
- data/ext/libmspack/mspack/szddd.c +35 -35
- data/ext/libmspack/test-driver +148 -0
- data/ext/x86_64-linux/libmspack.so +0 -0
- data/ext/x86_64-windows/mspack.dll +0 -0
- data/lib/libmspack/version.rb +2 -1
- data/lib/libmspack.rb +1 -1
- data/libmspack.gemspec +4 -4
- data/spec/libmspack_spec.rb +5 -4
- metadata +38 -105
- data/.travis.yml +0 -5
- data/ext/i386-windows/libmspack.dll +0 -0
- data/ext/libmspack/cleanup.sh +0 -9
- data/ext/libmspack/debian/changelog +0 -6
- data/ext/libmspack/debian/control +0 -14
- data/ext/libmspack/debian/rules +0 -101
- data/ext/libmspack/doc/Doxyfile.in +0 -22
- data/ext/libmspack/doc/Makefile.in +0 -14
- data/ext/libmspack/doc/szdd_kwaj_format.html +0 -331
- data/ext/libmspack/mspack/mspack.def +0 -28
- data/ext/libmspack/mspack/qtmc.c +0 -18
- data/ext/libmspack/rebuild.sh +0 -8
- data/ext/libmspack/test/cabd_c10 +0 -19
- data/ext/libmspack/test/cabd_compare +0 -34
- data/ext/libmspack/test/cabd_md5.c +0 -161
- data/ext/libmspack/test/cabd_memory.c +0 -179
- data/ext/libmspack/test/cabd_test.c +0 -386
- data/ext/libmspack/test/cabrip.c +0 -81
- data/ext/libmspack/test/chmd_compare +0 -38
- data/ext/libmspack/test/chmd_find.c +0 -95
- data/ext/libmspack/test/chmd_md5.c +0 -67
- data/ext/libmspack/test/chmd_order.c +0 -144
- data/ext/libmspack/test/chminfo.c +0 -284
- data/ext/libmspack/test/chmx.c +0 -216
- data/ext/libmspack/test/error.h +0 -22
- data/ext/libmspack/test/expand.c +0 -79
- data/ext/libmspack/test/md5.c +0 -457
- data/ext/libmspack/test/md5.h +0 -165
- data/ext/libmspack/test/md5_fh.h +0 -123
- data/ext/libmspack/test/msdecompile_md5 +0 -24
- data/ext/libmspack/test/msexpand_md5 +0 -39
- data/ext/libmspack/test/multifh.c +0 -435
- data/ext/libmspack/test/oabx.c +0 -41
- data/ext/libmspack/test/test_files/cabd/1.pl +0 -84
- data/ext/libmspack/test/test_files/cabd/2.pl +0 -75
- data/ext/libmspack/test/test_files/cabd/bad_folderindex.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_nofiles.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_nofolders.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/bad_signature.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt1.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt2.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt3.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt4.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/multi_basic_pt5.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/normal_255c_filename.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/normal_2files_1folder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nodata.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nofiles.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_nofolder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortextheader.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfile1.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfile2.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortfolder.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_shortheader.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nofname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_noninfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nonname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nopinfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_nopname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortfname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortninfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortnname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortpinfo.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/partial_str_shortpname.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_---.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_--D.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_-F-.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_-FD.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_H--.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_H-D.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_HF-.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/reserve_HFD.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/search_basic.cab +0 -0
- data/ext/libmspack/test/test_files/cabd/search_tricky1.cab +0 -0
- data/ext/libmspack/winbuild.sh +0 -26
- data/ext/libmspack.h +0 -259
- data/ext/x86_64-windows/libmspack.dll +0 -0
data/ext/libmspack/mspack/chmd.c
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* This file is part of libmspack.
|
|
2
|
-
* (C) 2003-
|
|
2
|
+
* (C) 2003-2018 Stuart Caie.
|
|
3
3
|
*
|
|
4
4
|
* libmspack is free software; you can redistribute it and/or modify it under
|
|
5
5
|
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
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
|
-
|
|
258
|
-
|
|
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
|
-
|
|
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 (
|
|
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 (
|
|
391
|
-
sys->message(fh, "WARNING; chunk size is not
|
|
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
|
|
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
|
-
|
|
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);
|
|
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
|
-
|
|
466
|
+
if ((name_len > 0) && (name[name_len-1] == '/')) continue;
|
|
458
467
|
}
|
|
459
468
|
|
|
460
469
|
if (section > 1) {
|
|
461
|
-
|
|
462
|
-
|
|
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
|
-
|
|
467
|
-
|
|
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
|
-
|
|
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
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
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
|
-
|
|
500
|
-
|
|
501
|
-
|
|
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
|
|
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
|
-
|
|
529
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
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
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
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 (
|
|
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
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
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
|
-
|
|
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
|
-
|
|
616
|
-
|
|
617
|
-
|
|
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
|
|
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
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
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
|
-
|
|
641
|
-
|
|
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
|
-
|
|
656
|
+
MSPACK_SYS_SEEK_START))
|
|
647
657
|
{
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
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
|
-
|
|
654
|
-
|
|
655
|
-
|
|
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
|
-
|
|
670
|
+
((buf[3] == 0x4C) || (buf[3] == 0x49))))
|
|
661
671
|
{
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
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
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
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
|
-
|
|
698
|
-
|
|
707
|
+
is_pmgl = 1;
|
|
708
|
+
entries_off = pmgl_Entries;
|
|
699
709
|
}
|
|
700
710
|
else {
|
|
701
|
-
|
|
702
|
-
|
|
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
|
-
|
|
724
|
-
|
|
733
|
+
D(("chunk has no entries"))
|
|
734
|
+
return -1;
|
|
725
735
|
}
|
|
726
736
|
|
|
727
737
|
if (qr_size > chm->chunk_size) {
|
|
728
|
-
|
|
729
|
-
|
|
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
|
-
|
|
736
|
-
|
|
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
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
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
|
-
|
|
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
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
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
|
-
#
|
|
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
|
-
#
|
|
833
|
-
|
|
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
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
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
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
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
|
-
|
|
994
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
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
|
-
|
|
1181
|
-
|
|
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
|
-
|
|
1194
|
-
|
|
1172
|
+
D(("ResetTable file is too short"))
|
|
1173
|
+
return 0;
|
|
1195
1174
|
}
|
|
1196
1175
|
if (!(data = read_sys_file(self, sec->rtable))) {
|
|
1197
|
-
|
|
1198
|
-
|
|
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
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
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
|
-
|
|
1211
|
-
|
|
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
|
-
|
|
1198
|
+
pos <= (sec->rtable->length - entrysize))
|
|
1220
1199
|
{
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
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
|
-
|
|
1237
|
-
|
|
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
|
-
|
|
1255
|
-
|
|
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
|
-
|
|
1267
|
-
|
|
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
|
-
|
|
1273
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1292
|
-
|
|
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
|
-
|
|
1288
|
+
name, &result, (int)sizeof(result)) || !result.section)
|
|
1304
1289
|
{
|
|
1305
|
-
|
|
1290
|
+
return MSPACK_ERR_DATAFORMAT;
|
|
1306
1291
|
}
|
|
1307
1292
|
|
|
1308
1293
|
if (!(*f_ptr = (struct mschmd_file *) sys->alloc(sys, sizeof(result)))) {
|
|
1309
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1365
|
+
struct mspack_system *sys, struct mspack_file *fh)
|
|
1381
1366
|
{
|
|
1382
|
-
#
|
|
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
|
-
|
|
1388
|
-
|
|
1372
|
+
sys->message(fh, (char *)largefile_msg);
|
|
1373
|
+
return 1;
|
|
1389
1374
|
}
|
|
1390
1375
|
#endif
|
|
1391
1376
|
return 0;
|