From 5a850cd1558792ec76db03e2a2370a394fc0f0e1 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 12 Nov 2016 02:19:54 +0000 Subject: [PATCH 1/8] Add some useful string functions --- src/openrct2/core/String.cpp | 88 ++++++++++++++++++++++++++++++++++++ src/openrct2/core/String.hpp | 17 +++++++ 2 files changed, 105 insertions(+) diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index 5f3fafd435..15e80d2490 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -15,6 +15,7 @@ #pragma endregion #include +#include extern "C" { @@ -116,6 +117,19 @@ namespace String } } + size_t IndexOf(const utf8 * str, utf8 match, size_t startIndex) + { + const utf8 * ch = str + startIndex; + for (; *ch != '\0'; ch++) + { + if (*ch == match) + { + return (size_t)(ch - str); + } + } + return SIZE_MAX; + } + size_t LastIndexOf(const utf8 * str, utf8 match) { const utf8 * lastOccurance = nullptr; @@ -300,6 +314,80 @@ namespace String return DiscardUse(ptr, String::Duplicate(replacement)); } + utf8 * Substring(const utf8 * buffer, size_t index) + { + size_t bufferSize = String::SizeOf(buffer); + bool goodSubstring = index <= bufferSize; + Guard::Assert(goodSubstring, "Substring past end of input string."); + + // If assertion continues, return empty string to avoid crash + if (!goodSubstring) + { + return String::Duplicate(""); + } + + return String::Duplicate(buffer + index); + } + + utf8 * Substring(const utf8 * buffer, size_t index, size_t size) + { + size_t bufferSize = String::SizeOf(buffer); + bool goodSubstring = index + size <= bufferSize; + Guard::Assert(goodSubstring, "Substring past end of input string."); + + // If assertion continues, cap the substring to avoid crash + if (!goodSubstring) + { + if (index >= bufferSize) + { + size = 0; + } + else + { + size = bufferSize - index; + } + } + + utf8 * result = Memory::Allocate(size + 1); + Memory::Copy(result, buffer + index, size); + result[size] = '\0'; + return result; + } + + size_t Split(utf8 * * * values, const utf8 * buffer, utf8 delimiter) + { + std::vector valuesList; + size_t index = 0; + size_t nextIndex; + do + { + nextIndex = String::IndexOf(buffer, '/', index); + utf8 * value; + if (nextIndex == SIZE_MAX) + { + value = String::Substring(buffer, index); + } + else + { + value = String::Substring(buffer, index, nextIndex - index); + } + valuesList.push_back(value); + index = nextIndex + 1; + } while (nextIndex != SIZE_MAX); + + *values = nullptr; + if (valuesList.size() > 0) + { + utf8 * * valuesArray = Memory::AllocateArray(valuesList.size()); + for (size_t i = 0; i < valuesList.size(); i++) + { + valuesArray[i] = valuesList[i]; + } + *values = valuesArray; + } + return valuesList.size(); + } + utf8 * SkipBOM(utf8 * buffer) { return (utf8*)SkipBOM((const utf8 *)buffer); diff --git a/src/openrct2/core/String.hpp b/src/openrct2/core/String.hpp index 427374b2af..1416764dce 100644 --- a/src/openrct2/core/String.hpp +++ b/src/openrct2/core/String.hpp @@ -32,6 +32,7 @@ namespace String bool Equals(const std::string &a, const std::string &b, bool ignoreCase = false); bool Equals(const utf8 * a, const utf8 * b, bool ignoreCase = false); bool StartsWith(const utf8 * str, const utf8 * match, bool ignoreCase = false); + size_t IndexOf(const utf8 * str, utf8 match, size_t startIndex = 0); size_t LastIndexOf(const utf8 * str, utf8 match); /** @@ -64,6 +65,22 @@ namespace String */ utf8 * DiscardDuplicate(utf8 * * ptr, const utf8 * replacement); + /** + * Creates a new string containing the characters between index and and end of the input string. + */ + utf8 * Substring(const utf8 * buffer, size_t index); + + /** + * Creates a new string containing the characters between index and index + size of the input string. + */ + utf8 * Substring(const utf8 * buffer, size_t index, size_t size); + + /** + * Splits the given string by a delimiter and returns the values as a new string array. + * @returns the number of values. + */ + size_t Split(utf8 * * * values, const utf8 * buffer, utf8 delimiter); + utf8 * SkipBOM(utf8 * buffer); const utf8 * SkipBOM(const utf8 * buffer); From 925d64249f50e78c1639df7bf476d33acf79e4b8 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 12 Nov 2016 02:21:42 +0000 Subject: [PATCH 2/8] Add openrct2:// uri scheme support This sets up a URI scheme for openrct2 for Windows by adding the necessary registry keys. This is done on startup every time to keep the binary location up to date. URI handling currently supports joining a server. --- src/openrct2/cmdline/CommandLine.hpp | 1 + src/openrct2/cmdline/RootCommands.cpp | 1 + src/openrct2/cmdline/UriHandler.cpp | 93 +++++++++++++++++++++++++++ src/openrct2/libopenrct2.vcxproj | 1 + src/openrct2/platform/platform.h | 1 + src/openrct2/platform/windows.c | 49 +++++++++++++- 6 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 src/openrct2/cmdline/UriHandler.cpp diff --git a/src/openrct2/cmdline/CommandLine.hpp b/src/openrct2/cmdline/CommandLine.hpp index 21463f9467..2014326da6 100644 --- a/src/openrct2/cmdline/CommandLine.hpp +++ b/src/openrct2/cmdline/CommandLine.hpp @@ -110,4 +110,5 @@ namespace CommandLine exitcode_t HandleCommandDefault(); exitcode_t HandleCommandConvert(CommandLineArgEnumerator * enumerator); + exitcode_t HandleCommandUri(CommandLineArgEnumerator * enumerator); } diff --git a/src/openrct2/cmdline/RootCommands.cpp b/src/openrct2/cmdline/RootCommands.cpp index b68ca8e7f1..1d64d017b8 100644 --- a/src/openrct2/cmdline/RootCommands.cpp +++ b/src/openrct2/cmdline/RootCommands.cpp @@ -126,6 +126,7 @@ const CommandLineCommand CommandLine::RootCommands[] DefineCommand("set-rct2", "", StandardOptions, HandleCommandSetRCT2), DefineCommand("convert", " ", StandardOptions, CommandLine::HandleCommandConvert), DefineCommand("scan-objects", "", StandardOptions, HandleCommandScanObjects), + DefineCommand("handle-uri", "openrct2://.../", StandardOptions, CommandLine::HandleCommandUri), #if defined(__WINDOWS__) && !defined(__MINGW32__) DefineCommand("register-shell", "", RegisterShellOptions, HandleCommandRegisterShell), diff --git a/src/openrct2/cmdline/UriHandler.cpp b/src/openrct2/cmdline/UriHandler.cpp new file mode 100644 index 0000000000..041f6c0bb9 --- /dev/null +++ b/src/openrct2/cmdline/UriHandler.cpp @@ -0,0 +1,93 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../core/Console.hpp" +#include "../core/Memory.hpp" +#include "../core/String.hpp" +#include "../network/network.h" +#include "CommandLine.hpp" + +extern "C" +{ + #include "../openrct2.h" +} + +static exitcode_t HandleUri(const utf8 * uri); + +exitcode_t CommandLine::HandleCommandUri(CommandLineArgEnumerator * enumerator) +{ + const utf8 * uri; + if (enumerator->TryPopString(&uri)) + { + if (String::StartsWith(uri, "openrct2://")) + { + const utf8 * uriCommand = uri + 11; + return HandleUri(uriCommand); + } + } + + Console::Error::WriteLine("Invalid URI"); + return EXITCODE_FAIL; +} + +static exitcode_t HandleUri(const utf8 * uri) +{ + utf8 * * args; + size_t numArgs = String::Split(&args, uri, '/'); + if (numArgs > 0) + { + utf8 * arg = args[0]; + if (String::Equals(arg, "join")) + { + if (numArgs > 1) + { + utf8 * hostnamePort = args[1]; + + // Argument is in hostname:port format, so we need to split + utf8 * hostname = String::Duplicate(hostnamePort); + sint32 port = NETWORK_DEFAULT_PORT; + size_t colonIndex = String::IndexOf(hostnamePort, ':'); + if (colonIndex != SIZE_MAX) + { + Memory::Free(hostname); + hostname = String::Substring(hostnamePort, 0, colonIndex); + port = atoi(hostnamePort + colonIndex + 1); + } + + // Set the network start configuration + gNetworkStart = NETWORK_MODE_CLIENT; + String::Set(gNetworkStartHost, sizeof(gNetworkStartHost), hostname); + gNetworkStartPort = port; + + Memory::Free(hostname); + } + else + { + Console::Error::WriteLine("Expected hostname:port after join"); + return EXITCODE_FAIL; + } + } + } + + // Clean up + for (size_t i = 0; i < numArgs; i++) + { + Memory::Free(args[i]); + } + Memory::FreeArray(args, numArgs); + + return EXITCODE_CONTINUE; +} diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 8096eb5290..fe636745d1 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -72,6 +72,7 @@ + diff --git a/src/openrct2/platform/platform.h b/src/openrct2/platform/platform.h index df2181f2c5..535b33fedf 100644 --- a/src/openrct2/platform/platform.h +++ b/src/openrct2/platform/platform.h @@ -224,6 +224,7 @@ void core_init(); HWND windows_get_window_handle(); void platform_setup_file_associations(); void platform_remove_file_associations(); + bool platform_setup_uri_protocol(); // This function cannot be marked as 'static', even though it may seem to be, // as it requires external linkage, which 'static' prevents __declspec(dllexport) sint32 StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, sint32 nCmdShow); diff --git a/src/openrct2/platform/windows.c b/src/openrct2/platform/windows.c index fa568c323d..e46fbbd84b 100644 --- a/src/openrct2/platform/windows.c +++ b/src/openrct2/platform/windows.c @@ -1040,7 +1040,8 @@ utf8* platform_get_username() { // File association setup /////////////////////////////////////////////////////////////////////////////// -#define SOFTWARE_CLASSES L"Software\\Classes" +#define SOFTWARE_CLASSES L"Software\\Classes" +#define MUI_CACHE L"Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache" static void get_progIdName(wchar_t *dst, const utf8 *extension) { @@ -1183,4 +1184,50 @@ void platform_remove_file_associations() } /////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// URI protocol association setup +/////////////////////////////////////////////////////////////////////////////// + +bool platform_setup_uri_protocol() +{ + log_verbose("Setting up URI protocol..."); + + // [HKEY_CURRENT_USER\Software\Classes] + HKEY hRootKey; + if (RegOpenKeyW(HKEY_CURRENT_USER, SOFTWARE_CLASSES, &hRootKey) == ERROR_SUCCESS) { + // [hRootKey\openrct2] + HKEY hClassKey; + if (RegCreateKeyA(hRootKey, "openrct2", &hClassKey) == ERROR_SUCCESS) { + if (RegSetValueA(hClassKey, NULL, REG_SZ, "URL:openrct2", 0) == ERROR_SUCCESS) { + if (RegSetKeyValueA(hClassKey, NULL, "URL Protocol", REG_SZ, "", 0) == ERROR_SUCCESS) { + // [hRootKey\openrct2\shell\open\command] + wchar_t exePath[MAX_PATH]; + GetModuleFileNameW(NULL, exePath, MAX_PATH); + + wchar_t buffer[512]; + swprintf_s(buffer, sizeof(buffer), L"\"%s\" handle-uri \"%%1\"", exePath); + if (RegSetValueW(hClassKey, L"shell\\open\\command", REG_SZ, buffer, 0) == ERROR_SUCCESS) { + // Not compulsory, but gives the application a nicer name + // [HKEY_CURRENT_USER\SOFTWARE\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache] + HKEY hMuiCacheKey; + if (RegCreateKeyW(hRootKey, MUI_CACHE, &hMuiCacheKey) == ERROR_SUCCESS) { + swprintf_s(buffer, sizeof(buffer), L"%s.FriendlyAppName", exePath); + RegSetKeyValueW(hMuiCacheKey, NULL, buffer, REG_SZ, L"OpenRCT2", sizeof(L"OpenRCT2") + 1); + } + + log_verbose("URI protocol setup successful"); + return true; + } + } + } + } + } + + log_verbose("URI protocol setup failed"); + return false; +} + +/////////////////////////////////////////////////////////////////////////////// + #endif From 7ccce750a6855b12740d984c5e6551692ca52a1c Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Feb 2017 15:23:47 +0000 Subject: [PATCH 3/8] Use std::string instead of char * for UriHandler --- src/openrct2/cmdline/UriHandler.cpp | 72 ++++++++++++++--------------- src/openrct2/core/String.cpp | 30 ++++-------- src/openrct2/core/String.hpp | 3 +- 3 files changed, 47 insertions(+), 58 deletions(-) diff --git a/src/openrct2/cmdline/UriHandler.cpp b/src/openrct2/cmdline/UriHandler.cpp index 041f6c0bb9..b935e36439 100644 --- a/src/openrct2/cmdline/UriHandler.cpp +++ b/src/openrct2/cmdline/UriHandler.cpp @@ -18,14 +18,11 @@ #include "../core/Memory.hpp" #include "../core/String.hpp" #include "../network/network.h" +#include "../OpenRCT2.h" #include "CommandLine.hpp" -extern "C" -{ - #include "../openrct2.h" -} - -static exitcode_t HandleUri(const utf8 * uri); +static exitcode_t HandleUri(const std::string &uri); +static bool TryParseHostnamePort(const std::string &hostnamePort, std::string * outHostname, sint32 * outPort, sint32 defaultPort); exitcode_t CommandLine::HandleCommandUri(CommandLineArgEnumerator * enumerator) { @@ -43,36 +40,22 @@ exitcode_t CommandLine::HandleCommandUri(CommandLineArgEnumerator * enumerator) return EXITCODE_FAIL; } -static exitcode_t HandleUri(const utf8 * uri) +static exitcode_t HandleUri(const std::string &uri) { - utf8 * * args; - size_t numArgs = String::Split(&args, uri, '/'); - if (numArgs > 0) + auto args = String::Split(uri, "/"); + if (args.size() > 0) { - utf8 * arg = args[0]; - if (String::Equals(arg, "join")) + std::string arg = args[0]; + if (arg == "join") { - if (numArgs > 1) + std::string hostname; + sint32 port; + if (args.size() > 1 && TryParseHostnamePort(args[1], &hostname, &port, NETWORK_DEFAULT_PORT)) { - utf8 * hostnamePort = args[1]; - - // Argument is in hostname:port format, so we need to split - utf8 * hostname = String::Duplicate(hostnamePort); - sint32 port = NETWORK_DEFAULT_PORT; - size_t colonIndex = String::IndexOf(hostnamePort, ':'); - if (colonIndex != SIZE_MAX) - { - Memory::Free(hostname); - hostname = String::Substring(hostnamePort, 0, colonIndex); - port = atoi(hostnamePort + colonIndex + 1); - } - // Set the network start configuration gNetworkStart = NETWORK_MODE_CLIENT; - String::Set(gNetworkStartHost, sizeof(gNetworkStartHost), hostname); + String::Set(gNetworkStartHost, sizeof(gNetworkStartHost), hostname.c_str()); gNetworkStartPort = port; - - Memory::Free(hostname); } else { @@ -81,13 +64,28 @@ static exitcode_t HandleUri(const utf8 * uri) } } } - - // Clean up - for (size_t i = 0; i < numArgs; i++) - { - Memory::Free(args[i]); - } - Memory::FreeArray(args, numArgs); - return EXITCODE_CONTINUE; } + +static bool TryParseHostnamePort(const std::string &hostnamePort, std::string * outHostname, sint32 * outPort, sint32 defaultPort) +{ + try + { + // Argument is in hostname:port format, so we need to split + std::string hostname = hostnamePort; + sint32 port = defaultPort; + size_t colonIndex = hostnamePort.find_first_of(':'); + if (colonIndex != std::string::npos) + { + hostname = hostnamePort.substr(0, colonIndex); + port = std::stoi(hostnamePort.substr(colonIndex + 1)); + } + *outPort = port; + *outHostname = hostname; + return true; + } + catch (const std::exception &) + { + return false; + } +} diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index 15e80d2490..b91061744e 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -354,38 +354,28 @@ namespace String return result; } - size_t Split(utf8 * * * values, const utf8 * buffer, utf8 delimiter) + std::vector Split(const std::string &s, const std::string &delimiter) { - std::vector valuesList; + std::vector results; size_t index = 0; size_t nextIndex; do { - nextIndex = String::IndexOf(buffer, '/', index); - utf8 * value; - if (nextIndex == SIZE_MAX) + nextIndex = s.find_first_of(delimiter, index); + std::string value; + if (nextIndex == std::string::npos) { - value = String::Substring(buffer, index); + value = s.substr(index); } else { - value = String::Substring(buffer, index, nextIndex - index); + value = s.substr(index, nextIndex - index); } - valuesList.push_back(value); + results.push_back(value); index = nextIndex + 1; - } while (nextIndex != SIZE_MAX); - - *values = nullptr; - if (valuesList.size() > 0) - { - utf8 * * valuesArray = Memory::AllocateArray(valuesList.size()); - for (size_t i = 0; i < valuesList.size(); i++) - { - valuesArray[i] = valuesList[i]; - } - *values = valuesArray; } - return valuesList.size(); + while (nextIndex != SIZE_MAX); + return results; } utf8 * SkipBOM(utf8 * buffer) diff --git a/src/openrct2/core/String.hpp b/src/openrct2/core/String.hpp index 1416764dce..4543a3fd97 100644 --- a/src/openrct2/core/String.hpp +++ b/src/openrct2/core/String.hpp @@ -17,6 +17,7 @@ #pragma once #include +#include #include "../common.h" namespace String @@ -79,7 +80,7 @@ namespace String * Splits the given string by a delimiter and returns the values as a new string array. * @returns the number of values. */ - size_t Split(utf8 * * * values, const utf8 * buffer, utf8 delimiter); + std::vector Split(const std::string &s, const std::string &delimiter); utf8 * SkipBOM(utf8 * buffer); const utf8 * SkipBOM(const utf8 * buffer); From 0ec43e3611180bf7580da1404478900b47ff3467 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Feb 2017 16:07:08 +0000 Subject: [PATCH 4/8] Improve String::Split and add tests --- src/openrct2/common.h | 3 +++ src/openrct2/core/String.cpp | 43 ++++++++++++++++++++++-------------- test/tests/AssertHelpers.hpp | 25 +++++++++++++++++++++ test/tests/StringTest.cpp | 21 ++++++++++++++++++ test/tests/tests.vcxproj | 1 + 5 files changed, 76 insertions(+), 17 deletions(-) create mode 100644 test/tests/AssertHelpers.hpp diff --git a/src/openrct2/common.h b/src/openrct2/common.h index 1a1d89dafe..14209e0ef3 100644 --- a/src/openrct2/common.h +++ b/src/openrct2/common.h @@ -113,6 +113,9 @@ typedef uint8 colour_t; #endif // __GNUC__ #endif // __cplusplus +// Gets the name of a symbol as a C string +#define nameof(symbol) #symbol + #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #include #define STUB() log_warning("Function %s at %s:%d is a stub.\n", __PRETTY_FUNCTION__, __FILE__, __LINE__) diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index b91061744e..1c96ee3304 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -15,6 +15,7 @@ #pragma endregion #include +#include #include extern "C" @@ -356,25 +357,33 @@ namespace String std::vector Split(const std::string &s, const std::string &delimiter) { - std::vector results; - size_t index = 0; - size_t nextIndex; - do + if (delimiter.empty()) { - nextIndex = s.find_first_of(delimiter, index); - std::string value; - if (nextIndex == std::string::npos) - { - value = s.substr(index); - } - else - { - value = s.substr(index, nextIndex - index); - } - results.push_back(value); - index = nextIndex + 1; + throw std::invalid_argument(nameof(delimiter) " can not be empty."); + } + + std::vector results; + if (!s.empty()) + { + size_t index = 0; + size_t nextIndex; + do + { + nextIndex = s.find(delimiter, index); + std::string value; + if (nextIndex == std::string::npos) + { + value = s.substr(index); + } + else + { + value = s.substr(index, nextIndex - index); + } + results.push_back(value); + index = nextIndex + delimiter.size(); + } + while (nextIndex != SIZE_MAX); } - while (nextIndex != SIZE_MAX); return results; } diff --git a/test/tests/AssertHelpers.hpp b/test/tests/AssertHelpers.hpp new file mode 100644 index 0000000000..1098db7a2c --- /dev/null +++ b/test/tests/AssertHelpers.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +template +void AssertVector(std::vector actual, TExpected expected) +{ + ASSERT_EQ(actual.size(), expected.size()) << + "Expected vector of size " << expected.size() << ", but was " << actual.size(); + size_t i = 0; + for (auto item : expected) + { + EXPECT_EQ(actual[i], item) << + "Element at index " << i << " did not match"; + i++; + } +} + +template +void AssertVector(std::vector actual, std::initializer_list expected) +{ + AssertVector>(actual, expected); +} diff --git a/test/tests/StringTest.cpp b/test/tests/StringTest.cpp index 8644c3c19b..7280eb6200 100644 --- a/test/tests/StringTest.cpp +++ b/test/tests/StringTest.cpp @@ -2,6 +2,7 @@ #include #include #include +#include "AssertHelpers.hpp" using TCase = std::tuple; @@ -28,3 +29,23 @@ TEST_P(StringTest, Trim) std::string actual = String::Trim(input); ASSERT_EQ(expected, actual); } + +TEST_F(StringTest, Split_ByComma) +{ + auto actual = String::Split("a,bb,ccc,dd", ","); + AssertVector(actual, { "a", "bb", "ccc", "dd" }); +} +TEST_F(StringTest, Split_ByColonColon) +{ + auto actual = String::Split("a::bb:ccc:::::dd", "::"); + AssertVector(actual, { "a", "bb:ccc", "", ":dd" }); +} +TEST_F(StringTest, Split_Empty) +{ + auto actual = String::Split("", "."); + AssertVector(actual, { }); +} +TEST_F(StringTest, Split_ByEmpty) +{ + EXPECT_THROW(String::Split("string", ""), std::invalid_argument); +} diff --git a/test/tests/tests.vcxproj b/test/tests/tests.vcxproj index 02dc0344b5..bbc3753f97 100644 --- a/test/tests/tests.vcxproj +++ b/test/tests/tests.vcxproj @@ -47,6 +47,7 @@ + From e81094ee60ba5f383a2988f6e3986016cc061828 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 25 Feb 2017 18:43:29 +0000 Subject: [PATCH 5/8] Fix loading parks by command line with non standard extensions --- src/openrct2/OpenRCT2.cpp | 59 +++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 24 deletions(-) diff --git a/src/openrct2/OpenRCT2.cpp b/src/openrct2/OpenRCT2.cpp index 9de2e9cf6f..06f82fda1a 100644 --- a/src/openrct2/OpenRCT2.cpp +++ b/src/openrct2/OpenRCT2.cpp @@ -14,16 +14,18 @@ *****************************************************************************/ #pragma endregion +#include #include #include "core/Console.hpp" -#include "core/Guard.hpp" #include "core/File.h" #include "core/FileStream.hpp" +#include "core/Guard.hpp" #include "core/String.hpp" #include "FileClassifier.h" #include "network/network.h" #include "object/ObjectRepository.h" #include "OpenRCT2.h" +#include "ParkImporter.h" #include "platform/crash.h" #include "PlatformEnvironment.h" #include "ride/TrackDesignRepository.h" @@ -518,50 +520,59 @@ namespace OpenRCT2 ClassifiedFile info; if (TryClassifyFile(path, &info)) { - if (info.Type == FILE_TYPE::SAVED_GAME) + if (info.Type == FILE_TYPE::SAVED_GAME || + info.Type == FILE_TYPE::SCENARIO) { + std::unique_ptr parkImporter; if (info.Version <= 2) { - if (rct1_load_saved_game(path)) + parkImporter.reset(ParkImporter::CreateS4()); + } + else + { + parkImporter.reset(ParkImporter::CreateS6()); + } + + if (info.Type == FILE_TYPE::SAVED_GAME) + { + try { + parkImporter->LoadSavedGame(path); + parkImporter->Import(); + game_fix_save_vars(); + sprite_position_tween_reset(); + gScreenAge = 0; + gLastAutoSaveUpdate = AUTOSAVE_PAUSE; game_load_init(); return true; } + catch (const Exception &) + { + Console::Error::WriteLine("Error loading saved game."); + } } else { - if (game_load_save(path)) - { - gFirstTimeSave = 0; - return true; - } - } - Console::Error::WriteLine("Error loading saved game."); - } - else if (info.Type == FILE_TYPE::SCENARIO) - { - if (info.Version <= 2) - { - - if (rct1_load_scenario(path)) + try { + parkImporter->LoadScenario(path); + parkImporter->Import(); + game_fix_save_vars(); + sprite_position_tween_reset(); + gScreenAge = 0; + gLastAutoSaveUpdate = AUTOSAVE_PAUSE; scenario_begin(); return true; } - } - else - { - if (scenario_load_and_play_from_path(path)) + catch (const Exception &) { - return true; + Console::Error::WriteLine("Error loading scenario."); } } - Console::Error::WriteLine("Error loading scenario."); } else { Console::Error::WriteLine("Invalid file type."); - Console::Error::WriteLine("Invalid file type."); } } else From e960da95e2bfea55baf9d20c437e37260c556bb9 Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 8 Mar 2017 19:15:03 +0000 Subject: [PATCH 6/8] Add a workaround for MINGW --- src/openrct2/platform/windows.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/openrct2/platform/windows.c b/src/openrct2/platform/windows.c index e46fbbd84b..520df12bd4 100644 --- a/src/openrct2/platform/windows.c +++ b/src/openrct2/platform/windows.c @@ -1213,7 +1213,14 @@ bool platform_setup_uri_protocol() HKEY hMuiCacheKey; if (RegCreateKeyW(hRootKey, MUI_CACHE, &hMuiCacheKey) == ERROR_SUCCESS) { swprintf_s(buffer, sizeof(buffer), L"%s.FriendlyAppName", exePath); +#ifdef __MINGW32__ + // mingw-w64 defines RegSetKeyValueW's signature incorrectly + // A fix has already been submitted upstream, this can be be removed after their next release: + // https://sourceforge.net/p/mingw-w64/mingw-w64/ci/da9341980a4b70be3563ac09b5927539e7da21f7/ + RegSetKeyValueW(hMuiCacheKey, NULL, (LPCSTR)buffer, REG_SZ, (LPCSTR)L"OpenRCT2", sizeof(L"OpenRCT2") + 1); +#else RegSetKeyValueW(hMuiCacheKey, NULL, buffer, REG_SZ, L"OpenRCT2", sizeof(L"OpenRCT2") + 1); +#endif } log_verbose("URI protocol setup successful"); From cdffd6116d772c47ed628bbd5c079b91a2b43fc9 Mon Sep 17 00:00:00 2001 From: Ted John Date: Wed, 8 Mar 2017 20:45:49 +0000 Subject: [PATCH 7/8] Fix non-network builds --- src/openrct2/cmdline/UriHandler.cpp | 47 ++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/openrct2/cmdline/UriHandler.cpp b/src/openrct2/cmdline/UriHandler.cpp index b935e36439..3890c76daa 100644 --- a/src/openrct2/cmdline/UriHandler.cpp +++ b/src/openrct2/cmdline/UriHandler.cpp @@ -22,7 +22,11 @@ #include "CommandLine.hpp" static exitcode_t HandleUri(const std::string &uri); + +#ifndef DISABLE_NETWORK +static exitcode_t HandleUriJoin(const std::vector &args); static bool TryParseHostnamePort(const std::string &hostnamePort, std::string * outHostname, sint32 * outPort, sint32 defaultPort); +#endif exitcode_t CommandLine::HandleCommandUri(CommandLineArgEnumerator * enumerator) { @@ -42,29 +46,40 @@ exitcode_t CommandLine::HandleCommandUri(CommandLineArgEnumerator * enumerator) static exitcode_t HandleUri(const std::string &uri) { + exitcode_t result = EXITCODE_CONTINUE; auto args = String::Split(uri, "/"); if (args.size() > 0) { +#ifndef DISABLE_NETWORK std::string arg = args[0]; if (arg == "join") { - std::string hostname; - sint32 port; - if (args.size() > 1 && TryParseHostnamePort(args[1], &hostname, &port, NETWORK_DEFAULT_PORT)) - { - // Set the network start configuration - gNetworkStart = NETWORK_MODE_CLIENT; - String::Set(gNetworkStartHost, sizeof(gNetworkStartHost), hostname.c_str()); - gNetworkStartPort = port; - } - else - { - Console::Error::WriteLine("Expected hostname:port after join"); - return EXITCODE_FAIL; - } + result = HandleUriJoin(args); } +#endif + } + return result; +} + +#ifndef DISABLE_NETWORK + +static exitcode_t HandleUriJoin(const std::vector &args) +{ + std::string hostname; + sint32 port; + if (args.size() > 1 && TryParseHostnamePort(args[1], &hostname, &port, NETWORK_DEFAULT_PORT)) + { + // Set the network start configuration + gNetworkStart = NETWORK_MODE_CLIENT; + String::Set(gNetworkStartHost, sizeof(gNetworkStartHost), hostname.c_str()); + gNetworkStartPort = port; + return EXITCODE_CONTINUE; + } + else + { + Console::Error::WriteLine("Expected hostname:port after join"); + return EXITCODE_FAIL; } - return EXITCODE_CONTINUE; } static bool TryParseHostnamePort(const std::string &hostnamePort, std::string * outHostname, sint32 * outPort, sint32 defaultPort) @@ -89,3 +104,5 @@ static bool TryParseHostnamePort(const std::string &hostnamePort, std::string * return false; } } + +#endif // DISABLE_NETWORK From 3bf14e05143f753cec6070a527d2ce3f04669413 Mon Sep 17 00:00:00 2001 From: Marijn van der Werf Date: Thu, 9 Mar 2017 14:57:14 +0100 Subject: [PATCH 8/8] Update Xcode project --- OpenRCT2.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/OpenRCT2.xcodeproj/project.pbxproj b/OpenRCT2.xcodeproj/project.pbxproj index 2cf84296cc..f33e59c269 100644 --- a/OpenRCT2.xcodeproj/project.pbxproj +++ b/OpenRCT2.xcodeproj/project.pbxproj @@ -240,6 +240,7 @@ C6E96E321E04072F0076A04F /* TitleSequencePlayer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C6E96E2D1E04072F0076A04F /* TitleSequencePlayer.cpp */; }; C6E96E361E0408B40076A04F /* libzip.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = C6E96E351E0408B40076A04F /* libzip.dylib */; }; C6E96E371E040E040076A04F /* libzip.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = C6E96E351E0408B40076A04F /* libzip.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + C6EABCC41E719691008C09AB /* UriHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C6EABCC31E719691008C09AB /* UriHandler.cpp */; }; D41B73EF1C2101890080A7B9 /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B73EE1C2101890080A7B9 /* libcurl.tbd */; }; D41B741D1C210A7A0080A7B9 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B741C1C210A7A0080A7B9 /* libiconv.tbd */; }; D41B74731C2125E50080A7B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D41B74721C2125E50080A7B9 /* Assets.xcassets */; }; @@ -716,6 +717,7 @@ C6E96E331E0408A80076A04F /* zip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = zip.h; sourceTree = ""; }; C6E96E341E0408A80076A04F /* zipconf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = zipconf.h; sourceTree = ""; }; C6E96E351E0408B40076A04F /* libzip.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libzip.dylib; sourceTree = ""; }; + C6EABCC31E719691008C09AB /* UriHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UriHandler.cpp; sourceTree = ""; }; C6FF1BAD1DBCE1A10078DCB5 /* junior_roller_coaster.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = junior_roller_coaster.h; sourceTree = ""; }; D41B73EE1C2101890080A7B9 /* libcurl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurl.tbd; path = usr/lib/libcurl.tbd; sourceTree = SDKROOT; }; D41B741C1C210A7A0080A7B9 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; }; @@ -1686,6 +1688,7 @@ D44270D91CC81B3200D84D28 /* RootCommands.cpp */, D44270DA1CC81B3200D84D28 /* ScreenshotCommands.cpp */, D44270DB1CC81B3200D84D28 /* SpriteCommands.cpp */, + C6EABCC31E719691008C09AB /* UriHandler.cpp */, ); path = cmdline; sourceTree = ""; @@ -2866,6 +2869,7 @@ C686F8B91CDBC37E009F9BFC /* supports.c in Sources */, D442726E1CC81B3200D84D28 /* maze_construction.c in Sources */, D44272751CC81B3200D84D28 /* news_options.c in Sources */, + C6EABCC41E719691008C09AB /* UriHandler.cpp in Sources */, D44272551CC81B3200D84D28 /* changelog.c in Sources */, C686F9471CDBC3B7009F9BFC /* top_spin.c in Sources */, D442720E1CC81B3200D84D28 /* rect.c in Sources */,