mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-17 12:03:07 +01:00
Merge pull request #9629 from IntelOrca/fix/utf8-support-windows
Fix UTF-8 support on Windows
This commit is contained in:
@@ -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<const char**>(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);
|
||||
|
||||
@@ -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<size_t>(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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace File
|
||||
std::vector<uint8_t> 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
|
||||
{
|
||||
|
||||
@@ -227,11 +227,11 @@ public:
|
||||
|
||||
void GetDirectoryChildren(std::vector<DirectoryChild>& 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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -1356,8 +1356,8 @@ void Network::BeginChatLog()
|
||||
_chatLogPath = BeginLog(directory, "", _chatLogFilenameFormat);
|
||||
|
||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||
auto pathW = std::unique_ptr<wchar_t>(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<wchar_t>(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
|
||||
|
||||
@@ -68,7 +68,7 @@ static bool UploadMinidump(const std::map<std::wstring, std::wstring>& 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<S6Exporter>();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user