--- lib/component.c.orig +++ lib/component.c @@ -40,11 +40,13 @@ case 7: case 8: case 9: + case 10: + case 11: + case 12: + case 13: + default: p += 0x6b; break; - - default: - abort(); } self->file_group_count = READ_UINT16(p); p += 2; --- lib/file.c.orig +++ lib/file.c @@ -77,6 +77,11 @@ case 7: case 8: case 9: + case 10: + case 11: + case 12: + case 13: + default: saved_p = p = header->data + header->common.cab_descriptor_offset + header->cab.file_table_offset + @@ -117,10 +122,6 @@ assert((p - saved_p) == 0x57); break; - - default: - unshield_error("Unknown major version: %i", header->major_version); - abort(); } if (!(fd->flags & FILE_COMPRESSED) && @@ -363,6 +364,11 @@ case 7: case 8: case 9: + case 10: + case 11: + case 12: + case 13: + default: { uint8_t six_header[VOLUME_HEADER_SIZE_V6]; uint8_t* p = six_header; @@ -389,10 +395,6 @@ reader->volume_header.last_file_size_compressed_high = READ_UINT32(p); p += 4; } break; - - default: - abort(); - goto exit; } #if VERBOSE >= 2 --- lib/libunshield.c.orig +++ lib/libunshield.c @@ -205,7 +205,7 @@ /** Read all header files */ -static bool unshield_read_headers(Unshield* unshield)/*{{{*/ +static bool unshield_read_headers(Unshield* unshield, int version)/*{{{*/ { int i; bool iterate = true; @@ -268,8 +268,21 @@ unshield_error("Failed to read common header from header file %i", i); goto error; } - - header->major_version = (header->common.version >> 12) & 0xf; + + if (version != -1) + { + header->major_version = version; + } + else if (header->common.version >> 24 == 1) + { + header->major_version = (header->common.version >> 12) & 0xf; + } + else if (header->common.version >> 24 == 2) + { + header->major_version = (header->common.version & 0xffff); + if (header->major_version != 0) + header->major_version = header->major_version / 100; + } #if 0 if (header->major_version < 5) @@ -326,6 +339,11 @@ Unshield* unshield_open(const char* filename)/*{{{*/ { + unshield_open_force_version(filename, -1); +}/*}}}*/ + +Unshield* unshield_open_force_version(const char* filename, int version)/*{{{*/ +{ Unshield* unshield = NEW1(Unshield); if (!unshield) { @@ -339,7 +357,7 @@ goto error; } - if (!unshield_read_headers(unshield)) + if (!unshield_read_headers(unshield, version)) { unshield_error("Failed to read header files"); goto error; --- lib/libunshield.h.orig +++ lib/libunshield.h @@ -33,6 +33,7 @@ */ Unshield* unshield_open(const char* filename); +Unshield* unshield_open_force_version(const char* filename, int version); void unshield_close(Unshield* unshield); /* --- man/unshield.1.orig +++ man/unshield.1 @@ -2,7 +2,7 @@ .SH NAME unshield \- extract CAB files from an InstallShield installer archive .SH SYNOPSIS -unshield [\-c COMPONENT] [\-d DIRECTORY] [\-D LEVEL] [\-g GROUP] [\-h] [\-j] [\-L] [\-n] [\-o] [\-O] [\-r] [\-v] [\-V] c|g|l|t|x CABFILE +unshield [\-c COMPONENT] [\-d DIRECTORY] [\-D LEVEL] [\-g GROUP] [\-h] [\-i VERSION] [\-j] [\-L] [\-n] [\-o] [\-O] [\-r] [\-v] [\-V] c|g|l|t|x CABFILE .SH DESCRIPTION Unshield extracts CAB files from InstallShield installers, used to install software on Microsoft Windows based machines. @@ -27,6 +27,11 @@ \fB\-h\fR Show help message .TP +\fB\-i\fR VERSION +Force InstallShield version number (don't autodetect)\n +.br +Use this option if you have a very old archive (generated with InstallShield <= 4) and / or the automatic detection fails +.TP \fB\-j\fR Junk paths (do not make directories) .TP --- src/unshield.c.orig +++ src/unshield.c @@ -58,6 +58,7 @@ static int log_level = UNSHIELD_LOG_LEVEL_LOWEST; static int exit_status = 0; static FORMAT format = FORMAT_NEW; +static int is_version = -1; static bool make_sure_directory_exists(const char* directory)/*{{{*/ { @@ -108,7 +109,7 @@ fprintf(stderr, "Syntax:\n" "\n" - "\t%s [-c COMPONENT] [-d DIRECTORY] [-D LEVEL] [-g GROUP] [-GhlOrV] c|g|l|t|x CABFILE\n" + "\t%s [-c COMPONENT] [-d DIRECTORY] [-D LEVEL] [-g GROUP] [-i VERSION] [-GhlOrV] c|g|l|t|x CABFILE\n" "\n" "Options:\n" "\t-c COMPONENT Only list/extract this component\n" @@ -120,6 +121,7 @@ "\t 3 - Errors, warnings and debug messages\n" "\t-g GROUP Only list/extract this file group\n" "\t-h Show this help message\n" + "\t-i VERSION Force InstallShield version number (don't autodetect)\n" "\t-j Junk paths (do not make directories)\n" "\t-L Make file and directory names lowercase\n" "\t-O Use old compression\n" @@ -152,7 +154,7 @@ { int c; - while ((c = getopt(argc, argv, "c:d:D:g:hjLnoOrV")) != -1) + while ((c = getopt(argc, argv, "c:d:D:g:hi:jLnoOrV")) != -1) { switch (c) { @@ -172,6 +174,10 @@ file_group_name = optarg; break; + case 'i': + is_version = atoi(optarg); + break; + case 'j': junk_paths = true; break; @@ -532,7 +538,7 @@ cabfile = argv[last_optind]; - unshield = unshield_open(cabfile); + unshield = unshield_open_force_version(cabfile, is_version); if (!unshield) { fprintf(stderr, "Failed to open %s as an InstallShield Cabinet File\n", cabfile);