... | ... |
@@ -1,17 +1,64 @@ |
1 |
-18-09-16 Stuart Caie <kyzer@cabextract.org.uk> |
|
2 |
- |
|
3 |
- * cabd.c: add new parameter, MSCABD_PARAM_SALVAGE, which makes CAB file |
|
4 |
- reading and extraction more lenient, to allow damaged or mangled CABs |
|
5 |
- to be extracted. When enabled, cabd->open() will no longer reject |
|
6 |
- cabinets entirely if they have files with invalid folder indicies |
|
7 |
- or filenames, but will simply ignore those files. Also, cabd->extract() |
|
8 |
- will limit files with invalid lengths to the maximum possible, rather |
|
9 |
- than reject them. Finally, invalid data block checksums will produce |
|
10 |
- warnings, but won't cause decompression to fail. It's still possible |
|
11 |
- for corrupted files to fail extraction, but hopefully more data can |
|
12 |
- be extracted before they do. This new parameter doesn't affect the |
|
13 |
- existing MSCABD_PARAM_FIXMSZIP parameter, which ignores MSZIP |
|
14 |
- decompression failures. |
|
1 |
+2018-10-20 Stuart Caie <kyzer@cabextract.org.uk> |
|
2 |
+ |
|
3 |
+ * src/chmextract.c: add anti "../" and leading slash protection to |
|
4 |
+ chmextract. I'm not pleased about this. All the sample code provided |
|
5 |
+ with libmspack is meant to be simple examples of library use, not |
|
6 |
+ "productised" binaries. Making the "useful" code samples install |
|
7 |
+ as binaries was a mistake. They were never intended to protect you |
|
8 |
+ from unpacking archive files with relative/absolute paths, and I |
|
9 |
+ would prefer that they never will be. |
|
10 |
+ |
|
11 |
+2018-10-17 Stuart Caie <kyzer@cabextract.org.uk> |
|
12 |
+ |
|
13 |
+ * cab.h: Make the CAB block input buffer one byte larger, to allow |
|
14 |
+ a maximum-allowed-size input block and the special extra byte added |
|
15 |
+ after the block by cabd_sys_read_block to help Quantum alignment. |
|
16 |
+ Thanks to Henri Salo for reporting this. |
|
17 |
+ |
|
18 |
+2018-10-17 Stuart Caie <kyzer@cabextract.org.uk> |
|
19 |
+ |
|
20 |
+ * chmd_read_headers(): again reject files with blank filenames, this |
|
21 |
+ time because their 1st or 2nd byte is null, not because their length |
|
22 |
+ is zero. Thanks again to Hanno Böck for finding the issue. |
|
23 |
+ |
|
24 |
+2018-10-16 Stuart Caie <kyzer@cabextract.org.uk> |
|
25 |
+ |
|
26 |
+ * Makefile.am: using automake _DEPENDENCIES for chmd_test appears to |
|
27 |
+ override the default dependencies (e.g. sources), so libchmd.la was no |
|
28 |
+ longer considered a dependency of chmd_test. This breaks parallel |
|
29 |
+ builds like "make -j4". Added libchmd.la explicitly to dependencies. |
|
30 |
+ Thanks to Thomas Deutschmann for reporting this. |
|
31 |
+ |
|
32 |
+2018-10-16 Stuart Caie <kyzer@cabextract.org.uk> |
|
33 |
+ |
|
34 |
+ * cabd.c: add new parameter, MSCABD_PARAM_SALVAGE, which makes CAB file |
|
35 |
+ reading and extraction more lenient, to allow damaged or mangled CABs |
|
36 |
+ to be extracted. When enabled: |
|
37 |
+ - cabd->open() won't reject cabinets with files that have invalid |
|
38 |
+ folder indices or filenames. These files will simply be skipped |
|
39 |
+ - cabd->extract() won't reject files with invalid lengths, but will |
|
40 |
+ limit them to the maximum possible |
|
41 |
+ - block output sizes over 32768 bytes won't be rejected |
|
42 |
+ - invalid data block checksums won't be rejected |
|
43 |
+ |
|
44 |
+ It's still possible for corrupted files to fail extraction, but more |
|
45 |
+ data can be extracted before they do. |
|
46 |
+ |
|
47 |
+ This new parameter doesn't affect the existing MSCABD_PARAM_FIXMSZIP |
|
48 |
+ parameter, which ignores MSZIP decompression failures. You can enable |
|
49 |
+ both at once. |
|
50 |
+ |
|
51 |
+ Thanks to Micah Snyder from ClamAV for working with me to get this |
|
52 |
+ feature into libmspack. This also helps ClamAV move towards using a |
|
53 |
+ vanilla copy of libmspack without needing their own patchset. |
|
54 |
+ |
|
55 |
+2018-08-13 Stuart Caie <kyzer@cabextract.org.uk> |
|
56 |
+ |
|
57 |
+ * mspack.h: clarify that mspack_system.free() should allow NULL. If your |
|
58 |
+ mspack_system implementation doesn't, it would already have crashed, as |
|
59 |
+ there are several places where libmspack calls sys->free(NULL). This |
|
60 |
+ change makes it official, and amends a few "if (x) sys->free(x)" cases |
|
61 |
+ to the simpler "sys->free(x)" to make it clearer. |
|
15 | 62 |
|
16 | 63 |
2018-08-09 Stuart Caie <kyzer@cabextract.org.uk> |
17 | 64 |
|
... | ... |
@@ -89,7 +89,7 @@ test_chmd_order_SOURCES = test/chmd_order.c test/md5.c test/md5.h \ |
89 | 89 |
test_chmd_order_LDADD = libmschmd.la |
90 | 90 |
test_chmd_test_SOURCES = test/chmd_test.c libmschmd.la |
91 | 91 |
test_chmd_test_LDADD = libmschmd.la |
92 |
-test_chmd_test_DEPENDENCIES = test/test_files/chmd/cve-2015-4467-reset-interval-zero.chm |
|
92 |
+test_chmd_test_DEPENDENCIES = libmschmd.la test/test_files/chmd/cve-2015-4467-reset-interval-zero.chm |
|
93 | 93 |
test_chminfo_SOURCES = test/chminfo.c libmschmd.la |
94 | 94 |
test_chminfo_LDADD = libmschmd.la |
95 | 95 |
test_kwajd_test_SOURCES = test/kwajd_test.c libmspack.la |
... | ... |
@@ -515,7 +515,7 @@ test_chmd_order_SOURCES = test/chmd_order.c test/md5.c test/md5.h \ |
515 | 515 |
test_chmd_order_LDADD = libmschmd.la |
516 | 516 |
test_chmd_test_SOURCES = test/chmd_test.c libmschmd.la |
517 | 517 |
test_chmd_test_LDADD = libmschmd.la |
518 |
-test_chmd_test_DEPENDENCIES = test/test_files/chmd/cve-2015-4467-reset-interval-zero.chm |
|
518 |
+test_chmd_test_DEPENDENCIES = libmschmd.la test/test_files/chmd/cve-2015-4467-reset-interval-zero.chm |
|
519 | 519 |
test_chminfo_SOURCES = test/chminfo.c libmschmd.la |
520 | 520 |
test_chminfo_LDADD = libmschmd.la |
521 | 521 |
test_kwajd_test_SOURCES = test/kwajd_test.c libmspack.la |
... | ... |
@@ -1,4 +1,4 @@ |
1 |
-libmspack 0.7.1alpha |
|
1 |
+libmspack 0.8alpha |
|
2 | 2 |
|
3 | 3 |
The purpose of libmspack is to provide compressors and decompressors, |
4 | 4 |
archivers and dearchivers for Microsoft compression formats: CAB, CHM, WIM, |
... | ... |
@@ -36,12 +36,11 @@ make install |
36 | 36 |
This will install the main libmspack library and mspack.h header file. |
37 | 37 |
Some other libraries and executables are built, but not installed. |
38 | 38 |
|
39 |
-If building from the Subversion repository, running rebuild.sh will create |
|
40 |
-all the automatically generated files like the configure script, and will |
|
41 |
-then ./configure, make and make distcheck. Running cleanup.sh will perform |
|
42 |
-a thorough clean, deleting all automatically generated files. |
|
39 |
+If building from the Git repository, running rebuild.sh will create all the |
|
40 |
+auto-generated files, then run ./configure && make. Running cleanup.sh will |
|
41 |
+perform a thorough clean, deleting all auto-generated files. |
|
43 | 42 |
|
44 |
-In addition to gcc, you also need the following for building from Subversion: |
|
43 |
+In addition to gcc, you also need the following for building from repository: |
|
45 | 44 |
|
46 | 45 |
- at least autoconf 2.57 |
47 | 46 |
- at least automake 1.7 |
... | ... |
@@ -1,6 +1,6 @@ |
1 | 1 |
#! /bin/sh |
2 | 2 |
# Guess values for system-dependent variables and create Makefiles. |
3 |
-# Generated by GNU Autoconf 2.69 for libmspack 0.7.1alpha. |
|
3 |
+# Generated by GNU Autoconf 2.69 for libmspack 0.8alpha. |
|
4 | 4 |
# |
5 | 5 |
# Report bugs to <kyzer@cabextract.org.uk>. |
6 | 6 |
# |
... | ... |
@@ -590,8 +590,8 @@ MAKEFLAGS= |
590 | 590 |
# Identity of this package. |
591 | 591 |
PACKAGE_NAME='libmspack' |
592 | 592 |
PACKAGE_TARNAME='libmspack' |
593 |
-PACKAGE_VERSION='0.7.1alpha' |
|
594 |
-PACKAGE_STRING='libmspack 0.7.1alpha' |
|
593 |
+PACKAGE_VERSION='0.8alpha' |
|
594 |
+PACKAGE_STRING='libmspack 0.8alpha' |
|
595 | 595 |
PACKAGE_BUGREPORT='kyzer@cabextract.org.uk' |
596 | 596 |
PACKAGE_URL='' |
597 | 597 |
|
... | ... |
@@ -1330,7 +1330,7 @@ if test "$ac_init_help" = "long"; then |
1330 | 1330 |
# Omit some internal or obsolete options to make the list less imposing. |
1331 | 1331 |
# This message is too long to be a string in the A/UX 3.1 sh. |
1332 | 1332 |
cat <<_ACEOF |
1333 |
-\`configure' configures libmspack 0.7.1alpha to adapt to many kinds of systems. |
|
1333 |
+\`configure' configures libmspack 0.8alpha to adapt to many kinds of systems. |
|
1334 | 1334 |
|
1335 | 1335 |
Usage: $0 [OPTION]... [VAR=VALUE]... |
1336 | 1336 |
|
... | ... |
@@ -1401,7 +1401,7 @@ fi |
1401 | 1401 |
|
1402 | 1402 |
if test -n "$ac_init_help"; then |
1403 | 1403 |
case $ac_init_help in |
1404 |
- short | recursive ) echo "Configuration of libmspack 0.7.1alpha:";; |
|
1404 |
+ short | recursive ) echo "Configuration of libmspack 0.8alpha:";; |
|
1405 | 1405 |
esac |
1406 | 1406 |
cat <<\_ACEOF |
1407 | 1407 |
|
... | ... |
@@ -1513,7 +1513,7 @@ fi |
1513 | 1513 |
test -n "$ac_init_help" && exit $ac_status |
1514 | 1514 |
if $ac_init_version; then |
1515 | 1515 |
cat <<\_ACEOF |
1516 |
-libmspack configure 0.7.1alpha |
|
1516 |
+libmspack configure 0.8alpha |
|
1517 | 1517 |
generated by GNU Autoconf 2.69 |
1518 | 1518 |
|
1519 | 1519 |
Copyright (C) 2012 Free Software Foundation, Inc. |
... | ... |
@@ -2119,7 +2119,7 @@ cat >config.log <<_ACEOF |
2119 | 2119 |
This file contains any messages produced by compilers while |
2120 | 2120 |
running configure, to aid debugging if configure makes a mistake. |
2121 | 2121 |
|
2122 |
-It was created by libmspack $as_me 0.7.1alpha, which was |
|
2122 |
+It was created by libmspack $as_me 0.8alpha, which was |
|
2123 | 2123 |
generated by GNU Autoconf 2.69. Invocation command line was |
2124 | 2124 |
|
2125 | 2125 |
$ $0 $@ |
... | ... |
@@ -2983,7 +2983,7 @@ fi |
2983 | 2983 |
|
2984 | 2984 |
# Define the identity of the package. |
2985 | 2985 |
PACKAGE='libmspack' |
2986 |
- VERSION='0.7.1alpha' |
|
2986 |
+ VERSION='0.8alpha' |
|
2987 | 2987 |
|
2988 | 2988 |
|
2989 | 2989 |
cat >>confdefs.h <<_ACEOF |
... | ... |
@@ -13640,7 +13640,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 |
13640 | 13640 |
# report actual input values of CONFIG_FILES etc. instead of their |
13641 | 13641 |
# values after options handling. |
13642 | 13642 |
ac_log=" |
13643 |
-This file was extended by libmspack $as_me 0.7.1alpha, which was |
|
13643 |
+This file was extended by libmspack $as_me 0.8alpha, which was |
|
13644 | 13644 |
generated by GNU Autoconf 2.69. Invocation command line was |
13645 | 13645 |
|
13646 | 13646 |
CONFIG_FILES = $CONFIG_FILES |
... | ... |
@@ -13706,7 +13706,7 @@ _ACEOF |
13706 | 13706 |
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 |
13707 | 13707 |
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" |
13708 | 13708 |
ac_cs_version="\\ |
13709 |
-libmspack config.status 0.7.1alpha |
|
13709 |
+libmspack config.status 0.8alpha |
|
13710 | 13710 |
configured by $0, generated by GNU Autoconf 2.69, |
13711 | 13711 |
with options \\"\$ac_cs_config\\" |
13712 | 13712 |
|
... | ... |
@@ -1,7 +1,7 @@ |
1 | 1 |
# -*- Autoconf -*- |
2 | 2 |
# Process this file with autoconf to produce a configure script. |
3 | 3 |
AC_PREREQ(2.59) |
4 |
-AC_INIT([libmspack],[0.7.1alpha],[kyzer@cabextract.org.uk]) |
|
4 |
+AC_INIT([libmspack],[0.8alpha],[kyzer@cabextract.org.uk]) |
|
5 | 5 |
AC_CONFIG_MACRO_DIR([m4]) |
6 | 6 |
AM_INIT_AUTOMAKE |
7 | 7 |
AC_CONFIG_SRCDIR([mspack/mspack.h]) |
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
/* This file is part of libmspack. |
2 |
- * (C) 2003-2004 Stuart Caie. |
|
2 |
+ * (C) 2003-2018 Stuart Caie. |
|
3 | 3 |
* |
4 | 4 |
* libmspack is free software; you can redistribute it and/or modify it under |
5 | 5 |
* the terms of the GNU Lesser General Public License (LGPL) version 2.1 |
... | ... |
@@ -67,16 +67,24 @@ |
67 | 67 |
* more than 6144 bytes. Quantum has no documentation, but the largest |
68 | 68 |
* block seen in the wild is 337 bytes above uncompressed size. |
69 | 69 |
*/ |
70 |
-#define CAB_BLOCKMAX (65535) |
|
71 |
-#define CAB_BLOCKSTD (32768) |
|
70 |
+#define CAB_BLOCKMAX (32768) |
|
72 | 71 |
#define CAB_INPUTMAX (CAB_BLOCKMAX+6144) |
73 | 72 |
|
73 |
+/* input buffer needs to be CAB_INPUTMAX + 1 byte to allow for max-sized block |
|
74 |
+ * plus 1 trailer byte added by cabd_sys_read_block() for Quantum alignment. |
|
75 |
+ * |
|
76 |
+ * When MSCABD_PARAM_SALVAGE is set, block size is not checked so can be |
|
77 |
+ * up to 65535 bytes, so max input buffer size needed is 65535 + 1 |
|
78 |
+ */ |
|
79 |
+#define CAB_INPUTMAX_SALVAGE (65535) |
|
80 |
+#define CAB_INPUTBUF (CAB_INPUTMAX_SALVAGE + 1) |
|
81 |
+ |
|
74 | 82 |
/* There are no more than 65535 data blocks per folder, so a folder cannot |
75 | 83 |
* be more than 32768*65535 bytes in length. As files cannot span more than |
76 | 84 |
* one folder, this is also their max offset, length and offset+length limit. |
77 | 85 |
*/ |
78 | 86 |
#define CAB_FOLDERMAX (65535) |
79 |
-#define CAB_LENGTHMAX UINT_MAX |
|
87 |
+#define CAB_LENGTHMAX (CAB_BLOCKMAX * CAB_FOLDERMAX) |
|
80 | 88 |
|
81 | 89 |
/* CAB compression definitions */ |
82 | 90 |
|
... | ... |
@@ -93,6 +101,7 @@ struct mscabd_decompress_state { |
93 | 93 |
struct mscabd_folder_data *data; /* current folder split we're in */ |
94 | 94 |
unsigned int offset; /* uncompressed offset within folder */ |
95 | 95 |
unsigned int block; /* which block are we decompressing? */ |
96 |
+ off_t outlen; /* cumulative sum of block output sizes */ |
|
96 | 97 |
struct mspack_system sys; /* special I/O code for decompressor */ |
97 | 98 |
int comp_type; /* type of compression used by folder */ |
98 | 99 |
int (*decompress)(void *, off_t); /* decompressor code */ |
... | ... |
@@ -101,7 +110,7 @@ struct mscabd_decompress_state { |
101 | 101 |
struct mspack_file *infh; /* input file handle */ |
102 | 102 |
struct mspack_file *outfh; /* output file handle */ |
103 | 103 |
unsigned char *i_ptr, *i_end; /* input data consumed, end */ |
104 |
- unsigned char input[CAB_INPUTMAX]; /* one input block of data */ |
|
104 |
+ unsigned char input[CAB_INPUTBUF]; /* one input block of data */ |
|
105 | 105 |
}; |
106 | 106 |
|
107 | 107 |
struct mscab_decompressor_p { |
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
/* This file is part of libmspack. |
2 |
- * (C) 2003-2011 Stuart Caie. |
|
2 |
+ * (C) 2003-2018 Stuart Caie. |
|
3 | 3 |
* |
4 | 4 |
* libmspack is free software; you can redistribute it and/or modify it under |
5 | 5 |
* the terms of the GNU Lesser General Public License (LGPL) version 2.1 |
... | ... |
@@ -109,7 +109,7 @@ static int cabd_sys_write( |
109 | 109 |
struct mspack_file *file, void *buffer, int bytes); |
110 | 110 |
static int cabd_sys_read_block( |
111 | 111 |
struct mspack_system *sys, struct mscabd_decompress_state *d, int *out, |
112 |
- int ignore_cksum); |
|
112 |
+ int ignore_cksum, int ignore_blocksize); |
|
113 | 113 |
static unsigned int cabd_checksum( |
114 | 114 |
unsigned char *data, unsigned int bytes, unsigned int cksum); |
115 | 115 |
static struct noned_state *noned_init( |
... | ... |
@@ -306,9 +306,9 @@ static void cabd_close(struct mscab_decompressor *base, |
306 | 306 |
static int cabd_read_headers(struct mspack_system *sys, |
307 | 307 |
struct mspack_file *fh, |
308 | 308 |
struct mscabd_cabinet_p *cab, |
309 |
- off_t offset, int quiet, int salvage) |
|
309 |
+ off_t offset, int salvage, int quiet) |
|
310 | 310 |
{ |
311 |
- int num_folders, num_files, folder_resv, i, x, fidx, fidx_ok, read_string_errno = 0; |
|
311 |
+ int num_folders, num_files, folder_resv, i, x, err, fidx; |
|
312 | 312 |
struct mscabd_folder_p *fol, *linkfol = NULL; |
313 | 313 |
struct mscabd_file *file, *linkfile = NULL; |
314 | 314 |
unsigned char buf[64]; |
... | ... |
@@ -392,18 +392,18 @@ static int cabd_read_headers(struct mspack_system *sys, |
392 | 392 |
|
393 | 393 |
/* read name and info of preceeding cabinet in set, if present */ |
394 | 394 |
if (cab->base.flags & cfheadPREV_CABINET) { |
395 |
- cab->base.prevname = cabd_read_string(sys, fh, &read_string_errno); |
|
396 |
- if (read_string_errno) return read_string_errno; |
|
397 |
- cab->base.previnfo = cabd_read_string(sys, fh, &read_string_errno); |
|
398 |
- if (read_string_errno) return read_string_errno; |
|
395 |
+ cab->base.prevname = cabd_read_string(sys, fh, &err); |
|
396 |
+ if (err) return err; |
|
397 |
+ cab->base.previnfo = cabd_read_string(sys, fh, &err); |
|
398 |
+ if (err) return err; |
|
399 | 399 |
} |
400 | 400 |
|
401 | 401 |
/* read name and info of next cabinet in set, if present */ |
402 | 402 |
if (cab->base.flags & cfheadNEXT_CABINET) { |
403 |
- cab->base.nextname = cabd_read_string(sys, fh, &read_string_errno); |
|
404 |
- if (read_string_errno) return read_string_errno; |
|
405 |
- cab->base.nextinfo = cabd_read_string(sys, fh, &read_string_errno); |
|
406 |
- if (read_string_errno) return read_string_errno; |
|
403 |
+ cab->base.nextname = cabd_read_string(sys, fh, &err); |
|
404 |
+ if (err) return err; |
|
405 |
+ cab->base.nextinfo = cabd_read_string(sys, fh, &err); |
|
406 |
+ if (err) return err; |
|
407 | 407 |
} |
408 | 408 |
|
409 | 409 |
/* read folders */ |
... | ... |
@@ -452,7 +452,6 @@ static int cabd_read_headers(struct mspack_system *sys, |
452 | 452 |
file->offset = EndGetI32(&buf[cffile_FolderOffset]); |
453 | 453 |
|
454 | 454 |
/* set folder pointer */ |
455 |
- fidx_ok = 1; |
|
456 | 455 |
fidx = EndGetI16(&buf[cffile_FolderIndex]); |
457 | 456 |
if (fidx < cffileCONTINUED_FROM_PREV) { |
458 | 457 |
/* normal folder index; count up to the correct folder */ |
... | ... |
@@ -462,12 +461,8 @@ static int cabd_read_headers(struct mspack_system *sys, |
462 | 462 |
file->folder = ifol; |
463 | 463 |
} |
464 | 464 |
else { |
465 |
- file->folder = NULL; |
|
466 |
- } |
|
467 |
- |
|
468 |
- if (!file->folder) { |
|
469 | 465 |
D(("invalid folder index")) |
470 |
- fidx_ok = 0; |
|
466 |
+ file->folder = NULL; |
|
471 | 467 |
} |
472 | 468 |
} |
473 | 469 |
else { |
... | ... |
@@ -511,11 +506,14 @@ static int cabd_read_headers(struct mspack_system *sys, |
511 | 511 |
file->date_y = (x >> 9) + 1980; |
512 | 512 |
|
513 | 513 |
/* get filename */ |
514 |
- file->filename = cabd_read_string(sys, fh, &read_string_errno); |
|
515 |
- if (read_string_errno || !fidx_ok) { |
|
514 |
+ file->filename = cabd_read_string(sys, fh, &err); |
|
515 |
+ |
|
516 |
+ /* if folder index or filename are bad, either skip it or fail */ |
|
517 |
+ if (err || !file->folder) { |
|
516 | 518 |
sys->free(file->filename); |
517 | 519 |
sys->free(file); |
518 |
- if (salvage) continue; else return read_string_errno; |
|
520 |
+ if (salvage) continue; |
|
521 |
+ return err ? err : MSPACK_ERR_DATAFORMAT; |
|
519 | 522 |
} |
520 | 523 |
|
521 | 524 |
/* link file entry into file list */ |
... | ... |
@@ -726,10 +724,11 @@ static int cabd_find(struct mscab_decompressor_p *self, unsigned char *buf, |
726 | 726 |
|
727 | 727 |
/* check that the files offset is less than the alleged length of |
728 | 728 |
* the cabinet, and that the offset + the alleged length are |
729 |
- * 'roughly' within the end of overall file length */ |
|
729 |
+ * 'roughly' within the end of overall file length. In salvage |
|
730 |
+ * mode, don't check the alleged length, allow it to be garbage */ |
|
730 | 731 |
if ((foffset_u32 < cablen_u32) && |
731 | 732 |
((caboff + (off_t) foffset_u32) < (flen + 32)) && |
732 |
- ((caboff + (off_t) cablen_u32) < (flen + 32)) ) |
|
733 |
+ (((caboff + (off_t) cablen_u32) < (flen + 32)) || salvage)) |
|
733 | 734 |
{ |
734 | 735 |
/* likely cabinet found -- try reading it */ |
735 | 736 |
if (!(cab = (struct mscabd_cabinet_p *) sys->alloc(sys, sizeof(struct mscabd_cabinet_p)))) { |
... | ... |
@@ -1012,7 +1011,7 @@ static int cabd_extract(struct mscab_decompressor *base, |
1012 | 1012 |
struct mscabd_folder_p *fol; |
1013 | 1013 |
struct mspack_system *sys; |
1014 | 1014 |
struct mspack_file *fh; |
1015 |
- off_t filelen, maxlen; |
|
1015 |
+ off_t filelen; |
|
1016 | 1016 |
|
1017 | 1017 |
if (!self) return MSPACK_ERR_ARGS; |
1018 | 1018 |
if (!file) return self->error = MSPACK_ERR_ARGS; |
... | ... |
@@ -1045,17 +1044,12 @@ static int cabd_extract(struct mscab_decompressor *base, |
1045 | 1045 |
return self->error = MSPACK_ERR_DECRUNCH; |
1046 | 1046 |
} |
1047 | 1047 |
|
1048 |
- /* if file goes beyond what can be decoded, either error, |
|
1049 |
- * or in salvage mode reduce file length to what can be decoded |
|
1048 |
+ /* if file goes beyond what can be decoded, given an error. |
|
1049 |
+ * In salvage mode, don't assume block sizes, just try decoding |
|
1050 | 1050 |
*/ |
1051 |
- maxlen = fol->base.num_blocks * CAB_BLOCKMAX; |
|
1052 |
- if ((file->offset + filelen) > maxlen) { |
|
1053 |
- if (self->param[MSCABD_PARAM_SALVAGE]) { |
|
1054 |
- sys->message(NULL, "WARNING: can only extract first %"LD" bytes " |
|
1055 |
- " of file \"%s\"", maxlen, file->filename); |
|
1056 |
- filelen = maxlen; |
|
1057 |
- } |
|
1058 |
- else { |
|
1051 |
+ if (!self->param[MSCABD_PARAM_SALVAGE]) { |
|
1052 |
+ off_t maxlen = fol->base.num_blocks * CAB_BLOCKMAX; |
|
1053 |
+ if ((file->offset + filelen) > maxlen) { |
|
1059 | 1054 |
sys->message(NULL, "ERROR; file \"%s\" cannot be extracted, " |
1060 | 1055 |
"cabinet set is incomplete", file->filename); |
1061 | 1056 |
return self->error = MSPACK_ERR_DECRUNCH; |
... | ... |
@@ -1107,6 +1101,7 @@ static int cabd_extract(struct mscab_decompressor *base, |
1107 | 1107 |
self->d->data = &fol->data; |
1108 | 1108 |
self->d->offset = 0; |
1109 | 1109 |
self->d->block = 0; |
1110 |
+ self->d->outlen = 0; |
|
1110 | 1111 |
self->d->i_ptr = self->d->i_end = &self->d->input[0]; |
1111 | 1112 |
|
1112 | 1113 |
/* read_error lasts for the lifetime of a decompressor */ |
... | ... |
@@ -1227,11 +1222,12 @@ static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) { |
1227 | 1227 |
struct mscab_decompressor_p *self = (struct mscab_decompressor_p *) file; |
1228 | 1228 |
unsigned char *buf = (unsigned char *) buffer; |
1229 | 1229 |
struct mspack_system *sys = self->system; |
1230 |
- int avail, todo, outlen, ignore_cksum; |
|
1230 |
+ int avail, todo, outlen, ignore_cksum, ignore_blocksize; |
|
1231 | 1231 |
|
1232 | 1232 |
ignore_cksum = self->param[MSCABD_PARAM_SALVAGE] || |
1233 | 1233 |
(self->param[MSCABD_PARAM_FIXMSZIP] && |
1234 | 1234 |
((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_MSZIP)); |
1235 |
+ ignore_blocksize = self->param[MSCABD_PARAM_SALVAGE]; |
|
1235 | 1236 |
|
1236 | 1237 |
todo = bytes; |
1237 | 1238 |
while (todo > 0) { |
... | ... |
@@ -1251,16 +1247,20 @@ static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) { |
1251 | 1251 |
|
1252 | 1252 |
/* check if we're out of input blocks, advance block counter */ |
1253 | 1253 |
if (self->d->block++ >= self->d->folder->base.num_blocks) { |
1254 |
- if (!self->param[MSCABD_PARAM_SALVAGE]) |
|
1254 |
+ if (!self->param[MSCABD_PARAM_SALVAGE]) { |
|
1255 | 1255 |
self->read_error = MSPACK_ERR_DATAFORMAT; |
1256 |
- else |
|
1256 |
+ } |
|
1257 |
+ else { |
|
1257 | 1258 |
D(("Ran out of CAB input blocks prematurely")) |
1259 |
+ } |
|
1258 | 1260 |
break; |
1259 | 1261 |
} |
1260 | 1262 |
|
1261 | 1263 |
/* read a block */ |
1262 |
- self->read_error = cabd_sys_read_block(sys, self->d, &outlen, ignore_cksum); |
|
1264 |
+ self->read_error = cabd_sys_read_block(sys, self->d, &outlen, |
|
1265 |
+ ignore_cksum, ignore_blocksize); |
|
1263 | 1266 |
if (self->read_error) return -1; |
1267 |
+ self->d->outlen += outlen; |
|
1264 | 1268 |
|
1265 | 1269 |
/* special Quantum hack -- trailer byte to allow the decompressor |
1266 | 1270 |
* to realign itself. CAB Quantum blocks, unlike LZX blocks, can have |
... | ... |
@@ -1271,19 +1271,10 @@ static int cabd_sys_read(struct mspack_file *file, void *buffer, int bytes) { |
1271 | 1271 |
|
1272 | 1272 |
/* is this the last block? */ |
1273 | 1273 |
if (self->d->block >= self->d->folder->base.num_blocks) { |
1274 |
- /* last block */ |
|
1275 | 1274 |
if ((self->d->comp_type & cffoldCOMPTYPE_MASK) == cffoldCOMPTYPE_LZX) { |
1276 | 1275 |
/* special LZX hack -- on the last block, inform LZX of the |
1277 | 1276 |
* size of the output data stream. */ |
1278 |
- lzxd_set_output_length((struct lzxd_stream *) self->d->state, (off_t) |
|
1279 |
- ((self->d->block-1) * CAB_BLOCKSTD + outlen)); |
|
1280 |
- } |
|
1281 |
- } |
|
1282 |
- else { |
|
1283 |
- /* not the last block */ |
|
1284 |
- if (outlen != CAB_BLOCKMAX) { |
|
1285 |
- self->system->message(self->d->infh, |
|
1286 |
- "WARNING; non-maximal data block"); |
|
1277 |
+ lzxd_set_output_length((struct lzxd_stream *) self->d->state, self->d->outlen); |
|
1287 | 1278 |
} |
1288 | 1279 |
} |
1289 | 1280 |
} /* if (avail) */ |
... | ... |
@@ -1308,11 +1299,12 @@ static int cabd_sys_write(struct mspack_file *file, void *buffer, int bytes) { |
1308 | 1308 |
*/ |
1309 | 1309 |
static int cabd_sys_read_block(struct mspack_system *sys, |
1310 | 1310 |
struct mscabd_decompress_state *d, |
1311 |
- int *out, int ignore_cksum) |
|
1311 |
+ int *out, int ignore_cksum, |
|
1312 |
+ int ignore_blocksize) |
|
1312 | 1313 |
{ |
1313 | 1314 |
unsigned char hdr[cfdata_SIZEOF]; |
1314 | 1315 |
unsigned int cksum; |
1315 |
- int len; |
|
1316 |
+ int len, full_len; |
|
1316 | 1317 |
|
1317 | 1318 |
/* reset the input block pointer and end of block pointer */ |
1318 | 1319 |
d->i_ptr = d->i_end = &d->input[0]; |
... | ... |
@@ -1333,16 +1325,19 @@ static int cabd_sys_read_block(struct mspack_system *sys, |
1333 | 1333 |
|
1334 | 1334 |
/* blocks must not be over CAB_INPUTMAX in size */ |
1335 | 1335 |
len = EndGetI16(&hdr[cfdata_CompressedSize]); |
1336 |
- if (((d->i_end - d->i_ptr) + len) > CAB_INPUTMAX) { |
|
1337 |
- D(("block size > CAB_INPUTMAX (%ld + %d)", |
|
1338 |
- (long)(d->i_end - d->i_ptr), len)) |
|
1339 |
- return MSPACK_ERR_DATAFORMAT; |
|
1336 |
+ full_len = (d->i_end - d->i_ptr) + len; /* include cab-spanning blocks */ |
|
1337 |
+ if (full_len > CAB_INPUTMAX) { |
|
1338 |
+ D(("block size %d > CAB_INPUTMAX", full_len)); |
|
1339 |
+ /* in salvage mode, blocks can be 65535 bytes but no more than that */ |
|
1340 |
+ if (!ignore_blocksize || full_len > CAB_INPUTMAX_SALVAGE) { |
|
1341 |
+ return MSPACK_ERR_DATAFORMAT; |
|
1342 |
+ } |
|
1340 | 1343 |
} |
1341 | 1344 |
|
1342 | 1345 |
/* blocks must not expand to more than CAB_BLOCKMAX */ |
1343 | 1346 |
if (EndGetI16(&hdr[cfdata_UncompressedSize]) > CAB_BLOCKMAX) { |
1344 | 1347 |
D(("block size > CAB_BLOCKMAX")) |
1345 |
- return MSPACK_ERR_DATAFORMAT; |
|
1348 |
+ if (!ignore_blocksize) return MSPACK_ERR_DATAFORMAT; |
|
1346 | 1349 |
} |
1347 | 1350 |
|
1348 | 1351 |
/* read the block data */ |
... | ... |
@@ -447,14 +447,14 @@ static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh, |
447 | 447 |
while (num_entries--) { |
448 | 448 |
READ_ENCINT(name_len); |
449 | 449 |
if (name_len > (unsigned int) (end - p)) goto chunk_end; |
450 |
- /* consider blank filenames to be an error */ |
|
451 |
- if (name_len == 0) goto chunk_end; |
|
452 | 450 |
name = p; p += name_len; |
453 |
- |
|
454 | 451 |
READ_ENCINT(section); |
455 | 452 |
READ_ENCINT(offset); |
456 | 453 |
READ_ENCINT(length); |
457 | 454 |
|
455 |
+ /* ignore blank or one-char (e.g. "/") filenames we'd return as blank */ |
|
456 |
+ if (name_len < 2 || !name[0] || !name[1]) continue; |
|
457 |
+ |
|
458 | 458 |
/* empty files and directory names are stored as a file entry at |
459 | 459 |
* offset 0 with length 0. We want to keep empty files, but not |
460 | 460 |
* directory names, which end with a "/" */ |
... | ... |
@@ -536,7 +536,7 @@ static int chmd_fast_find(struct mschm_decompressor *base, |
536 | 536 |
struct mschm_decompressor_p *self = (struct mschm_decompressor_p *) base; |
537 | 537 |
struct mspack_system *sys; |
538 | 538 |
struct mspack_file *fh; |
539 |
- const unsigned char *chunk, *p = NULL, *end = NULL; |
|
539 |
+ const unsigned char *chunk, *p, *end; |
|
540 | 540 |
int err = MSPACK_ERR_OK, result = -1; |
541 | 541 |
unsigned int n, sec; |
542 | 542 |
|
... | ... |
@@ -236,14 +236,10 @@ static int oabd_decompress(struct msoab_decompressor *_self, const char *input, |
236 | 236 |
} |
237 | 237 |
|
238 | 238 |
out: |
239 |
- if (lzx) |
|
240 |
- lzxd_free(lzx); |
|
241 |
- if (buf) |
|
242 |
- sys->free(buf); |
|
243 |
- if (outfh) |
|
244 |
- sys->close(outfh); |
|
245 |
- if (infh) |
|
246 |
- sys->close(infh); |
|
239 |
+ if (lzx) lzxd_free(lzx); |
|
240 |
+ if (outfh) sys->close(outfh); |
|
241 |
+ if (infh) sys->close(infh); |
|
242 |
+ sys->free(buf); |
|
247 | 243 |
|
248 | 244 |
return ret; |
249 | 245 |
} |
... | ... |
@@ -390,16 +386,11 @@ static int oabd_decompress_incremental(struct msoab_decompressor *_self, |
390 | 390 |
} |
391 | 391 |
|
392 | 392 |
out: |
393 |
- if (lzx) |
|
394 |
- lzxd_free(lzx); |
|
395 |
- if (buf) |
|
396 |
- sys->free(buf); |
|
397 |
- if (outfh) |
|
398 |
- sys->close(outfh); |
|
399 |
- if (basefh) |
|
400 |
- sys->close(basefh); |
|
401 |
- if (infh) |
|
402 |
- sys->close(infh); |
|
393 |
+ if (lzx) lzxd_free(lzx); |
|
394 |
+ if (outfh) sys->close(outfh); |
|
395 |
+ if (basefh) sys->close(basefh); |
|
396 |
+ if (infh) sys->close(infh); |
|
397 |
+ sys->free(buf); |
|
403 | 398 |
|
404 | 399 |
return ret; |
405 | 400 |
} |
... | ... |
@@ -8,74 +8,78 @@ |
8 | 8 |
#include <mspack.h> |
9 | 9 |
#include <system.h> |
10 | 10 |
|
11 |
+#if HAVE_FSEEKO |
|
12 |
+# define fseek fseeko |
|
13 |
+#endif |
|
14 |
+ |
|
11 | 15 |
#define BUF_SIZE (1024*4096) |
12 | 16 |
char buf[BUF_SIZE]; |
13 | 17 |
|
14 | 18 |
void rip(char *fname, off_t offset, unsigned int length) { |
15 |
- static unsigned int counter = 1; |
|
16 |
- struct stat st_buf; |
|
17 |
- char outname[13]; |
|
18 |
- FILE *in, *out; |
|
19 |
+ static unsigned int counter = 1; |
|
20 |
+ struct stat st_buf; |
|
21 |
+ char outname[13]; |
|
22 |
+ FILE *in = NULL, *out = NULL; |
|
19 | 23 |
|
20 |
- do { |
|
21 |
- snprintf(outname, 13, "%08u.cab", counter++); |
|
22 |
- } while (stat(outname, &st_buf) == 0); |
|
24 |
+ /* find an unused output filename */ |
|
25 |
+ do { |
|
26 |
+ snprintf(outname, 13, "%08u.cab", counter++); |
|
27 |
+ } while (stat(outname, &st_buf) == 0); |
|
23 | 28 |
|
24 |
- printf("ripping %s offset %" LD " length %u to %s\n", |
|
25 |
- fname, offset, length, outname); |
|
29 |
+ printf("ripping %s offset %" LD " length %u to %s\n", |
|
30 |
+ fname, offset, length, outname); |
|
26 | 31 |
|
27 |
- if ((in = fopen(fname, "rb"))) { |
|
28 |
-#if HAVE_FSEEKO |
|
29 |
- if (!fseeko(in, offset, SEEK_SET)) { |
|
30 |
-#else |
|
31 |
- if (!fseek(in, offset, SEEK_SET)) { |
|
32 |
-#endif |
|
33 |
- if ((out = fopen(outname, "wb"))) { |
|
34 |
- while (length > 0) { |
|
35 |
- unsigned int run = BUF_SIZE; |
|
36 |
- if (run > length) run = length; |
|
37 |
- if (fread(&buf[0], 1, run, in) != run) { |
|
38 |
- perror(fname); |
|
39 |
- break; |
|
40 |
- } |
|
41 |
- if (fwrite(&buf[0], 1, run, out) != run) { |
|
42 |
- perror(outname); |
|
43 |
- break; |
|
44 |
- } |
|
45 |
- length -= run; |
|
46 |
- } |
|
47 |
- fclose(out); |
|
48 |
- } |
|
49 |
- else { |
|
50 |
- perror(outname); |
|
51 |
- } |
|
32 |
+ if (!(in = fopen(fname, "rb"))) { |
|
33 |
+ perror(fname); |
|
34 |
+ goto cleanup; |
|
35 |
+ } |
|
36 |
+ if (!(out = fopen(outname, "wb"))) { |
|
37 |
+ perror(outname); |
|
38 |
+ goto cleanup; |
|
52 | 39 |
} |
53 |
- else { |
|
54 |
- perror(fname); |
|
40 |
+ if (fseek(in, offset, SEEK_SET)) { |
|
41 |
+ fprintf(stderr, "%s: can't seek to cab offset %"LD"\n", fname, offset); |
|
42 |
+ goto cleanup; |
|
55 | 43 |
} |
56 |
- fclose(in); |
|
57 |
- } |
|
58 |
- else { |
|
59 |
- perror(fname); |
|
60 |
- } |
|
44 |
+ while (length) { |
|
45 |
+ size_t run = (length > BUF_SIZE) ? BUF_SIZE : length; |
|
46 |
+ size_t actual = fread(&buf[0], 1, run, in); |
|
47 |
+ if (actual < run) { |
|
48 |
+ fprintf(stderr, "%s: file %u bytes shorter than expected\n", |
|
49 |
+ fname, length - (run - actual)); |
|
50 |
+ length = run = actual; |
|
51 |
+ } |
|
52 |
+ if (fwrite(&buf[0], 1, run, out) != run) { |
|
53 |
+ perror(outname); |
|
54 |
+ break; |
|
55 |
+ } |
|
56 |
+ length -= run; |
|
57 |
+ } |
|
58 |
+ |
|
59 |
+cleanup: |
|
60 |
+ if (in) fclose(in); |
|
61 |
+ if (out) fclose(out); |
|
61 | 62 |
} |
62 | 63 |
|
63 | 64 |
int main(int argc, char *argv[]) { |
64 |
- struct mscab_decompressor *cabd; |
|
65 |
- struct mscabd_cabinet *cab, *c; |
|
66 |
- int err; |
|
65 |
+ struct mscab_decompressor *cabd; |
|
66 |
+ struct mscabd_cabinet *cab, *c; |
|
67 |
+ int err; |
|
67 | 68 |
|
68 |
- MSPACK_SYS_SELFTEST(err); |
|
69 |
- if (err) return 0; |
|
69 |
+ MSPACK_SYS_SELFTEST(err); |
|
70 |
+ if (err) return 0; |
|
70 | 71 |
|
71 |
- if ((cabd = mspack_create_cab_decompressor(NULL))) { |
|
72 |
- for (argv++; *argv; argv++) { |
|
73 |
- if ((cab = cabd->search(cabd, *argv))) { |
|
74 |
- for (c = cab; c; c = c->next) rip(*argv, c->base_offset, c->length); |
|
75 |
- cabd->close(cabd, cab); |
|
76 |
- } |
|
72 |
+ if ((cabd = mspack_create_cab_decompressor(NULL))) { |
|
73 |
+ cabd->set_param(cabd, MSCABD_PARAM_SALVAGE, 1); |
|
74 |
+ for (argv++; *argv; argv++) { |
|
75 |
+ if ((cab = cabd->search(cabd, *argv))) { |
|
76 |
+ for (c = cab; c; c = c->next) { |
|
77 |
+ rip(*argv, c->base_offset, c->length); |
|
78 |
+ } |
|
79 |
+ cabd->close(cabd, cab); |
|
80 |
+ } |
|
81 |
+ } |
|
82 |
+ mspack_destroy_cab_decompressor(cabd); |
|
77 | 83 |
} |
78 |
- mspack_destroy_cab_decompressor(cabd); |
|
79 |
- } |
|
80 |
- return 0; |
|
84 |
+ return 0; |
|
81 | 85 |
} |
... | ... |
@@ -25,8 +25,6 @@ |
25 | 25 |
|
26 | 26 |
mode_t user_umask; |
27 | 27 |
|
28 |
-#define FILENAME ".test.chmx" |
|
29 |
- |
|
30 | 28 |
/** |
31 | 29 |
* Ensures that all directory components in a filepath exist. New directory |
32 | 30 |
* components are created, if necessary. |
... | ... |
@@ -51,126 +49,22 @@ static int ensure_filepath(char *path) { |
51 | 51 |
return 1; |
52 | 52 |
} |
53 | 53 |
|
54 |
-/** |
|
55 |
- * Creates a UNIX filename from the internal CAB filename and the given |
|
56 |
- * parameters. |
|
57 |
- * |
|
58 |
- * @param fname the internal CAB filename. |
|
59 |
- * @param dir a directory path to prepend to the output filename. |
|
60 |
- * @param lower if non-zero, filename should be made lower-case. |
|
61 |
- * @param isunix if zero, MS-DOS path seperators are used in the internal |
|
62 |
- * CAB filename. If non-zero, UNIX path seperators are used. |
|
63 |
- * @param utf8 if non-zero, the internal CAB filename is encoded in UTF8. |
|
64 |
- * @return a freshly allocated and created filename, or NULL if there was |
|
65 |
- * not enough memory. |
|
66 |
- * @see unix_path_seperators() |
|
67 |
- */ |
|
68 |
-static char *create_output_name(unsigned char *fname, unsigned char *dir, |
|
69 |
- int lower, int isunix, int utf8) |
|
70 |
-{ |
|
71 |
- unsigned char *p, *name, c, *fe, sep, slash; |
|
72 |
- unsigned int x; |
|
73 |
- |
|
74 |
- sep = (isunix) ? '/' : '\\'; /* the path-seperator */ |
|
75 |
- slash = (isunix) ? '\\' : '/'; /* the other slash */ |
|
76 |
- |
|
77 |
- /* length of filename */ |
|
78 |
- x = strlen((char *) fname); |
|
79 |
- /* UTF8 worst case scenario: tolower() expands all chars from 1 to 3 bytes */ |
|
80 |
- if (utf8) x *= 3; |
|
81 |
- /* length of output directory */ |
|
82 |
- if (dir) x += strlen((char *) dir); |
|
83 |
- |
|
84 |
- if (!(name = (unsigned char *) malloc(x + 2))) { |
|
85 |
- fprintf(stderr, "out of memory!\n"); |
|
86 |
- return NULL; |
|
87 |
- } |
|
88 |
- |
|
89 |
- /* start with blank name */ |
|
90 |
- *name = '\0'; |
|
91 |
- |
|
92 |
- /* add output directory if needed */ |
|
93 |
- if (dir) { |
|
94 |
- strcpy((char *) name, (char *) dir); |
|
95 |
- strcat((char *) name, "/"); |
|
96 |
- } |
|
97 |
- |
|
98 |
- /* remove leading slashes */ |
|
99 |
- while (*fname == sep) fname++; |
|
100 |
- |
|
101 |
- /* copy from fi->filename to new name, converting MS-DOS slashes to UNIX |
|
102 |
- * slashes as we go. Also lowercases characters if needed. |
|
103 |
- */ |
|
104 |
- p = &name[strlen((char *)name)]; |
|
105 |
- fe = &fname[strlen((char *)fname)]; |
|
106 |
- |
|
107 |
- if (utf8) { |
|
108 |
- /* UTF8 translates two-byte unicode characters into 1, 2 or 3 bytes. |
|
109 |
- * %000000000xxxxxxx -> %0xxxxxxx |
|
110 |
- * %00000xxxxxyyyyyy -> %110xxxxx %10yyyyyy |
|
111 |
- * %xxxxyyyyyyzzzzzz -> %1110xxxx %10yyyyyy %10zzzzzz |
|
112 |
- * |
|
113 |
- * Therefore, the inverse is as follows: |
|
114 |
- * First char: |
|
115 |
- * 0x00 - 0x7F = one byte char |
|
116 |
- * 0x80 - 0xBF = invalid |
|
117 |
- * 0xC0 - 0xDF = 2 byte char (next char only 0x80-0xBF is valid) |
|
118 |
- * 0xE0 - 0xEF = 3 byte char (next 2 chars only 0x80-0xBF is valid) |
|
119 |
- * 0xF0 - 0xFF = invalid |
|
120 |
- */ |
|
121 |
- do { |
|
122 |
- if (fname >= fe) { |
|
123 |
- free(name); |
|
124 |
- return NULL; |
|
125 |
- } |
|
126 |
- |
|
127 |
- /* get next UTF8 char */ |
|
128 |
- if ((c = *fname++) < 0x80) x = c; |
|
129 |
- else { |
|
130 |
- if ((c >= 0xC0) && (c < 0xE0)) { |
|
131 |
- x = (c & 0x1F) << 6; |
|
132 |
- x |= *fname++ & 0x3F; |
|
133 |
- } |
|
134 |
- else if ((c >= 0xE0) && (c < 0xF0)) { |
|
135 |
- x = (c & 0xF) << 12; |
|
136 |
- x |= (*fname++ & 0x3F) << 6; |
|
137 |
- x |= *fname++ & 0x3F; |
|
138 |
- } |
|
139 |
- else x = '?'; |
|
140 |
- } |
|
141 |
- |
|
142 |
- /* whatever is the path seperator -> '/' |
|
143 |
- * whatever is the other slash -> '\\' |
|
144 |
- * otherwise, if lower is set, the lowercase version */ |
|
145 |
- if (x == sep) x = '/'; |
|
146 |
- else if (x == slash) x = '\\'; |
|
147 |
- else if (lower) x = (unsigned int) tolower((int) x); |
|
148 |
- |
|
149 |
- /* integer back to UTF8 */ |
|
150 |
- if (x < 0x80) { |
|
151 |
- *p++ = (unsigned char) x; |
|
152 |
- } |
|
153 |
- else if (x < 0x800) { |
|
154 |
- *p++ = 0xC0 | (x >> 6); |
|
155 |
- *p++ = 0x80 | (x & 0x3F); |
|
156 |
- } |
|
157 |
- else { |
|
158 |
- *p++ = 0xE0 | (x >> 12); |
|
159 |
- *p++ = 0x80 | ((x >> 6) & 0x3F); |
|
160 |
- *p++ = 0x80 | (x & 0x3F); |
|
161 |
- } |
|
162 |
- } while (x); |
|
163 |
- } |
|
164 |
- else { |
|
165 |
- /* regular non-utf8 version */ |
|
166 |
- do { |
|
167 |
- c = *fname++; |
|
168 |
- if (c == sep) c = '/'; |
|
169 |
- else if (c == slash) c = '\\'; |
|
170 |
- else if (lower) c = (unsigned char) tolower((int) c); |
|
171 |
- } while ((*p++ = c)); |
|
172 |
- } |
|
173 |
- return (char *) name; |
|
54 |
+char *create_output_name(char *fname) { |
|
55 |
+ char *out, *p; |
|
56 |
+ if ((out = malloc(strlen(fname) + 1))) { |
|
57 |
+ /* remove leading slashes */ |
|
58 |
+ while (*fname == '/' || *fname == '\\') fname++; |
|
59 |
+ /* if that removes all characters, just call it "x" */ |
|
60 |
+ strcpy(out, (*fname) ? fname : "x"); |
|
61 |
+ |
|
62 |
+ /* change "../" to "xx/" */ |
|
63 |
+ for (p = out; *p; p++) { |
|
64 |
+ if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\\')) { |
|
65 |
+ p[0] = p[1] = 'x'; |
|
66 |
+ } |
|
67 |
+ } |
|
68 |
+ } |
|
69 |
+ return out; |
|
174 | 70 |
} |
175 | 71 |
|
176 | 72 |
static int sortfunc(const void *a, const void *b) { |
... | ... |
@@ -205,7 +99,7 @@ int main(int argc, char *argv[]) { |
205 | 205 |
qsort(f, numf, sizeof(struct mschmd_file *), &sortfunc); |
206 | 206 |
|
207 | 207 |
for (i = 0; i < numf; i++) { |
208 |
- char *outname = create_output_name((unsigned char *)f[i]->filename,NULL,0,1,0); |
|
208 |
+ char *outname = create_output_name(f[i]->filename); |
|
209 | 209 |
printf("Extracting %s\n", outname); |
210 | 210 |
ensure_filepath(outname); |
211 | 211 |
if (chmd->extract(chmd, f[i], outname)) { |
... | ... |
@@ -380,7 +380,8 @@ void cabd_extract_test_01() { |
380 | 380 |
"test_files/cabd/filename-read-violation-3.cab", |
381 | 381 |
"test_files/cabd/filename-read-violation-4.cab", |
382 | 382 |
"test_files/cabd/lzx-main-tree-no-lengths.cab", |
383 |
- "test_files/cabd/lzx-premature-matches.cab" |
|
383 |
+ "test_files/cabd/lzx-premature-matches.cab", |
|
384 |
+ "test_files/cabd/qtm-max-size-block.cab" |
|
384 | 385 |
}; |
385 | 386 |
|
386 | 387 |
cabd = mspack_create_cab_decompressor(NULL); |
... | ... |
@@ -34,6 +34,32 @@ void chmd_open_test_01() { |
34 | 34 |
mspack_destroy_chm_decompressor(chmd); |
35 | 35 |
} |
36 | 36 |
|
37 |
+/* check no files are returned with blank filenames */ |
|
38 |
+void chmd_open_test_02() { |
|
39 |
+ struct mschm_decompressor *chmd; |
|
40 |
+ struct mschmd_header *chm; |
|
41 |
+ struct mschmd_file *f; |
|
42 |
+ unsigned int i; |
|
43 |
+ const char *files[] = { |
|
44 |
+ "test_files/chmd/blank-filenames.chm" |
|
45 |
+ }; |
|
46 |
+ |
|
47 |
+ chmd = mspack_create_chm_decompressor(NULL); |
|
48 |
+ TEST(chmd != NULL); |
|
49 |
+ for (i = 0; i < (sizeof(files)/sizeof(char *)); i++) { |
|
50 |
+ chm = chmd->open(chmd, files[i]); |
|
51 |
+ TEST(chm != NULL); |
|
52 |
+ for (f = chm->files; f; f = f->next) { |
|
53 |
+ TEST(f->filename && f->filename[0]); |
|
54 |
+ } |
|
55 |
+ for (f = chm->sysfiles; f; f = f->next) { |
|
56 |
+ TEST(f->filename && f->filename[0]); |
|
57 |
+ } |
|
58 |
+ } |
|
59 |
+ mspack_destroy_chm_decompressor(chmd); |
|
60 |
+} |
|
61 |
+ |
|
62 |
+ |
|
37 | 63 |
/* check searching bad files doesn't crash */ |
38 | 64 |
void chmd_search_test_01() { |
39 | 65 |
struct mschm_decompressor *chmd; |
... | ... |
@@ -95,6 +121,7 @@ int main() { |
95 | 95 |
TEST(selftest == MSPACK_ERR_OK); |
96 | 96 |
|
97 | 97 |
chmd_open_test_01(); |
98 |
+ chmd_open_test_02(); |
|
98 | 99 |
chmd_search_test_01(); |
99 | 100 |
chmd_extract_test_01(); |
100 | 101 |
|