diff --git a/src/openrct2-dll/openrct2-dll.cpp b/src/openrct2-dll/openrct2-dll.cpp index 213147af8a..24f2340fc8 100644 --- a/src/openrct2-dll/openrct2-dll.cpp +++ b/src/openrct2-dll/openrct2-dll.cpp @@ -32,7 +32,7 @@ using namespace OpenRCT2::Ui; static char** GetCommandLineArgs(int argc, wchar_t** argvW); static void FreeCommandLineArgs(int argc, char** argv); -static char* ConvertUTF16toUTF8(const wchar_t* src); +static char* ConvertWideChartoUTF8(const wchar_t* src); DLLEXPORT int LaunchOpenRCT2(int argc, wchar_t** argvW) { @@ -43,6 +43,8 @@ DLLEXPORT int LaunchOpenRCT2(int argc, wchar_t** argvW) return -1; } + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); int exitCode = NormalisedMain(argc, const_cast(argv)); FreeCommandLineArgs(argc, argv); @@ -61,7 +63,7 @@ static char** GetCommandLineArgs(int argc, wchar_t** argvW) // Convert to UTF-8 for (int i = 0; i < argc; i++) { - argv[i] = ConvertUTF16toUTF8(argvW[i]); + argv[i] = ConvertWideChartoUTF8(argvW[i]); } return argv; @@ -77,7 +79,7 @@ static void FreeCommandLineArgs(int argc, char** argv) free(argv); } -static char* ConvertUTF16toUTF8(const wchar_t* src) +static char* ConvertWideChartoUTF8(const wchar_t* src) { int srcLen = lstrlenW(src); int sizeReq = WideCharToMultiByte(CP_UTF8, 0, src, srcLen, nullptr, 0, nullptr, nullptr); diff --git a/src/openrct2-ui/UiContext.Win32.cpp b/src/openrct2-ui/UiContext.Win32.cpp index c9b0e99538..c19b3fcd98 100644 --- a/src/openrct2-ui/UiContext.Win32.cpp +++ b/src/openrct2-ui/UiContext.Win32.cpp @@ -87,23 +87,23 @@ namespace OpenRCT2::Ui void ShowMessageBox(SDL_Window* window, const std::string& message) override { HWND hwnd = GetHWND(window); - std::wstring messageW = String::ToUtf16(message); + std::wstring messageW = String::ToWideChar(message); MessageBoxW(hwnd, messageW.c_str(), L"OpenRCT2", MB_OK); } void OpenFolder(const std::string& path) override { - std::wstring pathW = String::ToUtf16(path); + std::wstring pathW = String::ToWideChar(path); ShellExecuteW(NULL, L"open", pathW.c_str(), NULL, NULL, SW_SHOWNORMAL); } std::string ShowFileDialog(SDL_Window* window, const FileDialogDesc& desc) override { - std::wstring wcFilename = String::ToUtf16(desc.DefaultFilename); + std::wstring wcFilename = String::ToWideChar(desc.DefaultFilename); wcFilename.resize(std::max(wcFilename.size(), MAX_PATH)); - std::wstring wcTitle = String::ToUtf16(desc.Title); - std::wstring wcInitialDirectory = String::ToUtf16(desc.InitialDirectory); + std::wstring wcTitle = String::ToWideChar(desc.Title); + std::wstring wcInitialDirectory = String::ToWideChar(desc.InitialDirectory); std::wstring wcFilters = GetFilterString(desc.Filters); // Set open file name options @@ -162,7 +162,7 @@ namespace OpenRCT2::Ui LPMALLOC lpMalloc; if (SUCCEEDED(CoInitializeEx(0, COINIT_APARTMENTTHREADED)) && SUCCEEDED(SHGetMalloc(&lpMalloc))) { - std::wstring titleW = String::ToUtf16(title); + std::wstring titleW = String::ToWideChar(title); BROWSEINFOW bi = {}; bi.lpszTitle = titleW.c_str(); bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE | BIF_NONEWFOLDERBUTTON; @@ -211,7 +211,7 @@ namespace OpenRCT2::Ui std::wstringstream filtersb; for (auto filter : filters) { - filtersb << String::ToUtf16(filter.Name) << '\0' << String::ToUtf16(filter.Pattern) << '\0'; + filtersb << String::ToWideChar(filter.Name) << '\0' << String::ToWideChar(filter.Pattern) << '\0'; } return filtersb.str(); } diff --git a/src/openrct2-ui/windows/Changelog.cpp b/src/openrct2-ui/windows/Changelog.cpp index 97c3308f59..a5ba4b3fbe 100644 --- a/src/openrct2-ui/windows/Changelog.cpp +++ b/src/openrct2-ui/windows/Changelog.cpp @@ -213,7 +213,7 @@ static std::string GetChangelogText() { auto path = GetChangelogPath(); #if defined(_WIN32) && !defined(__MINGW32__) - auto pathW = String::ToUtf16(path); + auto pathW = String::ToWideChar(path); auto fs = std::ifstream(pathW, std::ios::in); #else auto fs = std::ifstream(path, std::ios::in); diff --git a/src/openrct2/CmdlineSprite.cpp b/src/openrct2/CmdlineSprite.cpp index d3b4bf375b..3a3f52f204 100644 --- a/src/openrct2/CmdlineSprite.cpp +++ b/src/openrct2/CmdlineSprite.cpp @@ -13,6 +13,7 @@ #include "OpenRCT2.h" #include "core/Imaging.h" +#include "core/String.hpp" #include "drawing/Drawing.h" #include "drawing/ImageImporter.h" #include "localisation/Language.h" @@ -68,11 +69,9 @@ static uint8_t* spriteFileData; static FILE* fopen_utf8(const char* path, const char* mode) { - wchar_t* pathW = utf8_to_widechar(path); - wchar_t* modeW = utf8_to_widechar(mode); - FILE* file = _wfopen(pathW, modeW); - free(pathW); - free(modeW); + auto pathW = String::ToWideChar(path); + auto modeW = String::ToWideChar(mode); + auto file = _wfopen(pathW.c_str(), modeW.c_str()); return file; } @@ -640,20 +639,19 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc) } // Resolve absolute sprite path - char* imagePath = platform_get_absolute_path(json_string_value(path), directoryPath); + auto imagePath = platform_get_absolute_path(json_string_value(path), directoryPath); rct_g1_element spriteElement; uint8_t* buffer; int bufferLength; if (!sprite_file_import( - imagePath, x_offset == nullptr ? 0 : json_integer_value(x_offset), + imagePath.c_str(), x_offset == nullptr ? 0 : json_integer_value(x_offset), y_offset == nullptr ? 0 : json_integer_value(y_offset), keep_palette, forceBmp, &spriteElement, &buffer, &bufferLength, gSpriteMode)) { - fprintf(stderr, "Could not import image file: %s\nCanceling\n", imagePath); + fprintf(stderr, "Could not import image file: %s\nCanceling\n", imagePath.c_str()); json_decref(sprite_list); - free(imagePath); return -1; } @@ -661,7 +659,6 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc) { fprintf(stderr, "Unable to open sprite file: %s\nCanceling\n", spriteFilePath); json_decref(sprite_list); - free(imagePath); return -1; } @@ -683,16 +680,14 @@ int32_t cmdline_for_sprite(const char** argv, int32_t argc) if (!sprite_file_save(spriteFilePath)) { - fprintf(stderr, "Could not save sprite file: %s\nCanceling\n", imagePath); + fprintf(stderr, "Could not save sprite file: %s\nCanceling\n", imagePath.c_str()); json_decref(sprite_list); - free(imagePath); return -1; } if (!silent) - fprintf(stdout, "Added: %s\n", imagePath); + fprintf(stdout, "Added: %s\n", imagePath.c_str()); - free(imagePath); sprite_file_close(); } diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index 73f44ed6b9..3390971050 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -504,6 +504,7 @@ namespace OpenRCT2 bool LoadParkFromFile(const std::string& path, bool loadTitleScreenOnFail) final override { + log_verbose("Context::LoadParkFromFile(%s)", path.c_str()); try { auto fs = FileStream(path, FILE_MODE_OPEN); diff --git a/src/openrct2/common.h b/src/openrct2/common.h index 2110a4415c..1af006ac29 100644 --- a/src/openrct2/common.h +++ b/src/openrct2/common.h @@ -31,10 +31,6 @@ using namespace Numerics; using utf8 = char; using utf8string = utf8*; using const_utf8string = const utf8*; -#ifdef _WIN32 -using utf16 = wchar_t; -using utf16string = utf16*; -#endif // Define MAX_PATH for various headers that don't want to include system headers // just for MAX_PATH diff --git a/src/openrct2/config/Config.cpp b/src/openrct2/config/Config.cpp index 556c461501..08d59488ee 100644 --- a/src/openrct2/config/Config.cpp +++ b/src/openrct2/config/Config.cpp @@ -362,7 +362,7 @@ namespace Config auto playerName = reader->GetString("player_name", ""); if (playerName.empty()) { - playerName = String::ToStd(platform_get_username()); + playerName = platform_get_username(); if (playerName.empty()) { playerName = "Player"; diff --git a/src/openrct2/core/File.cpp b/src/openrct2/core/File.cpp index bae6d23440..5df4e4514d 100644 --- a/src/openrct2/core/File.cpp +++ b/src/openrct2/core/File.cpp @@ -49,7 +49,7 @@ namespace File std::vector result; #if defined(_WIN32) && !defined(__MINGW32__) - auto pathW = String::ToUtf16(std::string(path)); + auto pathW = String::ToWideChar(std::string(path)); std::ifstream fs(pathW, std::ios::in | std::ios::binary); #else std::ifstream fs(std::string(path), std::ios::in | std::ios::binary); @@ -125,8 +125,8 @@ namespace File { uint64_t lastModified = 0; #ifdef _WIN32 - auto pathW = utf8_to_widechar(path.c_str()); - auto hFile = CreateFileW(pathW, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + auto pathW = String::ToWideChar(path.c_str()); + auto hFile = CreateFileW(pathW.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); if (hFile != INVALID_HANDLE_VALUE) { FILETIME ftCreate, ftAccess, ftWrite; @@ -136,7 +136,6 @@ namespace File } CloseHandle(hFile); } - free(pathW); #else struct stat statInfo { diff --git a/src/openrct2/core/FileScanner.cpp b/src/openrct2/core/FileScanner.cpp index 718d97cc49..169d62df4f 100644 --- a/src/openrct2/core/FileScanner.cpp +++ b/src/openrct2/core/FileScanner.cpp @@ -227,11 +227,11 @@ public: void GetDirectoryChildren(std::vector& children, const std::string& path) override { - std::string pattern = path + "\\*"; - wchar_t* wPattern = utf8_to_widechar(pattern.c_str()); + auto pattern = path + "\\*"; + auto wPattern = String::ToWideChar(pattern.c_str()); WIN32_FIND_DATAW findData; - HANDLE hFile = FindFirstFileW(wPattern, &findData); + HANDLE hFile = FindFirstFileW(wPattern.c_str(), &findData); if (hFile != INVALID_HANDLE_VALUE) { do @@ -244,8 +244,6 @@ public: } while (FindNextFileW(hFile, &findData)); FindClose(hFile); } - - Memory::Free(wPattern); } private: @@ -253,10 +251,7 @@ private: { DirectoryChild result; - utf8* name = widechar_to_utf8(child->cFileName); - result.Name = std::string(name); - Memory::Free(name); - + result.Name = String::ToUtf8(child->cFileName); if (child->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { result.Type = DIRECTORY_CHILD_TYPE::DC_DIRECTORY; diff --git a/src/openrct2/core/FileStream.hpp b/src/openrct2/core/FileStream.hpp index 0839b9994f..716be814b1 100644 --- a/src/openrct2/core/FileStream.hpp +++ b/src/openrct2/core/FileStream.hpp @@ -70,11 +70,9 @@ public: } #ifdef _WIN32 - wchar_t* pathW = utf8_to_widechar(path); - wchar_t* modeW = utf8_to_widechar(mode); - _file = _wfopen(pathW, modeW); - free(pathW); - free(modeW); + auto pathW = String::ToWideChar(path); + auto modeW = String::ToWideChar(mode); + _file = _wfopen(pathW.c_str(), modeW.c_str()); #else if (fileMode == FILE_MODE_OPEN) { diff --git a/src/openrct2/core/Imaging.cpp b/src/openrct2/core/Imaging.cpp index 3772b7d02e..18b676fdd0 100644 --- a/src/openrct2/core/Imaging.cpp +++ b/src/openrct2/core/Imaging.cpp @@ -305,7 +305,7 @@ namespace Imaging default: { #if defined(_WIN32) && !defined(__MINGW32__) - auto pathW = String::ToUtf16(path); + auto pathW = String::ToWideChar(path); std::ifstream fs(pathW, std::ios::binary); #else std::ifstream fs(path.data(), std::ios::binary); @@ -331,7 +331,7 @@ namespace Imaging case IMAGE_FORMAT::PNG: { #if defined(_WIN32) && !defined(__MINGW32__) - auto pathW = String::ToUtf16(path); + auto pathW = String::ToWideChar(path); std::ofstream fs(pathW, std::ios::binary); #else std::ofstream fs(path.data(), std::ios::binary); diff --git a/src/openrct2/core/Path.cpp b/src/openrct2/core/Path.cpp index 35064173d0..8c1bfeb045 100644 --- a/src/openrct2/core/Path.cpp +++ b/src/openrct2/core/Path.cpp @@ -171,19 +171,17 @@ namespace Path utf8* GetAbsolute(utf8* buffer, size_t bufferSize, const utf8* relativePath) { #ifdef _WIN32 - wchar_t* relativePathW = utf8_to_widechar(relativePath); + auto relativePathW = String::ToWideChar(relativePath); wchar_t absolutePathW[MAX_PATH]; - DWORD length = GetFullPathNameW(relativePathW, (DWORD)std::size(absolutePathW), absolutePathW, nullptr); - Memory::Free(relativePathW); + DWORD length = GetFullPathNameW(relativePathW.c_str(), (DWORD)std::size(absolutePathW), absolutePathW, nullptr); if (length == 0) { return String::Set(buffer, bufferSize, relativePath); } else { - utf8* absolutePath = widechar_to_utf8(absolutePathW); - String::Set(buffer, bufferSize, absolutePath); - Memory::Free(absolutePath); + auto absolutePath = String::ToUtf8(absolutePathW); + String::Set(buffer, bufferSize, absolutePath.c_str()); return buffer; } #else diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index 68da671696..bf5ec321f9 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -97,7 +97,7 @@ namespace String #endif } - std::wstring ToUtf16(const std::string_view& src) + std::wstring ToWideChar(const std::string_view& src) { #ifdef _WIN32 int srcLen = (int)src.size(); @@ -706,7 +706,7 @@ namespace String std::string ToUpper(const std::string_view& src) { #ifdef _WIN32 - auto srcW = ToUtf16(src); + auto srcW = ToWideChar(src); // Measure how long the destination needs to be auto requiredSize = LCMapStringEx( diff --git a/src/openrct2/core/String.hpp b/src/openrct2/core/String.hpp index 8314655ffc..3f337aa629 100644 --- a/src/openrct2/core/String.hpp +++ b/src/openrct2/core/String.hpp @@ -37,7 +37,7 @@ namespace String std::string StdFormat_VA(const utf8* format, va_list args); std::string StdFormat(const utf8* format, ...); std::string ToUtf8(const std::wstring_view& src); - std::wstring ToUtf16(const std::string_view& src); + std::wstring ToWideChar(const std::string_view& src); bool IsNullOrEmpty(const utf8* str); int32_t Compare(const std::string& a, const std::string& b, bool ignoreCase = false); diff --git a/src/openrct2/localisation/Language.h b/src/openrct2/localisation/Language.h index 17d0340456..d19b0e5eab 100644 --- a/src/openrct2/localisation/Language.h +++ b/src/openrct2/localisation/Language.h @@ -101,8 +101,6 @@ bool utf8_is_codepoint_start(const utf8* text); void utf8_remove_format_codes(utf8* text, bool allowcolours); int32_t utf8_get_codepoint_length(int32_t codepoint); int32_t utf8_length(const utf8* text); -wchar_t* utf8_to_widechar(const utf8* src); -utf8* widechar_to_utf8(const wchar_t* src); std::string rct2_to_utf8(const std::string_view& src, RCT2LanguageId languageId); std::string utf8_to_rct2(const std::string_view& src); diff --git a/src/openrct2/localisation/UTF8.cpp b/src/openrct2/localisation/UTF8.cpp index 708e8df85d..b91c929d18 100644 --- a/src/openrct2/localisation/UTF8.cpp +++ b/src/openrct2/localisation/UTF8.cpp @@ -137,44 +137,6 @@ int32_t utf8_length(const utf8* text) return count; } -wchar_t* utf8_to_widechar(const utf8* src) -{ - wchar_t* result = (wchar_t*)malloc((utf8_length(src) + 1) * sizeof(wchar_t)); - wchar_t* dst = result; - - const utf8* ch = src; - int32_t codepoint; - while ((codepoint = utf8_get_next(ch, &ch)) != 0) - { - if ((uint32_t)codepoint > 0xFFFF) - { - *dst++ = '?'; - } - else - { - *dst++ = codepoint; - } - } - *dst = 0; - - return result; -} - -utf8* widechar_to_utf8(const wchar_t* src) -{ - utf8* result = (utf8*)malloc((wcslen(src) * 4) + 1); - utf8* dst = result; - - for (; *src != 0; src++) - { - dst = utf8_write_codepoint(dst, *src); - } - *dst++ = 0; - - size_t size = (size_t)(dst - result); - return (utf8*)realloc(result, size); -} - /** * Returns a pointer to the null terminator of the given UTF-8 string. */ diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index 80e2d32d51..9f77360605 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -1356,8 +1356,8 @@ void Network::BeginChatLog() _chatLogPath = BeginLog(directory, "", _chatLogFilenameFormat); # if defined(_WIN32) && !defined(__MINGW32__) - auto pathW = std::unique_ptr(utf8_to_widechar(_chatLogPath.c_str())); - _chat_log_fs.open(pathW.get(), std::ios::out | std::ios::app); + auto pathW = String::ToWideChar(_chatLogPath.c_str()); + _chat_log_fs.open(pathW.c_str(), std::ios::out | std::ios::app); # else _chat_log_fs.open(_chatLogPath, std::ios::out | std::ios::app); # endif @@ -1382,8 +1382,8 @@ void Network::BeginServerLog() _serverLogPath = BeginLog(directory, ServerName, _serverLogFilenameFormat); # if defined(_WIN32) && !defined(__MINGW32__) - auto pathW = std::unique_ptr(utf8_to_widechar(_serverLogPath.c_str())); - _server_log_fs.open(pathW.get(), std::ios::out | std::ios::app | std::ios::binary); + auto pathW = String::ToWideChar(_serverLogPath.c_str()); + _server_log_fs.open(pathW.c_str(), std::ios::out | std::ios::app | std::ios::binary); # else _server_log_fs.open(_serverLogPath, std::ios::out | std::ios::app | std::ios::binary); # endif diff --git a/src/openrct2/platform/Crash.cpp b/src/openrct2/platform/Crash.cpp index 45b0dd0525..5dd09091c2 100644 --- a/src/openrct2/platform/Crash.cpp +++ b/src/openrct2/platform/Crash.cpp @@ -68,7 +68,7 @@ static bool UploadMinidump(const std::map& files, in } else { - parameters[L"commit"] = String::ToUtf16(gVersionInfoFull); + parameters[L"commit"] = String::ToWideChar(gVersionInfoFull); } int timeout = 10000; bool success = google_breakpad::HTTPUpload::SendRequest(url, parameters, files, &timeout, &response, &error); @@ -150,18 +150,17 @@ static bool OnCrash( wprintf(L"Commit: %s\n", _wszCommitSha1Short); bool savedGameDumped = false; - utf8* saveFilePathUTF8 = widechar_to_utf8(saveFilePath); + auto saveFilePathUTF8 = String::ToUtf8(saveFilePath); try { auto exporter = std::make_unique(); exporter->Export(); - exporter->SaveGame(saveFilePathUTF8); + exporter->SaveGame(saveFilePathUTF8.c_str()); savedGameDumped = true; } catch (const std::exception&) { } - free(saveFilePathUTF8); // Compress the save if (savedGameDumped) @@ -181,19 +180,16 @@ static bool OnCrash( fclose(dest); } - utf8* configFilePathUTF8 = widechar_to_utf8(configFilePath); - if (config_save(configFilePathUTF8)) + auto configFilePathUTF8 = String::ToUtf8(configFilePath); + if (config_save(configFilePathUTF8.c_str())) { uploadFiles[L"attachment_config.ini"] = configFilePath; } - free(configFilePathUTF8); std::string screenshotPath = screenshot_dump(); if (!screenshotPath.empty()) { - wchar_t* screenshotPathWchar = utf8_to_widechar(screenshotPath.c_str()); - auto screenshotPathW = std::wstring(screenshotPathWchar); - free(screenshotPathWchar); + auto screenshotPathW = String::ToWideChar(screenshotPath.c_str()); uploadFiles[L"attachment_screenshot.png"] = screenshotPathW; } @@ -270,11 +266,7 @@ static std::wstring GetDumpDirectory() { char userDirectory[MAX_PATH]; platform_get_user_directory(userDirectory, nullptr, sizeof(userDirectory)); - - wchar_t* userDirectoryW = utf8_to_widechar(userDirectory); - auto result = std::wstring(userDirectoryW); - free(userDirectoryW); - + auto result = String::ToWideChar(userDirectory); return result; } diff --git a/src/openrct2/platform/Platform.Win32.cpp b/src/openrct2/platform/Platform.Win32.cpp index 62ecff739c..b23ab59d5d 100644 --- a/src/openrct2/platform/Platform.Win32.cpp +++ b/src/openrct2/platform/Platform.Win32.cpp @@ -50,7 +50,7 @@ namespace Platform std::string GetEnvironmentVariable(const std::string& name) { std::wstring result; - auto wname = String::ToUtf16(name); + auto wname = String::ToWideChar(name); wchar_t wvalue[256]; auto valueSize = GetEnvironmentVariableW(wname.c_str(), wvalue, (DWORD)std::size(wvalue)); if (valueSize < std::size(wvalue)) diff --git a/src/openrct2/platform/Posix.cpp b/src/openrct2/platform/Posix.cpp index 733df1b6fc..092e635d1b 100644 --- a/src/openrct2/platform/Posix.cpp +++ b/src/openrct2/platform/Posix.cpp @@ -21,6 +21,7 @@ # include "../OpenRCT2.h" # include "../config/Config.h" # include "../core/Path.hpp" +# include "../core/String.hpp" # include "../localisation/Date.h" # include "../localisation/Language.h" # include "../util/Util.h" @@ -97,20 +98,19 @@ void platform_get_time_local(rct2_time* out_time) static size_t platform_utf8_to_multibyte(const utf8* path, char* buffer, size_t buffer_size) { - wchar_t* wpath = utf8_to_widechar(path); + auto wpath = String::ToWideChar(path); setlocale(LC_CTYPE, "UTF-8"); - size_t len = wcstombs(NULL, wpath, 0); + size_t len = wcstombs(NULL, wpath.c_str(), 0); bool truncated = false; if (len > buffer_size - 1) { truncated = true; len = buffer_size - 1; } - wcstombs(buffer, wpath, len); + wcstombs(buffer, wpath.c_str(), len); buffer[len] = '\0'; if (truncated) log_warning("truncated string %s", buffer); - free(wpath); return len; } @@ -286,19 +286,29 @@ bool platform_directory_delete(const utf8* path) return true; } -utf8* platform_get_absolute_path(const utf8* relative_path, const utf8* base_path) +std::string platform_get_absolute_path(const utf8* relative_path, const utf8* base_path) { - utf8 path[MAX_PATH]; + std::string result; + if (relative_path != nullptr) + { + std::string pathToResolve; + if (base_path == nullptr) + { + pathToResolve = std::string(relative_path); + } + else + { + pathToResolve = std::string(base_path) + std::string("/") + relative_path; + } - if (base_path != nullptr) - { - snprintf(path, MAX_PATH, "%s/%s", base_path, relative_path); + auto realpathResult = realpath(pathToResolve.c_str(), nullptr); + if (realpathResult != nullptr) + { + result = std::string(realpathResult); + free(realpathResult); + } } - else - { - safe_strcpy(path, base_path, MAX_PATH); - } - return realpath(path, NULL); + return result; } bool platform_lock_single_instance() @@ -482,18 +492,15 @@ datetime64 platform_get_datetime_now_utc() return utcNow; } -utf8* platform_get_username() +std::string platform_get_username() { - struct passwd* pw = getpwuid(getuid()); - - if (pw) + std::string result; + auto pw = getpwuid(getuid()); + if (pw != nullptr) { - return pw->pw_name; - } - else - { - return nullptr; + result = std::string(pw->pw_name); } + return result; } bool platform_process_is_elevated() diff --git a/src/openrct2/platform/Windows.cpp b/src/openrct2/platform/Windows.cpp index 78535d3bcf..e602d1eb70 100644 --- a/src/openrct2/platform/Windows.cpp +++ b/src/openrct2/platform/Windows.cpp @@ -85,18 +85,16 @@ void platform_get_time_local(rct2_time* out_time) bool platform_file_exists(const utf8* path) { - wchar_t* wPath = utf8_to_widechar(path); - DWORD result = GetFileAttributesW(wPath); + auto wPath = String::ToWideChar(path); + DWORD result = GetFileAttributesW(wPath.c_str()); DWORD error = GetLastError(); - free(wPath); return !(result == INVALID_FILE_ATTRIBUTES && (error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND)); } bool platform_directory_exists(const utf8* path) { - wchar_t* wPath = utf8_to_widechar(path); - DWORD dwAttrib = GetFileAttributesW(wPath); - free(wPath); + auto wPath = String::ToWideChar(path); + DWORD dwAttrib = GetFileAttributesW(wPath.c_str()); return dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY); } @@ -127,27 +125,20 @@ bool platform_ensure_directory_exists(const utf8* path) if (platform_directory_exists(path)) return 1; - wchar_t* wPath = utf8_to_widechar(path); - BOOL success = CreateDirectoryW(wPath, nullptr); - free(wPath); - return success == TRUE; + auto wPath = String::ToWideChar(path); + auto success = CreateDirectoryW(wPath.c_str(), nullptr); + return success != FALSE; } bool platform_directory_delete(const utf8* path) { - wchar_t pszFrom[MAX_PATH]; - - wchar_t* wPath = utf8_to_widechar(path); - wcsncpy(pszFrom, wPath, MAX_PATH); - - // Needs to be double-null terminated for some weird reason - pszFrom[wcslen(wPath) + 1] = 0; - free(wPath); + // Needs to be double-null terminated as pFrom is a null terminated array of strings + auto wPath = String::ToWideChar(path) + L"\0"; SHFILEOPSTRUCTW fileop; fileop.hwnd = nullptr; // no status display fileop.wFunc = FO_DELETE; // delete operation - fileop.pFrom = pszFrom; // source file name as double null terminated string + fileop.pFrom = wPath.c_str(); // source file name as double null terminated string fileop.pTo = nullptr; // no destination needed fileop.fFlags = FOF_NOCONFIRMATION | FOF_SILENT; // do not prompt the user @@ -189,30 +180,25 @@ int32_t platform_get_drives() bool platform_file_copy(const utf8* srcPath, const utf8* dstPath, bool overwrite) { - wchar_t* wSrcPath = utf8_to_widechar(srcPath); - wchar_t* wDstPath = utf8_to_widechar(dstPath); - BOOL success = CopyFileW(wSrcPath, wDstPath, overwrite ? FALSE : TRUE); - free(wSrcPath); - free(wDstPath); - return success == TRUE; + auto wSrcPath = String::ToWideChar(srcPath); + auto wDstPath = String::ToWideChar(dstPath); + auto success = CopyFileW(wSrcPath.c_str(), wDstPath.c_str(), overwrite ? FALSE : TRUE); + return success != FALSE; } bool platform_file_move(const utf8* srcPath, const utf8* dstPath) { - wchar_t* wSrcPath = utf8_to_widechar(srcPath); - wchar_t* wDstPath = utf8_to_widechar(dstPath); - BOOL success = MoveFileW(wSrcPath, wDstPath); - free(wSrcPath); - free(wDstPath); - return success == TRUE; + auto wSrcPath = String::ToWideChar(srcPath); + auto wDstPath = String::ToWideChar(dstPath); + auto success = MoveFileW(wSrcPath.c_str(), wDstPath.c_str()); + return success != FALSE; } bool platform_file_delete(const utf8* path) { - wchar_t* wPath = utf8_to_widechar(path); - BOOL success = DeleteFileW(wPath); - free(wPath); - return success == TRUE; + auto wPath = String::ToWideChar(path); + auto success = DeleteFileW(wPath.c_str()); + return success != FALSE; } bool platform_get_steam_path(utf8* outPath, size_t outSize) @@ -236,10 +222,9 @@ bool platform_get_steam_path(utf8* outPath, size_t outSize) result = RegQueryValueExW(hKey, L"SteamPath", nullptr, &type, (LPBYTE)wSteamPath, &size); if (result == ERROR_SUCCESS) { - utf8* utf8SteamPath = widechar_to_utf8(wSteamPath); - safe_strcpy(outPath, utf8SteamPath, outSize); + auto utf8SteamPath = String::ToUtf8(wSteamPath); + safe_strcpy(outPath, utf8SteamPath.c_str(), outSize); safe_strcat_path(outPath, "steamapps\\common", outSize); - free(utf8SteamPath); } free(wSteamPath); RegCloseKey(hKey); @@ -340,24 +325,22 @@ uint16_t platform_get_locale_language() time_t platform_file_get_modified_time(const utf8* path) { - WIN32_FILE_ATTRIBUTE_DATA data; - - wchar_t* wPath = utf8_to_widechar(path); - BOOL result = GetFileAttributesExW(wPath, GetFileExInfoStandard, &data); - free(wPath); - - if (!result) - return 0; - - FILETIME localFileTime; - result = FileTimeToLocalFileTime(&data.ftLastWriteTime, &localFileTime); - if (!result) - return 0; - - ULARGE_INTEGER ull; - ull.LowPart = localFileTime.dwLowDateTime; - ull.HighPart = localFileTime.dwHighDateTime; - return ull.QuadPart / 10000000ULL - 11644473600ULL; + WIN32_FILE_ATTRIBUTE_DATA data{}; + auto wPath = String::ToWideChar(path); + auto result = GetFileAttributesExW(wPath.c_str(), GetFileExInfoStandard, &data); + if (result != FALSE) + { + FILETIME localFileTime{}; + result = FileTimeToLocalFileTime(&data.ftLastWriteTime, &localFileTime); + if (result != FALSE) + { + ULARGE_INTEGER ull{}; + ull.LowPart = localFileTime.dwLowDateTime; + ull.HighPart = localFileTime.dwHighDateTime; + return ull.QuadPart / 10000000ULL - 11644473600ULL; + } + } + return 0; } uint8_t platform_get_locale_currency() @@ -468,9 +451,8 @@ bool platform_get_font_path(TTFFontDescriptor* font, utf8* buffer, size_t size) if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Fonts, 0, nullptr, &fontFolder))) { // Convert wchar to utf8, then copy the font folder path to the buffer. - utf8* outPathTemp = widechar_to_utf8(fontFolder); - safe_strcpy(buffer, outPathTemp, size); - free(outPathTemp); + auto outPathTemp = String::ToUtf8(fontFolder); + safe_strcpy(buffer, outPathTemp.c_str(), size); CoTaskMemFree(fontFolder); @@ -491,24 +473,30 @@ bool platform_get_font_path(TTFFontDescriptor* font, utf8* buffer, size_t size) } # endif // NO_TTF -utf8* platform_get_absolute_path(const utf8* relativePath, const utf8* basePath) +std::string platform_get_absolute_path(const utf8* relativePath, const utf8* basePath) { - utf8 path[MAX_PATH]; - safe_strcpy(path, basePath, sizeof(path)); - safe_strcat_path(path, relativePath, sizeof(path)); - - wchar_t* pathW = utf8_to_widechar(path); - wchar_t fullPathW[MAX_PATH]; - DWORD fullPathLen = GetFullPathNameW(pathW, (DWORD)std::size(fullPathW), fullPathW, nullptr); - - free(pathW); - - if (fullPathLen == 0) + std::string result; + if (relativePath != nullptr) { - return nullptr; - } + std::string pathToResolve; + if (basePath == nullptr) + { + pathToResolve = std::string(relativePath); + } + else + { + pathToResolve = std::string(basePath) + std::string("\\") + relativePath; + } - return widechar_to_utf8(fullPathW); + auto pathToResolveW = String::ToWideChar(pathToResolve); + wchar_t fullPathW[MAX_PATH]{}; + auto fullPathLen = GetFullPathNameW(pathToResolveW.c_str(), (DWORD)std::size(fullPathW), fullPathW, nullptr); + if (fullPathLen != 0) + { + result = String::ToUtf8(fullPathW); + } + } + return result; } datetime64 platform_get_datetime_now_utc() @@ -524,18 +512,16 @@ datetime64 platform_get_datetime_now_utc() return utcNow; } -utf8* platform_get_username() +std::string platform_get_username() { - static wchar_t usernameW[UNLEN + 1]; + std::string result; + wchar_t usernameW[UNLEN + 1]{}; DWORD usernameLength = UNLEN + 1; - if (!GetUserNameW(usernameW, &usernameLength)) + if (GetUserNameW(usernameW, &usernameLength)) { - return nullptr; + result = String::ToUtf8(usernameW); } - - static std::string username; - username = widechar_to_utf8(usernameW); - return username.data(); + return result; } bool platform_process_is_elevated() @@ -565,15 +551,11 @@ bool platform_process_is_elevated() # 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) +static std::wstring get_progIdName(const std::string_view& extension) { - utf8 progIdName[128]; - safe_strcpy(progIdName, OPENRCT2_NAME, sizeof(progIdName)); - safe_strcat(progIdName, extension, sizeof(progIdName)); - - wchar_t* progIdNameW = utf8_to_widechar(progIdName); - lstrcpyW(dst, progIdNameW); - free(progIdNameW); + auto progIdName = std::string(OPENRCT2_NAME) + std::string(extension); + auto progIdNameW = String::ToWideChar(progIdName); + return progIdNameW; } static bool windows_setup_file_association( @@ -587,13 +569,11 @@ static bool windows_setup_file_association( GetModuleFileNameW(nullptr, exePathW, (DWORD)std::size(exePathW)); GetModuleFileNameW(plaform_get_dll_module(), dllPathW, (DWORD)std::size(dllPathW)); - wchar_t* extensionW = utf8_to_widechar(extension); - wchar_t* fileTypeTextW = utf8_to_widechar(fileTypeText); - wchar_t* commandTextW = utf8_to_widechar(commandText); - wchar_t* commandArgsW = utf8_to_widechar(commandArgs); - - wchar_t progIdNameW[128]; - get_progIdName(progIdNameW, extension); + auto extensionW = String::ToWideChar(extension); + auto fileTypeTextW = String::ToWideChar(fileTypeText); + auto commandTextW = String::ToWideChar(commandText); + auto commandArgsW = String::ToWideChar(commandArgs); + auto progIdNameW = get_progIdName(extension); bool result = false; HKEY hKey = nullptr; @@ -606,18 +586,18 @@ static bool windows_setup_file_association( } // [hRootKey\.ext] - if (RegSetValueW(hRootKey, extensionW, REG_SZ, progIdNameW, 0) != ERROR_SUCCESS) + if (RegSetValueW(hRootKey, extensionW.c_str(), REG_SZ, progIdNameW.c_str(), 0) != ERROR_SUCCESS) { goto fail; } - if (RegCreateKeyW(hRootKey, progIdNameW, &hKey) != ERROR_SUCCESS) + if (RegCreateKeyW(hRootKey, progIdNameW.c_str(), &hKey) != ERROR_SUCCESS) { goto fail; } // [hRootKey\OpenRCT2.ext] - if (RegSetValueW(hKey, nullptr, REG_SZ, fileTypeTextW, 0) != ERROR_SUCCESS) + if (RegSetValueW(hKey, nullptr, REG_SZ, fileTypeTextW.c_str(), 0) != ERROR_SUCCESS) { goto fail; } @@ -637,14 +617,14 @@ static bool windows_setup_file_association( } // [hRootKey\OpenRCT2.sv6\shell\open] - if (RegSetValueW(hKey, L"shell\\open", REG_SZ, commandTextW, 0) != ERROR_SUCCESS) + if (RegSetValueW(hKey, L"shell\\open", REG_SZ, commandTextW.c_str(), 0) != ERROR_SUCCESS) { goto fail; } // [hRootKey\OpenRCT2.sv6\shell\open\command] wchar_t szCommandW[MAX_PATH]; - printResult = swprintf_s(szCommandW, MAX_PATH, L"\"%s\" %s", exePathW, commandArgsW); + printResult = swprintf_s(szCommandW, MAX_PATH, L"\"%s\" %s", exePathW, commandArgsW.c_str()); assert(printResult >= 0); if (RegSetValueW(hKey, L"shell\\open\\command", REG_SZ, szCommandW, 0) != ERROR_SUCCESS) { @@ -653,10 +633,6 @@ static bool windows_setup_file_association( result = true; fail: - free(extensionW); - free(fileTypeTextW); - free(commandTextW); - free(commandArgsW); RegCloseKey(hKey); RegCloseKey(hRootKey); return result; @@ -672,9 +648,8 @@ static void windows_remove_file_association(const utf8* extension) RegDeleteTreeA(hRootKey, extension); // [hRootKey\OpenRCT2.ext] - wchar_t progIdName[128]; - get_progIdName(progIdName, extension); - RegDeleteTreeW(hRootKey, progIdName); + auto progIdName = get_progIdName(extension); + RegDeleteTreeW(hRootKey, progIdName.c_str()); RegCloseKey(hRootKey); } diff --git a/src/openrct2/platform/platform.h b/src/openrct2/platform/platform.h index bad0ad63eb..5a43d04b73 100644 --- a/src/openrct2/platform/platform.h +++ b/src/openrct2/platform/platform.h @@ -99,7 +99,7 @@ bool platform_original_rct1_data_exists(const utf8* path); time_t platform_file_get_modified_time(const utf8* path); bool platform_ensure_directory_exists(const utf8* path); bool platform_directory_delete(const utf8* path); -utf8* platform_get_absolute_path(const utf8* relative_path, const utf8* base_path); +std::string platform_get_absolute_path(const utf8* relative_path, const utf8* base_path); bool platform_lock_single_instance(); bool platform_place_string_on_clipboard(utf8* target); @@ -113,7 +113,7 @@ uint32_t platform_get_ticks(); void platform_sleep(uint32_t ms); void platform_get_openrct_data_path(utf8* outPath, size_t outSize); void platform_get_user_directory(utf8* outPath, const utf8* subDirectory, size_t outSize); -utf8* platform_get_username(); +std::string platform_get_username(); bool platform_open_common_file_dialog(utf8* outFilename, file_dialog_desc* desc, size_t outSize); utf8* platform_open_directory_browser(const utf8* title); uint8_t platform_get_locale_currency(); diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp index 4094c2b581..b452ad4c33 100644 --- a/src/openrct2/rct2/S6Exporter.cpp +++ b/src/openrct2/rct2/S6Exporter.cpp @@ -1189,11 +1189,11 @@ int32_t scenario_save(const utf8* path, int32_t flags) { if (flags & S6_SAVE_FLAG_SCENARIO) { - log_verbose("saving scenario"); + log_verbose("scenario_save(%s, SCENARIO)", path); } else { - log_verbose("saving game"); + log_verbose("scenario_save(%s, SAVED GAME)", path); } if (!(flags & S6_SAVE_FLAG_AUTOMATIC))