diff --git a/src/openrct2-ui/scripting/CustomListView.cpp b/src/openrct2-ui/scripting/CustomListView.cpp index 332d028b39..e6f8812736 100644 --- a/src/openrct2-ui/scripting/CustomListView.cpp +++ b/src/openrct2-ui/scripting/CustomListView.cpp @@ -17,6 +17,7 @@ #include #include + #include #include #include #include @@ -305,7 +306,7 @@ bool CustomListView::SortItem(size_t indexA, size_t indexB, int32_t column) { const auto& cellA = Items[indexA].Cells[column]; const auto& cellB = Items[indexB].Cells[column]; - return StrLogicalCmp(cellA.c_str(), cellB.c_str()) < 0; + return String::StrLogicalCmp(cellA.c_str(), cellB.c_str()) < 0; } void CustomListView::SortItems(int32_t column) diff --git a/src/openrct2-ui/windows/CustomCurrency.cpp b/src/openrct2-ui/windows/CustomCurrency.cpp index 84f4e0315a..1df9a6ecda 100644 --- a/src/openrct2-ui/windows/CustomCurrency.cpp +++ b/src/openrct2-ui/windows/CustomCurrency.cpp @@ -163,7 +163,7 @@ namespace OpenRCT2::Ui::Windows switch (widgetIndex) { case WIDX_SYMBOL_TEXT: - SafeStrCpy( + String::SafeStrCpy( CurrencyDescriptors[EnumValue(CurrencyType::Custom)].symbol_unicode, std::string(text).c_str(), kCurrencySymbolMaxSize); diff --git a/src/openrct2-ui/windows/EditorObjectSelection.cpp b/src/openrct2-ui/windows/EditorObjectSelection.cpp index 36874c7cd0..37bf4373de 100644 --- a/src/openrct2-ui/windows/EditorObjectSelection.cpp +++ b/src/openrct2-ui/windows/EditorObjectSelection.cpp @@ -775,7 +775,7 @@ namespace OpenRCT2::Ui::Windows width_limit /= 2; // Draw ride type StringId rideTypeStringId = GetRideTypeStringId(listItem.repositoryItem); - SafeStrCpy(buffer, LanguageGetString(rideTypeStringId), 256 - (buffer - bufferWithColour)); + String::SafeStrCpy(buffer, LanguageGetString(rideTypeStringId), 256 - (buffer - bufferWithColour)); auto ft = Formatter(); ft.Add(itemBuffer); DrawTextEllipsised( @@ -784,7 +784,7 @@ namespace OpenRCT2::Ui::Windows } // Draw text - SafeStrCpy(buffer, listItem.repositoryItem->Name.c_str(), 256 - (buffer - bufferWithColour)); + String::SafeStrCpy(buffer, listItem.repositoryItem->Name.c_str(), 256 - (buffer - bufferWithColour)); if (gScreenFlags & SCREEN_FLAGS_TRACK_MANAGER) { while (*buffer != 0 && *buffer != 9) @@ -826,7 +826,7 @@ namespace OpenRCT2::Ui::Windows if (strcmp(_filter_string, c) == 0) return; - SafeStrCpy(_filter_string, c, sizeof(_filter_string)); + String::SafeStrCpy(_filter_string, c, sizeof(_filter_string)); FilterUpdateCounts(); diff --git a/src/openrct2-ui/windows/Guest.cpp b/src/openrct2-ui/windows/Guest.cpp index 8afed04574..07f6131b98 100644 --- a/src/openrct2-ui/windows/Guest.cpp +++ b/src/openrct2-ui/windows/Guest.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1831,14 +1832,14 @@ namespace OpenRCT2::Ui::Windows if (peep->GetNextIsSurface()) { OpenRCT2::FormatStringLegacy(buffer2, sizeof(buffer2), STR_PEEP_DEBUG_NEXT_SURFACE, nullptr); - SafeStrCat(buffer, buffer2, sizeof(buffer)); + String::SafeStrCat(buffer, buffer2, sizeof(buffer)); } if (peep->GetNextIsSloped()) { auto ft2 = Formatter(); ft2.Add(peep->GetNextDirection()); OpenRCT2::FormatStringLegacy(buffer2, sizeof(buffer2), STR_PEEP_DEBUG_NEXT_SLOPE, ft2.Data()); - SafeStrCat(buffer, buffer2, sizeof(buffer)); + String::SafeStrCat(buffer, buffer2, sizeof(buffer)); } DrawText(dpi, screenCoords, {}, buffer); } diff --git a/src/openrct2-ui/windows/GuestList.cpp b/src/openrct2-ui/windows/GuestList.cpp index aa288bae2f..6fbe95f44e 100644 --- a/src/openrct2-ui/windows/GuestList.cpp +++ b/src/openrct2-ui/windows/GuestList.cpp @@ -958,7 +958,7 @@ namespace OpenRCT2::Ui::Windows } } } - return StrLogicalCmp(a.Name, b.Name) < 0; + return String::StrLogicalCmp(a.Name, b.Name) < 0; } static GuestItem::CompareFunc GetGuestCompareFunc() diff --git a/src/openrct2-ui/windows/LoadSave.cpp b/src/openrct2-ui/windows/LoadSave.cpp index c15424d652..113d061577 100644 --- a/src/openrct2-ui/windows/LoadSave.cpp +++ b/src/openrct2-ui/windows/LoadSave.cpp @@ -122,15 +122,15 @@ namespace OpenRCT2::Ui::Windows switch (Config::Get().general.LoadSaveSort) { case Sort::NameAscending: - return StrLogicalCmp(a.name.c_str(), b.name.c_str()) < 0; + return String::StrLogicalCmp(a.name.c_str(), b.name.c_str()) < 0; case Sort::NameDescending: - return -StrLogicalCmp(a.name.c_str(), b.name.c_str()) < 0; + return -String::StrLogicalCmp(a.name.c_str(), b.name.c_str()) < 0; case Sort::DateDescending: return -difftime(a.date_modified, b.date_modified) < 0; case Sort::DateAscending: return difftime(a.date_modified, b.date_modified) < 0; } - return StrLogicalCmp(a.name.c_str(), b.name.c_str()) < 0; + return String::StrLogicalCmp(a.name.c_str(), b.name.c_str()) < 0; } static void SetAndSaveConfigPath(u8string& config_str, u8string_view path) @@ -265,7 +265,7 @@ namespace OpenRCT2::Ui::Windows } char pathBuffer[MAX_PATH]; - SafeStrCpy(pathBuffer, path, sizeof(pathBuffer)); + String::SafeStrCpy(pathBuffer, path, sizeof(pathBuffer)); // Closing this will cause a Ride window to pop up, so we have to do this to ensure that // no windows are open (besides the toolbars and LoadSave window). @@ -502,7 +502,7 @@ namespace OpenRCT2::Ui::Windows void PopulateList(int32_t includeNewItem, const u8string& directory, std::string_view extensionPattern) { const auto absoluteDirectory = Path::GetAbsolute(directory); - SafeStrCpy(_directory, absoluteDirectory.c_str(), std::size(_directory)); + String::SafeStrCpy(_directory, absoluteDirectory.c_str(), std::size(_directory)); // Note: This compares the pointers, not values _extensionPattern = extensionPattern; @@ -535,7 +535,7 @@ namespace OpenRCT2::Ui::Windows else { // Remove the separator at the end of the path, if present - SafeStrCpy(_parentDirectory, absoluteDirectory.c_str(), std::size(_parentDirectory)); + String::SafeStrCpy(_parentDirectory, absoluteDirectory.c_str(), std::size(_parentDirectory)); if (_parentDirectory[strlen(_parentDirectory) - 1] == *PATH_SEPARATOR || _parentDirectory[strlen(_parentDirectory) - 1] == '/') _parentDirectory[strlen(_parentDirectory) - 1] = '\0'; @@ -961,7 +961,7 @@ namespace OpenRCT2::Ui::Windows includeNewItem = (_type & 1) == LOADSAVETYPE_SAVE; char directory[MAX_PATH]; - SafeStrCpy(directory, _listItems[selectedItem].path.c_str(), sizeof(directory)); + String::SafeStrCpy(directory, _listItems[selectedItem].path.c_str(), sizeof(directory)); PopulateList(includeNewItem, directory, _extensionPattern); InitScrollWidgets(); diff --git a/src/openrct2-ui/windows/NewCampaign.cpp b/src/openrct2-ui/windows/NewCampaign.cpp index 2f92e88115..99efe6c55e 100644 --- a/src/openrct2-ui/windows/NewCampaign.cpp +++ b/src/openrct2-ui/windows/NewCampaign.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -101,7 +102,7 @@ namespace OpenRCT2::Ui::Windows if (rideB != nullptr) rideBName = rideB->GetName(); - return StrLogicalCmp(rideAName.c_str(), rideBName.c_str()) < 0; + return String::StrLogicalCmp(rideAName.c_str(), rideBName.c_str()) < 0; } /** diff --git a/src/openrct2-ui/windows/RideList.cpp b/src/openrct2-ui/windows/RideList.cpp index 9e77a6f55a..63b7ec92ee 100644 --- a/src/openrct2-ui/windows/RideList.cpp +++ b/src/openrct2-ui/windows/RideList.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -809,7 +810,7 @@ namespace OpenRCT2::Ui::Windows void SortListByName() { std::sort(_rideList.begin(), _rideList.end(), [](const auto& lhs, const auto& rhs) { - return !(0 <= StrLogicalCmp(lhs.Name.c_str(), rhs.Name.c_str())); + return !(0 <= String::StrLogicalCmp(lhs.Name.c_str(), rhs.Name.c_str())); }); } diff --git a/src/openrct2-ui/windows/ScenarioSelect.cpp b/src/openrct2-ui/windows/ScenarioSelect.cpp index 1b7aa88986..f78a753e72 100644 --- a/src/openrct2-ui/windows/ScenarioSelect.cpp +++ b/src/openrct2-ui/windows/ScenarioSelect.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -445,7 +446,7 @@ namespace OpenRCT2::Ui::Windows // Draw scenario name char buffer[64]; - SafeStrCpy(buffer, scenario->Name, sizeof(buffer)); + String::SafeStrCpy(buffer, scenario->Name, sizeof(buffer)); StringId format = isDisabled ? static_cast(STR_STRINGID) : (isHighlighted ? highlighted_format : unhighlighted_format); auto ft = Formatter(); diff --git a/src/openrct2-ui/windows/ServerStart.cpp b/src/openrct2-ui/windows/ServerStart.cpp index dc851cb5ea..442395b8d4 100644 --- a/src/openrct2-ui/windows/ServerStart.cpp +++ b/src/openrct2-ui/windows/ServerStart.cpp @@ -16,6 +16,7 @@ #include #include #include + #include #include #include #include @@ -84,9 +85,9 @@ namespace OpenRCT2::Ui::Windows list_information_type = 0; snprintf(_port, 7, "%u", Config::Get().network.DefaultPort); - SafeStrCpy(_name, Config::Get().network.ServerName.c_str(), sizeof(_name)); - SafeStrCpy(_description, Config::Get().network.ServerDescription.c_str(), sizeof(_description)); - SafeStrCpy(_greeting, Config::Get().network.ServerGreeting.c_str(), sizeof(_greeting)); + String::SafeStrCpy(_name, Config::Get().network.ServerName.c_str(), sizeof(_name)); + String::SafeStrCpy(_description, Config::Get().network.ServerDescription.c_str(), sizeof(_description)); + String::SafeStrCpy(_greeting, Config::Get().network.ServerGreeting.c_str(), sizeof(_greeting)); } void OnMouseUp(WidgetIndex widgetIndex) override { @@ -175,7 +176,7 @@ namespace OpenRCT2::Ui::Windows if (strcmp(_port, temp.c_str()) == 0) return; - SafeStrCpy(_port, temp.c_str(), sizeof(_port)); + String::SafeStrCpy(_port, temp.c_str(), sizeof(_port)); // Don't allow negative/zero for port number tempPort = atoi(_port); @@ -191,7 +192,7 @@ namespace OpenRCT2::Ui::Windows if (strcmp(_name, temp.c_str()) == 0) return; - SafeStrCpy(_name, temp.c_str(), sizeof(_name)); + String::SafeStrCpy(_name, temp.c_str(), sizeof(_name)); // Don't allow empty server names if (_name[0] != '\0') @@ -206,7 +207,7 @@ namespace OpenRCT2::Ui::Windows if (strcmp(_description, temp.c_str()) == 0) return; - SafeStrCpy(_description, temp.c_str(), sizeof(_description)); + String::SafeStrCpy(_description, temp.c_str(), sizeof(_description)); Config::Get().network.ServerDescription = _description; Config::Save(); @@ -216,7 +217,7 @@ namespace OpenRCT2::Ui::Windows if (strcmp(_greeting, temp.c_str()) == 0) return; - SafeStrCpy(_greeting, temp.c_str(), sizeof(_greeting)); + String::SafeStrCpy(_greeting, temp.c_str(), sizeof(_greeting)); Config::Get().network.ServerGreeting = _greeting; Config::Save(); @@ -226,7 +227,7 @@ namespace OpenRCT2::Ui::Windows if (strcmp(_password, temp.c_str()) == 0) return; - SafeStrCpy(_password, temp.c_str(), sizeof(_password)); + String::SafeStrCpy(_password, temp.c_str(), sizeof(_password)); WidgetInvalidate(*this, WIDX_PASSWORD_INPUT); break; diff --git a/src/openrct2-ui/windows/StaffList.cpp b/src/openrct2-ui/windows/StaffList.cpp index 26bac9eb69..7adae461df 100644 --- a/src/openrct2-ui/windows/StaffList.cpp +++ b/src/openrct2-ui/windows/StaffList.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -516,7 +517,7 @@ namespace OpenRCT2::Ui::Windows } std::sort(_staffList.begin(), _staffList.end(), [](const auto& a, const auto& b) { - return StrLogicalCmp(a.Name.c_str(), b.Name.c_str()) < 0; + return String::StrLogicalCmp(a.Name.c_str(), b.Name.c_str()) < 0; }); } diff --git a/src/openrct2/Game.cpp b/src/openrct2/Game.cpp index 444b9b3890..0216a36fb9 100644 --- a/src/openrct2/Game.cpp +++ b/src/openrct2/Game.cpp @@ -31,6 +31,7 @@ #include "core/Money.hpp" #include "core/Path.hpp" #include "core/SawyerCoding.h" +#include "core/String.hpp" #include "entity/EntityRegistry.h" #include "entity/PatrolArea.h" #include "entity/Peep.h" @@ -173,7 +174,7 @@ void RCT2StringToUTF8Self(char* buffer, size_t length) if (length > 0) { auto temp = RCT2StringToUTF8(buffer, RCT2LanguageId::EnglishUK); - SafeStrCpy(buffer, temp.data(), length); + String::SafeStrCpy(buffer, temp.data(), length); } } diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index d0a57c094f..45e02cd0b6 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -9,6 +9,7 @@ #include "../Diagnostic.h" +#include #include #include #include @@ -493,7 +494,7 @@ namespace OpenRCT2::String size_t newStringSize = (nextCh - 1) - firstNonWhitespace; #ifdef DEBUG - size_t currentStringSize = String::SizeOf(str); + size_t currentStringSize = SizeOf(str); Guard::Assert(newStringSize < currentStringSize, GUARD_LINE); #endif @@ -652,7 +653,7 @@ namespace OpenRCT2::String return std::string(src); } - return String::ToUtf8(dstW); + return ToUtf8(dstW); #else icu::UnicodeString str = icu::UnicodeString::fromUTF8(std::string(src)); str.toUpper(); @@ -721,4 +722,124 @@ namespace OpenRCT2::String return escaped.str(); } + + /* Case insensitive logical compare */ + // Example: + // - Guest 10 + // - Guest 99 + // - Guest 100 + // - John v2.0 + // - John v2.1 + int32_t StrLogicalCmp(const char* s1, const char* s2) + { + for (;;) + { + if (*s2 == '\0') + return *s1 != '\0'; + if (*s1 == '\0') + return -1; + if (!(isdigit(static_cast(*s1)) && isdigit(static_cast(*s2)))) + { + if (toupper(*s1) != toupper(*s2)) + return toupper(*s1) - toupper(*s2); + + ++s1; + ++s2; + } + else + { + char *lim1, *lim2; + unsigned long n1 = strtoul(s1, &lim1, 10); + unsigned long n2 = strtoul(s2, &lim2, 10); + if (n1 > n2) + return 1; + if (n1 < n2) + return -1; + + s1 = lim1; + s2 = lim2; + } + } + } + + char* SafeStrCpy(char* destination, const char* source, size_t size) + { + assert(destination != nullptr); + assert(source != nullptr); + + if (size == 0) + return destination; + + char* result = destination; + + bool truncated = false; + const char* sourceLimit = source + size - 1; + const char* ch = source; + uint32_t codepoint; + while ((codepoint = UTF8GetNext(ch, &ch)) != 0) + { + if (ch <= sourceLimit) + { + destination = UTF8WriteCodepoint(destination, codepoint); + } + else + { + truncated = true; + } + } + *destination = 0; + + if (truncated) + { + LOG_WARNING("Truncating string \"%s\" to %d bytes.", result, size); + } + return result; + } + + char* SafeStrCat(char* destination, const char* source, size_t size) + { + assert(destination != nullptr); + assert(source != nullptr); + + if (size == 0) + { + return destination; + } + + char* result = destination; + + size_t i; + for (i = 0; i < size; i++) + { + if (*destination == '\0') + { + break; + } + + destination++; + } + + bool terminated = false; + for (; i < size; i++) + { + if (*source != '\0') + { + *destination++ = *source++; + } + else + { + *destination = *source; + terminated = true; + break; + } + } + + if (!terminated) + { + result[size - 1] = '\0'; + LOG_WARNING("Truncating string \"%s\" to %d bytes.", result, size); + } + + return result; + } } // namespace OpenRCT2::String diff --git a/src/openrct2/core/String.hpp b/src/openrct2/core/String.hpp index bdcf2ce5aa..64ac4de99d 100644 --- a/src/openrct2/core/String.hpp +++ b/src/openrct2/core/String.hpp @@ -184,4 +184,8 @@ namespace OpenRCT2::String // Escapes special characters in a string to the percentage equivalent that can be used in URLs. std::string URLEncode(std::string_view value); + + int32_t StrLogicalCmp(char const* a, char const* b); + char* SafeStrCpy(char* destination, const char* source, size_t num); + char* SafeStrCat(char* destination, const char* source, size_t size); } // namespace OpenRCT2::String diff --git a/src/openrct2/entity/Peep.cpp b/src/openrct2/entity/Peep.cpp index c9e12c506d..284a7a0ca4 100644 --- a/src/openrct2/entity/Peep.cpp +++ b/src/openrct2/entity/Peep.cpp @@ -22,6 +22,7 @@ #include "../audio/audio.h" #include "../config/Config.h" #include "../core/Guard.hpp" +#include "../core/String.hpp" #include "../drawing/LightFX.h" #include "../entity/Balloon.h" #include "../entity/EntityRegistry.h" @@ -2663,7 +2664,7 @@ int32_t PeepCompare(const EntityId sprite_index_a, const EntityId sprite_index_b ft.Rewind(); peep_b->FormatNameTo(ft); OpenRCT2::FormatStringLegacy(nameB, sizeof(nameB), STR_STRINGID, ft.Data()); - return StrLogicalCmp(nameA, nameB); + return String::StrLogicalCmp(nameA, nameB); } /** diff --git a/src/openrct2/localisation/Currency.cpp b/src/openrct2/localisation/Currency.cpp index 9ae77042f4..ff2c44c865 100644 --- a/src/openrct2/localisation/Currency.cpp +++ b/src/openrct2/localisation/Currency.cpp @@ -11,6 +11,7 @@ #include "../config/Config.h" #include "../core/Guard.hpp" +#include "../core/String.hpp" #include "../util/Util.h" #include "Formatting.h" #include "StringIds.h" @@ -46,7 +47,7 @@ void CurrencyLoadCustomCurrencyConfig() CurrencyDescriptors[EnumValue(CurrencyType::Custom)].affix_unicode = Config::Get().general.CustomCurrencyAffix; if (!Config::Get().general.CustomCurrencySymbol.empty()) { - SafeStrCpy( + String::SafeStrCpy( CurrencyDescriptors[EnumValue(CurrencyType::Custom)].symbol_unicode, Config::Get().general.CustomCurrencySymbol.c_str(), kCurrencySymbolMaxSize); } diff --git a/src/openrct2/ride/TrackDesignRepository.cpp b/src/openrct2/ride/TrackDesignRepository.cpp index 8e4d30663a..595c305f25 100644 --- a/src/openrct2/ride/TrackDesignRepository.cpp +++ b/src/openrct2/ride/TrackDesignRepository.cpp @@ -281,7 +281,7 @@ private: { return a.RideType < b.RideType; } - return StrLogicalCmp(a.Name.c_str(), b.Name.c_str()) < 0; + return String::StrLogicalCmp(a.Name.c_str(), b.Name.c_str()) < 0; }); } diff --git a/src/openrct2/scenes/title/TitleSequence.cpp b/src/openrct2/scenes/title/TitleSequence.cpp index 5a218823e7..375902905a 100644 --- a/src/openrct2/scenes/title/TitleSequence.cpp +++ b/src/openrct2/scenes/title/TitleSequence.cpp @@ -380,7 +380,7 @@ namespace OpenRCT2::Title { auto entityID = EntityId::FromUnderlying(atoi(parts[1].data()) & 0xFFFF); auto followCommand = FollowEntityCommand{ entityID }; - SafeStrCpy(followCommand.Follow.SpriteName, parts[2].data(), kUserStringMaxLength); + String::SafeStrCpy(followCommand.Follow.SpriteName, parts[2].data(), kUserStringMaxLength); command = followCommand; } else if (String::IEquals(token, "WAIT")) @@ -399,7 +399,7 @@ namespace OpenRCT2::Title else if (String::IEquals(token, "LOADSC")) { auto loadScenarioCommand = LoadScenarioCommand{}; - SafeStrCpy(loadScenarioCommand.Scenario, parts[1].data(), sizeof(loadScenarioCommand.Scenario)); + String::SafeStrCpy(loadScenarioCommand.Scenario, parts[1].data(), sizeof(loadScenarioCommand.Scenario)); command = loadScenarioCommand; } } diff --git a/src/openrct2/util/Util.cpp b/src/openrct2/util/Util.cpp index b207a8037c..4444c6cade 100644 --- a/src/openrct2/util/Util.cpp +++ b/src/openrct2/util/Util.cpp @@ -23,126 +23,6 @@ #include #include -/* Case insensitive logical compare */ -// Example: -// - Guest 10 -// - Guest 99 -// - Guest 100 -// - John v2.0 -// - John v2.1 -int32_t StrLogicalCmp(const char* s1, const char* s2) -{ - for (;;) - { - if (*s2 == '\0') - return *s1 != '\0'; - if (*s1 == '\0') - return -1; - if (!(isdigit(static_cast(*s1)) && isdigit(static_cast(*s2)))) - { - if (toupper(*s1) != toupper(*s2)) - return toupper(*s1) - toupper(*s2); - - ++s1; - ++s2; - } - else - { - char *lim1, *lim2; - unsigned long n1 = strtoul(s1, &lim1, 10); - unsigned long n2 = strtoul(s2, &lim2, 10); - if (n1 > n2) - return 1; - if (n1 < n2) - return -1; - - s1 = lim1; - s2 = lim2; - } - } -} - -char* SafeStrCpy(char* destination, const char* source, size_t size) -{ - assert(destination != nullptr); - assert(source != nullptr); - - if (size == 0) - return destination; - - char* result = destination; - - bool truncated = false; - const char* sourceLimit = source + size - 1; - const char* ch = source; - uint32_t codepoint; - while ((codepoint = UTF8GetNext(ch, &ch)) != 0) - { - if (ch <= sourceLimit) - { - destination = UTF8WriteCodepoint(destination, codepoint); - } - else - { - truncated = true; - } - } - *destination = 0; - - if (truncated) - { - LOG_WARNING("Truncating string \"%s\" to %d bytes.", result, size); - } - return result; -} - -char* SafeStrCat(char* destination, const char* source, size_t size) -{ - assert(destination != nullptr); - assert(source != nullptr); - - if (size == 0) - { - return destination; - } - - char* result = destination; - - size_t i; - for (i = 0; i < size; i++) - { - if (*destination == '\0') - { - break; - } - - destination++; - } - - bool terminated = false; - for (; i < size; i++) - { - if (*source != '\0') - { - *destination++ = *source++; - } - else - { - *destination = *source; - terminated = true; - break; - } - } - - if (!terminated) - { - result[size - 1] = '\0'; - LOG_WARNING("Truncating string \"%s\" to %d bytes.", result, size); - } - - return result; -} - uint32_t UtilRand() { thread_local std::mt19937 _prng(std::random_device{}()); diff --git a/src/openrct2/util/Util.h b/src/openrct2/util/Util.h index 3a985ed0b5..5b35eb3f6d 100644 --- a/src/openrct2/util/Util.h +++ b/src/openrct2/util/Util.h @@ -12,10 +12,6 @@ #include "../core/Money.hpp" #include "../core/StringTypes.h" -int32_t StrLogicalCmp(char const* a, char const* b); -char* SafeStrCpy(char* destination, const char* source, size_t num); -char* SafeStrCat(char* destination, const char* source, size_t size); - uint32_t UtilRand(); float UtilRandNormalDistributed(); diff --git a/test/tests/StringTest.cpp b/test/tests/StringTest.cpp index 733a86366b..020c43618f 100644 --- a/test/tests/StringTest.cpp +++ b/test/tests/StringTest.cpp @@ -146,8 +146,8 @@ TEST_F(StringTest, ToUpper_Japanese) TEST_F(StringTest, StrLogicalCmp) { - auto res_logical_1 = StrLogicalCmp("foo1", "foo1_2"); - auto res_logical_2 = StrLogicalCmp("foo1_2", "foo1"); + auto res_logical_1 = String::StrLogicalCmp("foo1", "foo1_2"); + auto res_logical_2 = String::StrLogicalCmp("foo1_2", "foo1"); auto res_1 = strcmp("foo1", "foo1_2"); auto res_2 = strcmp("foo1_2", "foo1"); // We only care if sign is correct, actual values might not be. @@ -155,22 +155,22 @@ TEST_F(StringTest, StrLogicalCmp) EXPECT_GE(res_2 * res_logical_2, 1); EXPECT_NE(res_logical_1, res_logical_2); - EXPECT_GT(StrLogicalCmp("foo12", "foo1"), 0); - EXPECT_LT(StrLogicalCmp("foo12", "foo13"), 0); - EXPECT_EQ(StrLogicalCmp("foo13", "foo13"), 0); + EXPECT_GT(String::StrLogicalCmp("foo12", "foo1"), 0); + EXPECT_LT(String::StrLogicalCmp("foo12", "foo13"), 0); + EXPECT_EQ(String::StrLogicalCmp("foo13", "foo13"), 0); - EXPECT_EQ(StrLogicalCmp("foo13", "FOO13"), 0); + EXPECT_EQ(String::StrLogicalCmp("foo13", "FOO13"), 0); - EXPECT_LT(StrLogicalCmp("A", "b"), 0); - EXPECT_LT(StrLogicalCmp("a", "B"), 0); - EXPECT_GT(StrLogicalCmp("B", "a"), 0); - EXPECT_GT(StrLogicalCmp("b", "A"), 0); + EXPECT_LT(String::StrLogicalCmp("A", "b"), 0); + EXPECT_LT(String::StrLogicalCmp("a", "B"), 0); + EXPECT_GT(String::StrLogicalCmp("B", "a"), 0); + EXPECT_GT(String::StrLogicalCmp("b", "A"), 0); // ^ is used at the start of a ride name to move it to the end of the list - EXPECT_LT(StrLogicalCmp("A", "^"), 0); - EXPECT_LT(StrLogicalCmp("a", "^"), 0); - EXPECT_LT(StrLogicalCmp("!", "A"), 0); - EXPECT_LT(StrLogicalCmp("!", "a"), 0); + EXPECT_LT(String::StrLogicalCmp("A", "^"), 0); + EXPECT_LT(String::StrLogicalCmp("a", "^"), 0); + EXPECT_LT(String::StrLogicalCmp("!", "A"), 0); + EXPECT_LT(String::StrLogicalCmp("!", "a"), 0); } TEST_F(StringTest, IEqualsU8String)