libmspack 0.10.1.2 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|