libmspack 0.10.1.2 → 0.11.0
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 +4 -4
- data/Rakefile +1 -1
- data/ext/libmspack/ChangeLog +145 -0
- data/ext/libmspack/INSTALL +3 -3
- data/ext/libmspack/Makefile.am +7 -4
- data/ext/libmspack/Makefile.in +265 -147
- data/ext/libmspack/README +3 -2
- data/ext/libmspack/aclocal.m4 +111 -113
- data/ext/libmspack/ar-lib +10 -9
- data/ext/libmspack/compile +9 -8
- data/ext/libmspack/config.guess +887 -613
- data/ext/libmspack/config.h.in +6 -9
- data/ext/libmspack/config.sub +1349 -1260
- data/ext/libmspack/configure +3035 -2490
- data/ext/libmspack/configure.ac +3 -3
- data/ext/libmspack/depcomp +4 -4
- data/ext/libmspack/install-sh +107 -74
- data/ext/libmspack/libmscabd.la +1 -1
- data/ext/libmspack/libmschmd.la +1 -1
- data/ext/libmspack/libmspack.la +1 -1
- data/ext/libmspack/ltmain.sh +156 -61
- data/ext/libmspack/m4/libtool.m4 +19 -12
- data/ext/libmspack/missing +8 -8
- data/ext/libmspack/mspack/cabd.c +21 -19
- data/ext/libmspack/mspack/chm.h +3 -2
- data/ext/libmspack/mspack/chmd.c +137 -57
- data/ext/libmspack/mspack/kwajd.c +29 -29
- data/ext/libmspack/mspack/lzx.h +0 -1
- data/ext/libmspack/mspack/lzxd.c +30 -154
- data/ext/libmspack/mspack/macros.h +64 -0
- data/ext/libmspack/mspack/mszipd.c +7 -18
- data/ext/libmspack/mspack/qtmd.c +3 -5
- data/ext/libmspack/mspack/readbits.h +14 -5
- data/ext/libmspack/mspack/readhuff.h +26 -21
- data/ext/libmspack/mspack/system.c +0 -5
- data/ext/libmspack/mspack/system.h +20 -67
- data/ext/libmspack/test-driver +16 -11
- data/ext/x86_64-linux/libmspack.so +0 -0
- data/ext/x86_64-windows/mspack.dll +0 -0
- data/lib/libmspack/version.rb +1 -1
- metadata +4 -3
data/ext/libmspack/mspack/cabd.c
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
/* This file is part of libmspack.
|
2
|
-
* (C) 2003-
|
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
|
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
|
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
|
656
|
+
#if SIZEOF_OFF_T < 8
|
655
657
|
/* detect 32-bit off_t overflow */
|
656
658
|
if (flen < 0) {
|
657
|
-
sys->message(fh,
|
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
|
758
|
+
#if SIZEOF_OFF_T < 8
|
757
759
|
/* detect 32-bit off_t overflow */
|
758
760
|
if (offset < caboff) {
|
759
|
-
sys->message(fh,
|
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
|
-
|
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
|
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
|
-
|
1053
|
-
if (
|
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 ^= (
|
1403
|
+
cksum ^= EndGetI32(data);
|
1402
1404
|
}
|
1403
1405
|
|
1404
1406
|
switch (bytes & 3) {
|
data/ext/libmspack/mspack/chm.h
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
/* This file is part of libmspack.
|
2
|
-
* (C) 2003-
|
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
|
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 */
|
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-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
|
266
|
-
unsigned char buf[0x54], *chunk = NULL
|
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
|
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(&
|
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,
|
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 (
|
416
|
-
|
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 -
|
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
|
-
|
453
|
-
|
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
|
-
|
456
|
-
|
457
|
-
|
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
|
-
*
|
514
|
-
|
522
|
+
* an ENCINT is badly encoded */
|
523
|
+
encint_err:
|
515
524
|
if (num_entries >= 0) {
|
516
|
-
D(("
|
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;
|
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
|
-
|
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
|
-
|
606
|
-
|
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
|
-
|
616
|
-
D(("
|
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
|
-
|
759
|
-
if (name_len > (unsigned int) (end - p)) goto
|
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
|
-
|
796
|
-
if (name_len > (unsigned int) (end - p)) goto
|
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
|
-
|
814
|
-
|
815
|
-
|
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
|
-
|
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
|
-
|
827
|
-
D(("
|
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,
|
942
|
-
|
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
|
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,
|
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
|
1056
|
-
D(("ControlData file is
|
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
|
1410
|
+
#if SIZEOF_OFF_T >= 8
|
1368
1411
|
*var = EndGetI64(mem);
|
1369
1412
|
#else
|
1370
|
-
|
1371
|
-
|
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-
|
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
|
105
|
-
|
106
|
-
|
107
|
-
|
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
|
-
|
116
|
-
|
117
|
-
sys->
|
118
|
-
|
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,
|
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,
|
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,
|
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
|
-
|
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
|
-
|
439
|
-
|
440
|
-
|
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,
|
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
|
-
|
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
|
|