From 94ffb9cd375120eb47f1e52e9ea4fa632646e239 Mon Sep 17 00:00:00 2001 From: Daniel Scharrer Date: Tue, 5 Jun 2018 00:59:29 +0200 Subject: [PATCH] Fix slice file name for Inno Setup < 4.1.7 For backwards compatibility we now always try both the slice filename derived from the setup filename as well as the one derived from the basename stored in the setup headers. The setup version only determines which name to try first. Fixes: issue #59 --- CHANGELOG | 1 + src/cli/extract.cpp | 17 ++++++++++++----- src/cli/gog.cpp | 7 +++++-- src/cli/gog.hpp | 2 +- src/stream/slice.cpp | 19 +++++++++++++++---- src/stream/slice.hpp | 5 ++++- 6 files changed, 38 insertions(+), 13 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 2a97bfa..fc660e5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,7 @@ innoextract 1.7 (TDB) - Added (preliminary) support for Inno Setup 5.6.0 installers - Fixed building in paths that contain regex expressions - Fixed case-sensitivity in parent directory when creating subdirectories + - Fixed .bin slice file names used with Inno Setup versions older than 4.1.7 innoextract 1.6 (2016-03-24) - Added support for Inno Setup 5.5.7 (and 5.5.8) installers diff --git a/src/cli/extract.cpp b/src/cli/extract.cpp index 60c457b..fa2c226 100644 --- a/src/cli/extract.cpp +++ b/src/cli/extract.cpp @@ -782,15 +782,22 @@ void process_file(const fs::path & file, const extract_options & o) { total_size += location.uncompressed_size; } - fs::path dir = file.parent_path(); - std::string basename = util::as_string(file.stem()); - boost::scoped_ptr slice_reader; if(o.extract || o.test) { if(offsets.data_offset) { slice_reader.reset(new stream::slice_reader(&ifs, offsets.data_offset)); } else { - slice_reader.reset(new stream::slice_reader(dir, basename, info.header.slices_per_disk)); + fs::path dir = file.parent_path(); + std::string basename = util::as_string(file.stem()); + std::string basename2 = info.header.base_filename; + // Prevent access to unexpected files + std::replace(basename2.begin(), basename2.end(), '/', '_'); + std::replace(basename2.begin(), basename2.end(), '\\', '_'); + // Older Inno Setup versions used the basename stored in the headers, change our default accordingly + if(info.version < INNO_VERSION(4, 1, 7) && !basename2.empty()) { + std::swap(basename2, basename); + } + slice_reader.reset(new stream::slice_reader(dir, basename, basename2, info.header.slices_per_disk)); } } @@ -963,7 +970,7 @@ void process_file(const fs::path & file, const extract_options & o) { extract_progress.clear(); if(o.warn_unused || o.gog) { - gog::probe_bin_files(o, info, dir, basename, offsets.data_offset == 0); + gog::probe_bin_files(o, info, file, offsets.data_offset == 0); } } diff --git a/src/cli/gog.cpp b/src/cli/gog.cpp index dfdb35f..3a27bb7 100644 --- a/src/cli/gog.cpp +++ b/src/cli/gog.cpp @@ -488,8 +488,11 @@ size_t probe_bin_file_series(const extract_options & o, const setup::info & info } // anonymous namespace -void probe_bin_files(const extract_options & o, const setup::info & info, const fs::path & dir, - const std::string & basename, bool external) { +void probe_bin_files(const extract_options & o, const setup::info & info, + const fs::path & setup_file, bool external) { + + boost::filesystem::path dir = setup_file.parent_path(); + std::string basename = util::as_string(setup_file.stem()); size_t bin_count = 0; bin_count += probe_bin_file_series(o, info, dir, basename + ".bin"); diff --git a/src/cli/gog.hpp b/src/cli/gog.hpp index 7b09435..281ecbb 100644 --- a/src/cli/gog.hpp +++ b/src/cli/gog.hpp @@ -41,7 +41,7 @@ namespace gog { std::string get_game_id(const setup::info & info); void probe_bin_files(const extract_options & o, const setup::info & info, - const boost::filesystem::path & dir, const std::string & basename, bool external); + const boost::filesystem::path & setup_file, bool external); } // namespace gog diff --git a/src/stream/slice.cpp b/src/stream/slice.cpp index 335ddea..d9eb55e 100644 --- a/src/stream/slice.cpp +++ b/src/stream/slice.cpp @@ -57,10 +57,10 @@ slice_reader::slice_reader(std::istream * istream, boost::uint32_t data_offset) } } -slice_reader::slice_reader(const path_type & dir, const std::string & base_file, - size_t slices_per_disk) +slice_reader::slice_reader(const path_type & dir, const std::string & basename, + const std::string & basename2, size_t slices_per_disk) : data_offset(0), - dir(dir), base_file(base_file), + dir(dir), base_file(basename), base_file2(basename2), slices_per_disk(slices_per_disk), current_slice(0), slice_size(0), is(&ifs) { } @@ -79,6 +79,10 @@ void slice_reader::seek(size_t slice) { bool slice_reader::open_file(const path_type & file) { + if(!boost::filesystem::exists(file)) { + return false; + } + log_info << "Opening \"" << color::cyan << file.string() << color::reset << '"'; ifs.close(); @@ -160,13 +164,20 @@ void slice_reader::open(size_t slice) { ifs.close(); path_type slice_file = slice_filename(base_file, slice, slices_per_disk); - if(open_file(dir / slice_file)) { return; } + path_type slice_file2 = slice_filename(base_file2, slice, slices_per_disk); + if(!base_file2.empty() && slice_file2 != slice_file && open_file(dir / slice_file2)) { + return; + } + std::ostringstream oss; oss << "could not open slice " << slice << ": " << slice_file; + if(!base_file2.empty() && slice_file2 != slice_file) { + oss << " or " << slice_file2; + } throw slice_error(oss.str()); } diff --git a/src/stream/slice.hpp b/src/stream/slice.hpp index 45be534..e0986ea 100644 --- a/src/stream/slice.hpp +++ b/src/stream/slice.hpp @@ -64,6 +64,7 @@ class slice_reader : public boost::iostreams::source { // Information for eading external setup data path_type dir; //!< Slice directory specified at construction. std::string base_file; //!< Base file name for slices. + std::string base_file2; //!< Fallback base filename for slices. const size_t slices_per_disk; //!< Number of slices grouped into each disk (for names). // Information about the current slice @@ -110,9 +111,11 @@ public: * * \param dir The directory containing the slice files. * \param basename The base name for slice files. + * \param basename2 Alternative base name for slice files. * \param slices_per_disk How many slices are grouped into one disk. Must not be \c 0. */ - slice_reader(const path_type & dir, const std::string & basename, size_t slices_per_disk); + slice_reader(const path_type & dir, const std::string & basename, const std::string & basename2, + size_t slices_per_disk); /*! * Attempt to seek to an offset within a slice.