From dce7a287e7b620eba2c12cee19ec3e2aebfc69cf Mon Sep 17 00:00:00 2001 From: Daniel Scharrer Date: Tue, 5 Jun 2018 04:57:31 +0200 Subject: [PATCH] gogalaxy: Convert GOG Galaxy file constraints --- src/cli/goggalaxy.cpp | 156 +++++++++++++++++++++++++++++++++++++++ src/cli/goggalaxy.hpp | 2 + src/setup/expression.cpp | 2 +- 3 files changed, 159 insertions(+), 1 deletion(-) diff --git a/src/cli/goggalaxy.cpp b/src/cli/goggalaxy.cpp index a3c7f10..d8ce2b6 100644 --- a/src/cli/goggalaxy.cpp +++ b/src/cli/goggalaxy.cpp @@ -20,11 +20,13 @@ #include "cli/goggalaxy.hpp" +#include #include #include #include #include +#include #include "crypto/checksum.hpp" @@ -180,6 +182,67 @@ struct constraint { }; +std::vector parse_constraints(const std::string & input) { + + std::vector result; + + size_t start = 0; + + while(start < input.length()) { + + start = input.find_first_not_of(" \t\r\n", start); + if(start == std::string::npos) { + break; + } + + bool negated = false; + if(input[start] == '!') { + negated = true; + start++; + } + + size_t end = input.find('#', start); + if(end == std::string::npos) { + end = input.length(); + } + + if(end != start) { + std::string token = input.substr(start, end - start); + boost::trim(token); + result.push_back(constraint(token, negated)); + } + + if(end == std::string::npos) { + end = input.length(); + } + + start = end + 1; + } + + return result; +} + +std::string create_constraint_expression(std::vector & constraints) { + + std::string result; + + BOOST_FOREACH(const constraint & constraint, constraints) { + + if(!result.empty()) { + result += " or "; + } + + if(constraint.negated) { + result += " not "; + } + + result += constraint.name; + + } + + return result; +} + } // anonymous namespace void parse_galaxy_files(setup::info & info) { @@ -187,6 +250,8 @@ void parse_galaxy_files(setup::info & info) { setup::file_entry * file_start = NULL; size_t remaining_parts = 0; + std::set all_languages; + BOOST_FOREACH(setup::file_entry & file, info.files) { // Multi-part file info: file checksum, filename, part count @@ -306,12 +371,103 @@ void parse_galaxy_files(setup::info & info) { remaining_parts = 0; } + if(!file.destination.empty()) { + // languages, architectures, winversions + std::vector check = parse_function_call(file.check, "check_if_install"); + if(!check.empty()) { + if(check.size() >= 1 && !check[0].empty()) { + std::vector languages = parse_constraints(check[0]); + BOOST_FOREACH(const constraint & language, languages) { + all_languages.insert(language.name); + } + } + + } + } + } if(remaining_parts != 0) { log_warning << "Incomplete GOG Galaxy file " << file_start->destination; } + /* + * GOG Galaxy multi-part files also have their own constraints, convert these to standard + * Inno Setup ones. + * + * Do this in a separate loop to not break constraint checks above. + */ + + BOOST_FOREACH(setup::file_entry & file, info.files) { + + if(file.destination.empty()) { + continue; + } + + // languages, architectures, winversions + std::vector check = parse_function_call(file.check, "check_if_install"); + if(!check.empty()) { + + if(check.size() >= 1 && !check[0].empty()) { + + std::vector languages = parse_constraints(check[0]); + + // Ignore constraints that just contain all languages + bool has_all_languages = false; + if(languages.size() >= all_languages.size() && all_languages.size() > 1) { + has_all_languages = true; + BOOST_FOREACH(const std::string & known_language, all_languages) { + bool has_language = false; + BOOST_FOREACH(const constraint & language, languages) { + if(!language.negated && language.name == known_language) { + has_language = true; + break; + } + } + if(!has_language) { + has_all_languages = false; + break; + } + } + } + + if(!languages.empty() && !has_all_languages) { + if(!file.languages.empty()) { + log_warning << "Overwriting language constraints for GOG Galaxy file " << file.destination; + } + file.languages = create_constraint_expression(languages); + } + + } + + if(check.size() >= 2 && !check[1].empty() && check[1] != "32#64#") { + log_warning << "Ignoring architecture constraint for GOG Galaxy file " << file.destination + << ": " << check[1]; + } + + if(check.size() >= 3 && !check[2].empty()) { + log_warning << "Ignoring OS constraint for GOG Galaxy file " << file.destination + << ": " << check[2]; + } + + if(file.components.empty()) { + file.components = "game"; + } + + } + + // component id, ? + std::vector dependency = parse_function_call(file.check, "check_if_install_dependency"); + if(!dependency.empty()) { + + if(file.components.empty() && dependency.size() >= 1 && !dependency[0].empty()) { + file.components = dependency[0]; + } + + } + + } + } } //namespace gog diff --git a/src/cli/goggalaxy.hpp b/src/cli/goggalaxy.hpp index bccab02..13c0e99 100644 --- a/src/cli/goggalaxy.hpp +++ b/src/cli/goggalaxy.hpp @@ -41,6 +41,8 @@ namespace gog { * * Each part (including the first) has an after_install script with a checksum for the decompressed * part as well as compressed and decompressed sizes. + * + * Additionally, language constrained are also parsed from check scripts and added to the language list. */ void parse_galaxy_files(setup::info & info); diff --git a/src/setup/expression.cpp b/src/setup/expression.cpp index 0c1e1eb..a8b9e44 100644 --- a/src/setup/expression.cpp +++ b/src/setup/expression.cpp @@ -32,7 +32,7 @@ namespace setup { namespace { static bool is_identifier_start(char c) { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'; + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '-'; } static bool is_identifier(char c) {