From 171969f5fb9c3cc01606c260c249955f73ce9c51 Mon Sep 17 00:00:00 2001 From: Ted John Date: Thu, 9 Jan 2020 20:47:54 +0000 Subject: [PATCH 1/2] Fix #10496: Game can't handle path with non-english string --- src/openrct2/core/Path.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openrct2/core/Path.cpp b/src/openrct2/core/Path.cpp index 2206901ef6..3be125d853 100644 --- a/src/openrct2/core/Path.cpp +++ b/src/openrct2/core/Path.cpp @@ -144,7 +144,7 @@ namespace Path const std::string GetExtension(const std::string& path) { - return fs::path{ path }.extension().string(); + return fs::u8path(path).extension().string(); } const utf8* GetExtension(const utf8* path) From 9562f42d9148f2cae03e0d7fe0c861bbbba3c360 Mon Sep 17 00:00:00 2001 From: Ted John Date: Sat, 11 Jan 2020 00:42:48 +0000 Subject: [PATCH 2/2] Convert object filenames to UTF-8 when exporting --- src/openrct2/object/ObjectRepository.cpp | 69 ++++++++++++------------ 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/src/openrct2/object/ObjectRepository.cpp b/src/openrct2/object/ObjectRepository.cpp index 17ff6e723c..557dcda31a 100644 --- a/src/openrct2/object/ObjectRepository.cpp +++ b/src/openrct2/object/ObjectRepository.cpp @@ -42,6 +42,9 @@ #include #include +// windows.h defines CP_UTF8 +#undef CP_UTF8 + using namespace OpenRCT2; struct ObjectEntryHash @@ -323,10 +326,8 @@ public: } else { - utf8 path[MAX_PATH]; - GetPathForNewObject(path, sizeof(path), objectName); - log_verbose("Adding object: [%s]", objectName); + auto path = GetPathForNewObject(objectName); try { SaveObject(path, objectEntry, data, dataSize); @@ -334,18 +335,15 @@ public: } catch (const std::exception&) { - Console::Error::WriteLine("Failed saving object: [%s] to '%s'.", objectName, path); + Console::Error::WriteLine("Failed saving object: [%s] to '%s'.", objectName, path.c_str()); } } } void AddObjectFromFile(const std::string_view& objectName, const void* data, size_t dataSize) override { - utf8 path[MAX_PATH]; - std::string objectNameString(objectName); - GetPathForNewObject(path, sizeof(path), objectNameString.c_str()); - - log_verbose("Adding object: [%s]", objectNameString.c_str()); + log_verbose("Adding object: [%s]", std::string(objectName).c_str()); + auto path = GetPathForNewObject(objectName); try { File::WriteAllBytes(path, data, dataSize); @@ -353,7 +351,7 @@ public: } catch (const std::exception&) { - Console::Error::WriteLine("Failed saving object: [%s] to '%s'.", objectNameString.c_str(), path); + Console::Error::WriteLine("Failed saving object: [%s] to '%s'.", std::string(objectName).c_str(), path.c_str()); } } @@ -470,7 +468,7 @@ private: } static void SaveObject( - const utf8* path, const rct_object_entry* entry, const void* data, size_t dataSize, bool fixChecksum = true) + const std::string_view& path, const rct_object_entry* entry, const void* data, size_t dataSize, bool fixChecksum = true) { if (fixChecksum) { @@ -532,7 +530,7 @@ private: // Save to file try { - auto fs = FileStream(path, FILE_MODE_WRITE); + auto fs = FileStream(std::string(path), FILE_MODE_WRITE); fs.Write(entry, sizeof(rct_object_entry)); fs.Write(encodedDataBuffer, encodedDataSize); @@ -575,10 +573,31 @@ private: return salt; } - void GetPathForNewObject(utf8* buffer, size_t bufferSize, const char* name) + std::string GetPathForNewObject(const std::string_view& name) { + // Get object directory and create it if it doesn't exist + auto userObjPath = _env->GetDirectoryPath(DIRBASE::USER, DIRID::OBJECT); + Path::CreateDirectory(userObjPath); + + // Find a unique file name + auto fileName = GetFileNameForNewObject(name); + auto fullPath = Path::Combine(userObjPath, fileName + ".DAT"); + auto counter = 1U; + while (File::Exists(fullPath)) + { + counter++; + fullPath = Path::Combine(userObjPath, String::StdFormat("%s-%02X.DAT", fileName.c_str(), counter)); + } + + return fullPath; + } + + std::string GetFileNameForNewObject(const std::string_view& name) + { + // Trim name char normalisedName[9] = { 0 }; - for (int32_t i = 0; i < 8; i++) + auto maxLength = std::min(name.size(), 8); + for (size_t i = 0; i < maxLength; i++) { if (name[i] != ' ') { @@ -587,28 +606,12 @@ private: else { normalisedName[i] = '\0'; + break; } } - const std::string& userObjPath = _env->GetDirectoryPath(DIRBASE::USER, DIRID::OBJECT); - String::Set(buffer, bufferSize, userObjPath.c_str()); - platform_ensure_directory_exists(buffer); - - Path::Append(buffer, bufferSize, normalisedName); - String::Append(buffer, bufferSize, ".DAT"); - - uint32_t counter = 2; - for (; platform_file_exists(buffer);) - { - utf8 counterString[8]; - snprintf(counterString, sizeof(counterString), "-%02X", counter); - counter++; - - String::Set(buffer, bufferSize, userObjPath.c_str()); - Path::Append(buffer, bufferSize, normalisedName); - String::Append(buffer, bufferSize, counterString); - String::Append(buffer, bufferSize, ".DAT"); - } + // Convert to UTF-8 filename + return String::Convert(normalisedName, CODE_PAGE::CP_1252, CODE_PAGE::CP_UTF8); } void WritePackedObject(IStream* stream, const rct_object_entry* entry)