diff --git a/src/cli/extract.cpp b/src/cli/extract.cpp index ae72f21f..686e1a84 100644 --- a/src/cli/extract.cpp +++ b/src/cli/extract.cpp @@ -890,6 +890,42 @@ void create_output_directory(const extract_options & o) { } // anonymous namespace +void dump_compiledcode(std::istream & is, const loader::offsets & offsets, const setup::info & info, const extract_options & o) { + setup::version version; + is.seekg(offsets.header_offset); + version.load(is); + + std::string filename = "compiledCode.bin"; + + if(!o.quiet) { + std::cout << "Dumping compiled setup code to \"" + << color::white << filename << color::reset << "\"\n"; + } else if(!o.silent) { + std::cout << filename << '\n'; + } + + fs::path path = o.output_dir / filename; + util::ofstream ofs; + try { + ofs.open(path, std::ios_base::out | std::ios_base::trunc | std::ios_base::binary); + if(!ofs.is_open()) { + throw std::exception(); + } + } catch(...) { + throw std::runtime_error("Could not open output file \"" + path.string() + '"'); + } + + try { + ofs.write(info.header.compiled_code.c_str(), static_cast(info.header.compiled_code.length())); + } catch(const std::exception & e) { + std::ostringstream oss; + oss << "Stream error while dumping compiled setup code!\n"; + oss << " ├─ detected setup version: " << version << '\n'; + oss << " └─ error reason: " << e.what(); + throw format_error(oss.str()); + } +} + void process_file(const fs::path & installer, const extract_options & o) { bool is_directory; @@ -992,6 +1028,12 @@ void process_file(const fs::path & installer, const extract_options & o) { throw format_error(oss.str()); } + if(o.dump_compiledcode) { + create_output_directory(o); + dump_compiledcode(ifs, offsets, info, o); + return; + } + if(o.gog_galaxy && (o.list || o.test || o.extract || o.list_languages)) { gog::parse_galaxy_files(info, o.gog); } diff --git a/src/cli/extract.hpp b/src/cli/extract.hpp index e6a84d62..8f5504bc 100644 --- a/src/cli/extract.hpp +++ b/src/cli/extract.hpp @@ -33,7 +33,9 @@ #include #include +#include "loader/offsets.hpp" #include "setup/filename.hpp" +#include "setup/info.hpp" struct format_error : public std::runtime_error { explicit format_error(const std::string & reason) : std::runtime_error(reason) { } @@ -60,6 +62,7 @@ struct extract_options { #ifdef DEBUG bool dump_headers; //!< Dump setup headers #endif + bool dump_compiledcode; //!< Dump compiled code bool list; //!< List files bool test; //!< Test files (but don't extract) bool extract; //!< Extract files @@ -119,4 +122,6 @@ struct extract_options { void process_file(const boost::filesystem::path & installer, const extract_options & o); +void dump_compiledcode(std::istream & is, const loader::offsets & offsets, const setup::info & info, const extract_options & o); + #endif // INNOEXTRACT_CLI_EXTRACT_HPP diff --git a/src/cli/main.cpp b/src/cli/main.cpp index 82b72d35..bd7a9135 100644 --- a/src/cli/main.cpp +++ b/src/cli/main.cpp @@ -144,6 +144,7 @@ int main(int argc, char * argv[]) { #ifdef DEBUG ("dump-headers", "Dump decompressed setup headers") #endif + ("dump-compiledcode", "Dump decompressed compiled code binary") ; po::options_description modifiers("Modifiers"); @@ -442,6 +443,14 @@ int main(int argc, char * argv[]) { } #endif + o.dump_compiledcode = (options.count("dump-compiledcode") != 0); + if(o.dump_compiledcode) { + if(explicit_action || o.data_version) { + log_error << "Combining --dump-compiledcode with other options is not allowed"; + return ExitUserError; + } + } + o.extract_unknown = (options.count("no-extract-unknown") == 0); const std::vector & files = options["setup-files"]