Skip to content

Commit

Permalink
Add an option to extract additional .bin files
Browse files Browse the repository at this point in the history
Both additional Inno Setup installers and RAR archives from recent
multi-part GOG.com installers are supported.

Fixes: issue #37
  • Loading branch information
dscharrer committed Sep 22, 2015
1 parent 6948838 commit 908903d
Show file tree
Hide file tree
Showing 10 changed files with 485 additions and 30 deletions.
13 changes: 11 additions & 2 deletions doc/innoextract.1
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Here is a short summary of the options available in innoextract. Please refer to
\-L \-\-lowercase Convert extracted filenames to lower-case
\-T \-\-timestamps \fITZ\fP Timezone for file times or "local" or "none"
\-d \-\-output\-dir \fIDIR\fP Extract files into the given directory
\-g \-\-gog Process additional archives from GOG.com installers
.fi
.TP
.B Filters:
Expand Down Expand Up @@ -83,6 +84,15 @@ This option takes precedence over \fB\-\-include\fP and \fB\-\-language\fP: temp
\fB\-e\fP, \fB\-\-extract\fP
Extract all files to the current directory. This action is enabled by default, unless either \fB\-\-list\fP or \fB\-\-extract\fP is specified. You may only specify one of \fB\-\-extract\fP and \fB\-\-test\fP.
.TP
\fB\-g\fP, \fB\-\-gog\fP
Try to process additional .bin files that have the same basename as the setup but are not actually part of the Inno Setup installer. This is the case for newer multi-part GOG.com installers where these .bin files are RAR archives, potential encrypted with the MD5 checksum of the game ID (see the \fB\-\-gog\-game\-id\fP option).

Extracting these RAR archives requires rar, unrar or lsar/unar command-line utilities to be in the PATH.

The \fB\-\-list\fP, \fB\-\-test\fP, \fB\-\-extract\fP and \fB\-\-output\-dir\fP options are passed along to unrar/unar, but other options may be ignored for the RAR files. For multi-part RAR archives, the \fB\-\-test\fP requires a writable output directory for temporary files.

Note that is option is geared towards GOG.com installers. Other installers may come be bundled with different extraneous \fI.bin\fP which this option might not be able to handle.
.TP
\fB\-\-gog\-game\-id\fP
Determine the ID used by GOG.com for the game contained in this installer. This will only work with Galaxy-ready GOG.com installers.

Expand All @@ -93,7 +103,6 @@ The \fB\-\-gog\-game\-id\fP action can be combined with \fB\-\-list\fP, \fB\-\-t
For newer multi-part GOG.com installers the \fI.bin\fP files are not part of the Inno Setup installer but instead are RAR archives. Some of these RAR files are encrypted, with the password being the MD5 checksum of the game ID:

\fBinnoextract \-\-gog\-game\-id --silent\fP \fIsetup_....exe\fP | \fBmd5sum\fP | \fBcut \-d\fP ' ' \fB\-f\fP 1

.TP
\fB\-h\fP, \fB\-\-help\fP
Show a list of the supported options.
Expand Down Expand Up @@ -199,7 +208,7 @@ Names for data slice/disk files in multi-file installers must follow the standar

Encrypted installers are not supported.
.SH SEE ALSO
\fBcabextract\fP(1), \fBunshield\fP(1), \fBtzset\fP(3)
\fBcabextract\fP(1), \fBunar\fP(1), \fBunrar\fP(1), \fBunshield\fP(1), \fBtzset\fP(3)
.SH BUGS
.PP
No known bugs.
Expand Down
91 changes: 64 additions & 27 deletions src/cli/extract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,51 @@ namespace fs = boost::filesystem;

namespace {

static size_t probe_bin_files(const extract_options & o, const setup::info & info,
const fs::path & dir, const std::string & basename,
size_t format = 0, size_t start = 0) {

size_t count = 0;

std::vector<fs::path> files;

for(size_t i = start;; i++) {

fs::path file;
if(format == 0) {
file = dir / basename;
} else {
file = dir / stream::slice_reader::slice_filename(basename, i, format);
}

try {
if(!fs::is_regular_file(file)) {
break;
}
} catch(...) {
break;
}

if(o.gog) {
files.push_back(file);
} else {
log_warning << file.filename() << " is not part of the installer!";
count++;
}

if(format == 0) {
break;
}

}

if(!files.empty()) {
gog::process_bin_files(files, o, info);
}

return count;
}

struct file_output {

fs::path name;
Expand All @@ -78,27 +123,6 @@ struct file_output {

};

static bool probe_bin_file(const fs::path & file) {
try {
if(!fs::is_regular_file(file)) {
return false;
}
} catch(...) {
return false;
}
log_warning << file << " is not part of the installer!";
return true;
}

static void probe_bin_files(const fs::path & dir, const std::string & basename,
size_t start, size_t format) {
for(size_t i = start;; i++) {
if(!probe_bin_file(dir / stream::slice_reader::slice_filename(basename, i, format))) {
break;
}
}
}

template <typename Entry>
class processed_item {

Expand Down Expand Up @@ -386,7 +410,7 @@ void process_file(const fs::path & file, const extract_options & o) {
if(o.list_languages) {
entries |= setup::info::Languages;
}
if(o.gog_game_id) {
if(o.gog_game_id || o.gog) {
entries |= setup::info::RegistryEntries;
}
#ifdef DEBUG
Expand Down Expand Up @@ -838,22 +862,35 @@ void process_file(const fs::path & file, const extract_options & o) {

extract_progress.clear();

if(o.warn_unused) {
probe_bin_file(dir / (basename + ".bin"));
probe_bin_file(dir / (basename + "-0" + ".bin"));
if(o.warn_unused || o.gog) {
size_t bin_count = 0;
bin_count += size_t(probe_bin_files(o, info, dir, basename + ".bin"));
bin_count += size_t(probe_bin_files(o, info, dir, basename + "-0" + ".bin"));
size_t slice = 0;
size_t format = 1;
if(!offsets.data_offset && info.header.slices_per_disk == 1) {
slice = max_slice + 1;
}
probe_bin_files(dir, basename, slice, format);
bin_count += probe_bin_files(o, info, dir, basename, format, slice);
slice = 0;
format = 2;
if(!offsets.data_offset && info.header.slices_per_disk != 1) {
slice = max_slice + 1;
format = info.header.slices_per_disk;
}
probe_bin_files(dir, basename, slice, format);
bin_count += probe_bin_files(o, info, dir, basename, format, slice);
if(bin_count) {
const char * verb = "inspecting";
if(o.extract) {
verb = "extracting";
} else if(o.test) {
verb = "testing";
} else if(o.list) {
verb = "listing the contents of";
}
std::cerr << color::yellow << "Use the --gog option to try " << verb << " "
<< (bin_count > 1 ? "these files" : "this file") << ".\n" << color::reset;
}
}

}
2 changes: 2 additions & 0 deletions src/cli/extract.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ struct extract_options {
bool preserve_file_times; //!< Set timestamps of extracted files
bool local_timestamps; //!< Use local timezone for setting timestamps

bool gog; //!< Try to extract additional archives used in GOG.com installers

bool extract_temp; //!< Extract temporary files
bool default_language; //!< Extract files not associated with any language
std::string language; //!< Extract only files for this language
Expand Down
Loading

0 comments on commit 908903d

Please sign in to comment.