From f53f17878c989fff3b8cd2cd5248959e7707044f Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Thu, 3 Jul 2025 21:47:11 +0200 Subject: [PATCH 01/11] Add truncateBy and truncateTo methods to string classes. --- .../GameEngine/Include/Common/AsciiString.h | 13 +++++++++ .../GameEngine/Include/Common/UnicodeString.h | 13 +++++++++ .../Include/GameClient/DisplayString.h | 3 ++ .../Source/Common/System/AsciiString.cpp | 29 +++++++++++++++++-- .../Source/Common/System/UnicodeString.cpp | 29 +++++++++++++++++-- .../Source/GameClient/DisplayString.cpp | 25 ++++++++++++++++ 6 files changed, 106 insertions(+), 6 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h b/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h index 9b304aa980..1fc42d0924 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h @@ -240,6 +240,19 @@ class AsciiString */ void removeLastChar(); + /** + Remove the final charCount characters in the string. If the string is empty, + do nothing. + */ + void truncateBy(const UnsignedInt charCount); + + /** + Truncate the string to a length of maxLength characters, not including null termination, + by removing from the end. + If the string is empty or shorter than maxLength, do nothing. + */ + void truncateTo(const UnsignedInt maxLength); + /** Analogous to sprintf() -- this formats a string according to the given sprintf-style format string (and the variable argument list) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h b/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h index b0ef11bd8f..33ed489864 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h @@ -235,6 +235,19 @@ class UnicodeString */ void removeLastChar(); + /** + Remove the final charCount characters in the string. If the string is empty, + do nothing. + */ + void truncateBy(const UnsignedInt charCount); + + /** + Truncate the string to a length of maxLength characters, not including null termination, + by removing from the end. + If the string is empty or shorter than maxLength, do nothing. + */ + void truncateTo(const UnsignedInt maxLength); + /** Analogous to sprintf() -- this formats a string according to the given sprintf-style format string (and the variable argument list) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/DisplayString.h b/GeneralsMD/Code/GameEngine/Include/GameClient/DisplayString.h index e0ca7336c1..039a9f1e9c 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/DisplayString.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/DisplayString.h @@ -100,6 +100,9 @@ class DisplayString : public MemoryPoolObject virtual void setClipRegion( IRegion2D *region ); ///< clip text in this region virtual void removeLastChar( void ); ///< remove the last character + virtual void truncateBy(const UnsignedInt charCount); ///< remove the last charCount characters + virtual void truncateTo(const UnsignedInt maxLength); ///< remove characters, if needed, until the string is maxLength long excluding null terminator + virtual void appendChar( WideChar c ); ///< append character to end DisplayString *next( void ); ///< return next string diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp index 7250d53b5a..d86716fb42 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp @@ -331,15 +331,38 @@ void AsciiString::toLower() // ----------------------------------------------------- void AsciiString::removeLastChar() +{ + truncateBy(1); +} + +// ----------------------------------------------------- +void AsciiString::truncateBy(const UnsignedInt charCount) { validate(); - if (m_data) + if (m_data && charCount > 0) { - int len = strlen(peek()); + size_t len = strlen(peek()); if (len > 0) { ensureUniqueBufferOfSize(len+1, true, NULL, NULL); - peek()[len - 1] = 0; + size_t count = min(charCount, len); + peek()[len - count] = 0; + } + } + validate(); +} + +// ----------------------------------------------------- +void AsciiString::truncateTo(const UnsignedInt maxLength) +{ + validate(); + if (m_data) + { + size_t len = strlen(peek()); + if (len > maxLength) + { + ensureUniqueBufferOfSize(len + 1, true, NULL, NULL); + peek()[maxLength] = 0; } } validate(); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp index 235e9f8868..33160baa35 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp @@ -268,15 +268,38 @@ void UnicodeString::trim() // ----------------------------------------------------- void UnicodeString::removeLastChar() +{ + truncateBy(1); +} + +// ----------------------------------------------------- +void UnicodeString::truncateBy(const UnsignedInt charCount) { validate(); - if (m_data) + if (m_data && charCount > 0) { - int len = wcslen(peek()); + size_t len = wcslen(peek()); if (len > 0) { ensureUniqueBufferOfSize(len+1, true, NULL, NULL); - peek()[len - 1] = 0; + size_t count = min(charCount, len); + peek()[len - count] = 0; + } + } + validate(); +} + +// ----------------------------------------------------- +void UnicodeString::truncateTo(const UnsignedInt maxLength) +{ + validate(); + if (m_data) + { + size_t len = wcslen(peek()); + if (len > maxLength) + { + ensureUniqueBufferOfSize(len + 1, true, NULL, NULL); + peek()[maxLength] = 0; } } validate(); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/DisplayString.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/DisplayString.cpp index e67b95af57..e99ae39b1f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/DisplayString.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/DisplayString.cpp @@ -133,6 +133,31 @@ void DisplayString::removeLastChar( void ) } // end removeLastChar +// DisplayString::truncateBy ================================================== +/** Remove the last charCount characters from the string text */ +//============================================================================= +void DisplayString::truncateBy( const UnsignedInt charCount ) +{ + m_textString.truncateBy(charCount); + + // our text has now changed + notifyTextChanged(); + +} // end truncateBy + +// DisplayString::truncateTo ================================================== +/** Remove the last characters from the string text so it's at the most + * maxLength characters long */ +//============================================================================= +void DisplayString::truncateTo( const UnsignedInt maxLength ) +{ + m_textString.truncateTo(maxLength); + + // our text has now changed + notifyTextChanged(); + +} // end truncateTo + // DisplayString::appendChar ================================================== /** Append character to the end of the string */ //============================================================================= From b82d101c8456cb213ce9e4884aba8bad9c53e9a5 Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Thu, 10 Jul 2025 18:31:47 +0200 Subject: [PATCH 02/11] Update trim to use truncateTo --- .../Source/Common/System/AsciiString.cpp | 17 ++++++++--------- .../Source/Common/System/UnicodeString.cpp | 17 ++++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp index eec745a2f1..c61a065b09 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp @@ -293,16 +293,15 @@ void AsciiString::trim() { // Clip trailing white space from the string. int len = strlen(peek()); - for (int index = len-1; index >= 0; index--) + int index = len - 1; + while (index >= 0 && isspace(getCharAt(index))) { - if (isspace(getCharAt(index))) - { - removeLastChar(); - } - else - { - break; - } + --index; + } + + if (index < len - 1) + { + truncateTo(index + 1); } } } diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp index bce4df7682..34ad1c9eaa 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp @@ -245,16 +245,15 @@ void UnicodeString::trim() { // Clip trailing white space from the string. int len = wcslen(peek()); - for (int index = len-1; index >= 0; index--) + int index = len - 1; + while (index >= 0 && iswspace(getCharAt(index))) { - if (iswspace(getCharAt(index))) - { - removeLastChar(); - } - else - { - break; - } + --index; + } + + if (index < len - 1) + { + truncateTo(index + 1); } } } From b5c039a9394c014ae589892a311d1495860c65a8 Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Thu, 10 Jul 2025 19:00:01 +0200 Subject: [PATCH 03/11] Replace repeated use of removeLastChar() with truncateBy or truncateTo. --- .../Source/Common/ReplaySimulation.cpp | 23 +++++++++---------- .../GameEngine/Source/Common/CommandLine.cpp | 5 +--- .../GameEngine/Source/Common/GameEngine.cpp | 4 +--- .../GameEngine/Source/Common/Recorder.cpp | 4 +--- .../Source/Common/StatsCollector.cpp | 5 +--- .../Common/System/SaveGame/GameState.cpp | 3 +-- .../Source/Common/UserPreferences.cpp | 11 ++------- .../GUI/GUICallbacks/Menus/LanLobbyMenu.cpp | 10 ++++---- .../Menus/NetworkDirectConnect.cpp | 9 +++----- .../GUI/GUICallbacks/Menus/PopupSaveLoad.cpp | 5 +--- .../GUI/GUICallbacks/Menus/ReplayMenu.cpp | 3 +-- .../GUICallbacks/Menus/WOLBuddyOverlay.cpp | 6 ++--- .../GUI/GUICallbacks/Menus/WOLLoginMenu.cpp | 19 ++++++++------- .../GameEngine/Source/GameClient/MapUtil.cpp | 11 +++------ .../Source/GameNetwork/GameInfo.cpp | 4 +--- .../Source/GameNetwork/GameSpy/LadderDefs.cpp | 3 +-- .../GameEngine/Source/GameNetwork/LANAPI.cpp | 3 +-- .../WorldBuilder/src/WorldBuilderDoc.cpp | 9 ++++++-- 18 files changed, 51 insertions(+), 86 deletions(-) diff --git a/Core/GameEngine/Source/Common/ReplaySimulation.cpp b/Core/GameEngine/Source/Common/ReplaySimulation.cpp index 354925c8fc..b3b444e808 100644 --- a/Core/GameEngine/Source/Common/ReplaySimulation.cpp +++ b/Core/GameEngine/Source/Common/ReplaySimulation.cpp @@ -215,19 +215,18 @@ std::vector ReplaySimulation::resolveFilenameWildcards(const std::v AsciiString dir1 = TheRecorder->getReplayDir(); AsciiString dir2 = *filename; AsciiString wildcard = *filename; + const char* lastSep = dir2.reverseFind('\\'); + if (lastSep == NULL) { - int len = dir2.getLength(); - while (len) - { - char c = dir2.getCharAt(len-1); - if (c == '/' || c == '\\') - { - wildcard.set(wildcard.str()+dir2.getLength()); - break; - } - dir2.removeLastChar(); - len--; - } + lastSep = dir2.reverseFind('/'); + } + + if (lastSep != NULL) + { + // include one extra char so the separator itself gets included + int lenToLastSep = lastSep - dir2.str() + sizeof(char); + dir2.truncateTo(lenToLastSep); + wildcard.set(wildcard.str() + lenToLastSep); } FilenameList files; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/CommandLine.cpp b/GeneralsMD/Code/GameEngine/Source/Common/CommandLine.cpp index 0a25c90db7..10f3f7c913 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/CommandLine.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/CommandLine.cpp @@ -95,10 +95,7 @@ static void ConvertShortMapPathToLongMapPath(AsciiString &mapName) DEBUG_CRASH(("Invalid map name %s", mapName.str())); } // remove the .map from the end. - token.removeLastChar(); - token.removeLastChar(); - token.removeLastChar(); - token.removeLastChar(); + token.truncateBy(4); actualpath.concat(token); actualpath.concat('\\'); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp index 1e2f3ec1e8..42a12ab7ae 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp @@ -957,9 +957,7 @@ void updateTGAtoDDS() } // replace tga with dds - filenameDDS.removeLastChar(); // a - filenameDDS.removeLastChar(); // g - filenameDDS.removeLastChar(); // t + filenameDDS.truncateBy(3); // tga filenameDDS.concat("dds"); Bool needsToBeUpdated = FALSE; diff --git a/GeneralsMD/Code/GameEngine/Source/Common/Recorder.cpp b/GeneralsMD/Code/GameEngine/Source/Common/Recorder.cpp index 7578c2f8e5..532850318d 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/Recorder.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/Recorder.cpp @@ -297,9 +297,7 @@ void RecorderClass::cleanUpReplayFile( void ) return; AsciiString debugFname = fname; - debugFname.removeLastChar(); - debugFname.removeLastChar(); - debugFname.removeLastChar(); + debugFname.truncateBy(3); debugFname.concat("txt"); UnsignedInt fileSize = 0; FILE *fp = fopen(logFileName, "rb"); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/StatsCollector.cpp b/GeneralsMD/Code/GameEngine/Source/Common/StatsCollector.cpp index 0d6e080350..a5099f5bb6 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/StatsCollector.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/StatsCollector.cpp @@ -317,10 +317,7 @@ void StatsCollector::createFileName( void ) const char *fname = name.reverseFind('\\'); if (fname) name = fname+1; - name.removeLastChar(); // p - name.removeLastChar(); // a - name.removeLastChar(); // m - name.removeLastChar(); // . + name.truncateBy(4); // ".map" m_statsFileName.clear(); #if defined(RTS_DEBUG) if (TheGlobalData->m_saveStats) diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp index 0f608da490..fbfa347390 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp @@ -408,8 +408,7 @@ static void findHighFileNumber( AsciiString filename, void *userData ) // strip off the extension at the end of the filename AsciiString nameOnly = filename; - for( size_t count = 0; count < strlen( SAVE_GAME_EXTENSION ); count++ ) - nameOnly.removeLastChar(); + nameOnly.truncateBy( strlen( SAVE_GAME_EXTENSION ) ); // convert filename (which is only numbers) to a number Int fileNumber = atoi( nameOnly.str() ); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/UserPreferences.cpp b/GeneralsMD/Code/GameEngine/Source/Common/UserPreferences.cpp index cd1019b1dd..7994f647fd 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/UserPreferences.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/UserPreferences.cpp @@ -899,11 +899,7 @@ Bool LadderPreferences::loadProfile( Int profileID ) continue; p.port = atoi( ptr + 1 ); - Int i=0; - for (; i g_lanPlayerNameLength) - defaultName.removeLastChar(); + defaultName.truncateTo(g_lanPlayerNameLength); + GadgetTextEntrySetText( textEntryPlayerName, defaultName); // Clear the text entry line GadgetTextEntrySetText(textEntryChat, UnicodeString::TheEmptyString); @@ -473,8 +473,7 @@ void LanLobbyMenuInit( WindowLayout *layout, void *userData ) GadgetListBoxReset(listboxPlayers); GadgetListBoxReset(listboxGames); - while (defaultName.getLength() > g_lanPlayerNameLength) - defaultName.removeLastChar(); + defaultName.truncateTo(g_lanPlayerNameLength); TheLAN->RequestSetName(defaultName); TheLAN->RequestLocations(); @@ -857,8 +856,7 @@ WindowMsgHandledType LanLobbyMenuSystem( GameWindow *window, UnsignedInt msg, else txtInput = UnicodeString::TheEmptyString; - while (txtInput.getLength() > g_lanPlayerNameLength) - txtInput.removeLastChar(); + txtInput.truncateTo(g_lanPlayerNameLength); if (!txtInput.isEmpty() && txtInput.getCharAt(txtInput.getLength()-1) == L',') txtInput.removeLastChar(); // we use , for strtok's so we can't allow them in names. :( diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/NetworkDirectConnect.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/NetworkDirectConnect.cpp index 720957a13c..66b9d1462d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/NetworkDirectConnect.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/NetworkDirectConnect.cpp @@ -197,8 +197,7 @@ void HostDirectConnectGame() prefs["UserName"] = UnicodeStringToQuotedPrintable(name); prefs.write(); - while (name.getLength() > g_lanPlayerNameLength) - name.removeLastChar(); + name.truncateTo(g_lanPlayerNameLength); TheLAN->RequestSetName(name); TheLAN->RequestGameCreate(localIPString, TRUE); } @@ -241,8 +240,7 @@ void JoinDirectConnectGame() UpdateRemoteIPList(); PopulateRemoteIPComboBox(); - while (name.getLength() > g_lanPlayerNameLength) - name.removeLastChar(); + name.truncateTo(g_lanPlayerNameLength); TheLAN->RequestSetName(name); TheLAN->RequestGameJoinDirectConnect(ipaddress); @@ -500,8 +498,7 @@ WindowMsgHandledType NetworkDirectConnectSystem( GameWindow *window, UnsignedInt prefs["UserName"] = UnicodeStringToQuotedPrintable(name); prefs.write(); - while (name.getLength() > g_lanPlayerNameLength) - name.removeLastChar(); + name.truncateTo(g_lanPlayerNameLength); TheLAN->RequestSetName(name); buttonPushed = true; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupSaveLoad.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupSaveLoad.cpp index 04703084d5..027a85511b 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupSaveLoad.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/PopupSaveLoad.cpp @@ -469,10 +469,7 @@ static void setEditDescription( GameWindow *editControl ) //Keep the extension out of the descriptive name. if( (defaultDesc.getLength() >= 4) && (defaultDesc.getCharAt(defaultDesc.getLength()-4) == '.') ) { - for( Int stripIndex = 0; stripIndex < 4; stripIndex++ ) - { - defaultDesc.removeLastChar(); - } + defaultDesc.truncateBy(4); } } // end else diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/ReplayMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/ReplayMenu.cpp index 6e5a5d0396..6b29e95cfd 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/ReplayMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/ReplayMenu.cpp @@ -124,8 +124,7 @@ static Bool readReplayMapInfo(const AsciiString& filename, RecorderClass::Replay static void removeReplayExtension(UnicodeString& replayName) { const Int extensionLength = TheRecorder->getReplayExtention().getLength(); - for (Int k=0; k < extensionLength; ++k) - replayName.removeLastChar(); + replayName.truncateBy(extensionLength); } //------------------------------------------------------------------------------------------------- diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLBuddyOverlay.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLBuddyOverlay.cpp index 4e29d14fe5..1adba463f9 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLBuddyOverlay.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLBuddyOverlay.cpp @@ -550,10 +550,8 @@ void HandleBuddyResponses( void ) } // end if UnicodeString snippet = message.m_message; - while (snippet.getLength() > 11) - { - snippet.removeLastChar(); - } + snippet.truncateTo(11); + UnicodeString s; s.format(TheGameText->fetch("Buddy:MessageNotification"), nick.str(), snippet.str()); lastNotificationWasStatus = FALSE; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp index cb1d566db2..0e129bcd9f 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp @@ -1467,18 +1467,17 @@ WindowMsgHandledType WOLLoginMenuSystem( GameWindow *window, UnsignedInt msg, UnicodeString uniLine; uniLine = UnicodeString(MultiByteToWideCharSingleLine(asciiLine.str()).c_str()); int len = uniLine.getLength(); - for (int index = len-1; index >= 0; index--) + int index = len - 1; + while (index >= 0 && iswspace(uniLine.getCharAt(index))) { - if (iswspace(uniLine.getCharAt(index))) - { - uniLine.removeLastChar(); - } - else - { - break; - } + --index; } - //uniLine.trim(); + + if (index < len - 1) + { + uniLine.truncateTo(index + 1); + } + DEBUG_LOG(("adding TOS line: [%ls]\n", uniLine.str())); GadgetListBoxAddEntryText(listboxTOS, uniLine, tosColor, -1); } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MapUtil.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/MapUtil.cpp index 386aab3cc4..71b4a33a36 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MapUtil.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/MapUtil.cpp @@ -574,8 +574,7 @@ Bool MapCache::loadUserMaps() { AsciiString endingStr; AsciiString fname = s+1; - for (size_t i=0; iinitMapStringFile(stringFileName); md.m_displayName = TheGameText->fetch(munkee); @@ -1146,10 +1144,7 @@ Image *getMapPreviewImage( AsciiString mapName ) AsciiString name; AsciiString tempName; AsciiString filename; - tgaName.removeLastChar(); // p - tgaName.removeLastChar(); // a - tgaName.removeLastChar(); // m - tgaName.removeLastChar(); // . + tgaName.truncateBy(4); // ".map" name = tgaName;//.reverseFind('\\') + 1; filename = tgaName.reverseFind('\\') + 1; //tgaName = name; diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameInfo.cpp b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameInfo.cpp index 89f3397f26..772ed3cf9a 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameInfo.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameInfo.cpp @@ -517,9 +517,7 @@ void GameInfo::setMap( AsciiString mapName ) { m_mapMask = 1; AsciiString path = mapName; - path.removeLastChar(); - path.removeLastChar(); - path.removeLastChar(); + path.truncateBy(3); path.concat("tga"); DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str())); File *fp = TheFileSystem->openFile(path.str()); diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp index 8759be5564..501b6cb1fe 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp @@ -87,8 +87,7 @@ static LadderInfo *parseLadder(AsciiString raw) line.nextToken(&tokenHomepage, " "); lad->name = MultiByteToWideCharSingleLine(tokenName.str()).c_str(); - while (lad->name.getLength() > 20) - lad->name.removeLastChar(); // Per Harvard's request, ladder names are limited to 20 chars + lad->name.truncateTo(20); // Per Harvard's request, ladder names are limited to 20 chars lad->address = tokenAddr; lad->port = atoi(tokenPort.str()); lad->homepageURL = tokenHomepage; diff --git a/GeneralsMD/Code/GameEngine/Source/GameNetwork/LANAPI.cpp b/GeneralsMD/Code/GameEngine/Source/GameNetwork/LANAPI.cpp index 60830041de..5fcb6dd3c5 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameNetwork/LANAPI.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameNetwork/LANAPI.cpp @@ -894,8 +894,7 @@ void LANAPI::RequestGameCreate( UnicodeString gameName, Bool isDirectConnect ) else s.concat(gameName); - while (s.getLength() > g_lanGameNameLength) - s.removeLastChar(); + s.truncateTo(g_lanGameNameLength); DEBUG_LOG(("Setting local game name to '%ls'\n", s.str())); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp index 8b714b110a..4f3df86baf 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp @@ -1405,8 +1405,13 @@ BOOL CWorldBuilderDoc::OnOpenDocument(LPCTSTR lpszPathName) // clear out map-specific text TheGameText->reset(); AsciiString s = lpszPathName; - while (s.getLength() && s.getCharAt(s.getLength()-1) != '\\') - s.removeLastChar(); + Int numNonSep = 0; + const Int sLength = s.getLength(); + while (sLength > numNonSep && s.getCharAt(sLength - 1 - numNonSep) != '\\') + { + ++numNonSep; + } + s.truncateBy(numNonSep); s.concat("map.str"); DEBUG_LOG(("Looking for map-specific text in [%s]\n", s.str())); TheGameText->initMapStringFile(s); From a61b34a69dd4b2ec874a8f4231cbcdfb193281ae Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Thu, 10 Jul 2025 23:06:38 +0200 Subject: [PATCH 04/11] Use truncateTo instead of truncateBy for file name --- .../Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp index 4f3df86baf..3f88ea8565 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp @@ -1405,13 +1405,11 @@ BOOL CWorldBuilderDoc::OnOpenDocument(LPCTSTR lpszPathName) // clear out map-specific text TheGameText->reset(); AsciiString s = lpszPathName; - Int numNonSep = 0; - const Int sLength = s.getLength(); - while (sLength > numNonSep && s.getCharAt(sLength - 1 - numNonSep) != '\\') + const char* lastSep = s.reverseFind('\\'); + if (lastSep != NULL) { - ++numNonSep; + s.truncateTo(lastSep - s.str() + 1); } - s.truncateBy(numNonSep); s.concat("map.str"); DEBUG_LOG(("Looking for map-specific text in [%s]\n", s.str())); TheGameText->initMapStringFile(s); From d10b002e96a2fbd676d1dd6050709f339eba1fa6 Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Thu, 10 Jul 2025 23:07:30 +0200 Subject: [PATCH 05/11] Use known size for ascii chars. --- Core/GameEngine/Source/Common/ReplaySimulation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/GameEngine/Source/Common/ReplaySimulation.cpp b/Core/GameEngine/Source/Common/ReplaySimulation.cpp index b3b444e808..bade41e93e 100644 --- a/Core/GameEngine/Source/Common/ReplaySimulation.cpp +++ b/Core/GameEngine/Source/Common/ReplaySimulation.cpp @@ -224,7 +224,7 @@ std::vector ReplaySimulation::resolveFilenameWildcards(const std::v if (lastSep != NULL) { // include one extra char so the separator itself gets included - int lenToLastSep = lastSep - dir2.str() + sizeof(char); + int lenToLastSep = lastSep - dir2.str() + 1; dir2.truncateTo(lenToLastSep); wildcard.set(wildcard.str() + lenToLastSep); } From f5fc609fdcb5af18ff5be8acab0be6b876a13d54 Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Sat, 12 Jul 2025 21:13:04 +0200 Subject: [PATCH 06/11] Add trimEnd methods and use Int for parameters. --- .../GameEngine/Include/Common/AsciiString.h | 14 +++- .../GameEngine/Include/Common/UnicodeString.h | 14 +++- .../Include/GameClient/DisplayString.h | 4 +- .../Source/Common/System/AsciiString.cpp | 70 ++++++++++++++----- .../Source/Common/System/UnicodeString.cpp | 70 ++++++++++++++----- .../Source/GameClient/DisplayString.cpp | 4 +- 6 files changed, 134 insertions(+), 42 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h b/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h index c115c15a77..bcb8474821 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h @@ -228,6 +228,16 @@ class AsciiString */ void trim( void ); + /** + Remove trailing whitespace from the string. + */ + void trimEnd(void); + + /** + Remove all consecutive occurances of c from the end of the string. + */ + void trimEnd(const char c); + /** Make the string lowercase */ @@ -244,14 +254,14 @@ class AsciiString Remove the final charCount characters in the string. If the string is empty, do nothing. */ - void truncateBy(const UnsignedInt charCount); + void truncateBy(const Int charCount); /** Truncate the string to a length of maxLength characters, not including null termination, by removing from the end. If the string is empty or shorter than maxLength, do nothing. */ - void truncateTo(const UnsignedInt maxLength); + void truncateTo(const Int maxLength); /** Analogous to sprintf() -- this formats a string according to the diff --git a/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h b/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h index 1ba504e17e..af5be37be6 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h @@ -228,6 +228,16 @@ class UnicodeString */ void trim( void ); + /** + Remove trailing whitespace from the string. + */ + void trimEnd(void); + + /** + Remove all consecutive occurances of c from the end of the string. + */ + void trimEnd(const WideChar c); + /** Remove the final character in the string. If the string is empty, do nothing. (This is a rather dorky method, but used a lot in @@ -239,14 +249,14 @@ class UnicodeString Remove the final charCount characters in the string. If the string is empty, do nothing. */ - void truncateBy(const UnsignedInt charCount); + void truncateBy(const Int charCount); /** Truncate the string to a length of maxLength characters, not including null termination, by removing from the end. If the string is empty or shorter than maxLength, do nothing. */ - void truncateTo(const UnsignedInt maxLength); + void truncateTo(const Int maxLength); /** Analogous to sprintf() -- this formats a string according to the diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/DisplayString.h b/GeneralsMD/Code/GameEngine/Include/GameClient/DisplayString.h index 039a9f1e9c..97e0c0c17f 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/DisplayString.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/DisplayString.h @@ -100,8 +100,8 @@ class DisplayString : public MemoryPoolObject virtual void setClipRegion( IRegion2D *region ); ///< clip text in this region virtual void removeLastChar( void ); ///< remove the last character - virtual void truncateBy(const UnsignedInt charCount); ///< remove the last charCount characters - virtual void truncateTo(const UnsignedInt maxLength); ///< remove characters, if needed, until the string is maxLength long excluding null terminator + virtual void truncateBy(const Int charCount); ///< remove the last charCount characters + virtual void truncateTo(const Int maxLength); ///< remove characters, if needed, until the string is maxLength long excluding null terminator virtual void appendChar( WideChar c ); ///< append character to end diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp index c61a065b09..333be15d4a 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/AsciiString.cpp @@ -289,20 +289,52 @@ void AsciiString::trim() set(c); } - if (m_data) // another check, because the previous set() could erase m_data + trimEnd(); + } + validate(); +} + +// ----------------------------------------------------- +void AsciiString::trimEnd() +{ + validate(); + + if (m_data) + { + // Clip trailing white space from the string. + const int len = strlen(peek()); + int index = len; + while (index > 0 && isspace(getCharAt(index - 1))) { - // Clip trailing white space from the string. - int len = strlen(peek()); - int index = len - 1; - while (index >= 0 && isspace(getCharAt(index))) - { - --index; - } + --index; + } - if (index < len - 1) - { - truncateTo(index + 1); - } + if (index < len) + { + truncateTo(index); + } + } + validate(); +} + +// ----------------------------------------------------- +void AsciiString::trimEnd(const char c) +{ + validate(); + + if (m_data) + { + // Clip trailing consecutive occurances of c from the string. + const int len = strlen(peek()); + int index = len; + while (index > 0 && getCharAt(index - 1) == c) + { + --index; + } + + if (index < len) + { + truncateTo(index); } } validate(); @@ -335,16 +367,20 @@ void AsciiString::removeLastChar() } // ----------------------------------------------------- -void AsciiString::truncateBy(const UnsignedInt charCount) +void AsciiString::truncateBy(const Int charCount) { validate(); if (m_data && charCount > 0) { - size_t len = strlen(peek()); + const size_t len = strlen(peek()); if (len > 0) { ensureUniqueBufferOfSize(len+1, true, NULL, NULL); - size_t count = min(charCount, len); + size_t count = charCount; + if (charCount > len) + { + count = len; + } peek()[len - count] = 0; } } @@ -352,12 +388,12 @@ void AsciiString::truncateBy(const UnsignedInt charCount) } // ----------------------------------------------------- -void AsciiString::truncateTo(const UnsignedInt maxLength) +void AsciiString::truncateTo(const Int maxLength) { validate(); if (m_data) { - size_t len = strlen(peek()); + const size_t len = strlen(peek()); if (len > maxLength) { ensureUniqueBufferOfSize(len + 1, true, NULL, NULL); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp b/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp index 34ad1c9eaa..c35a48d4a0 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/System/UnicodeString.cpp @@ -241,20 +241,52 @@ void UnicodeString::trim() set(c); } - if (m_data) // another check, because the previous set() could erase m_data + trimEnd(); + } + validate(); +} + +// ----------------------------------------------------- +void UnicodeString::trimEnd() +{ + validate(); + + if (m_data) + { + // Clip trailing white space from the string. + const int len = wcslen(peek()); + int index = len; + while (index > 0 && iswspace(getCharAt(index - 1))) { - // Clip trailing white space from the string. - int len = wcslen(peek()); - int index = len - 1; - while (index >= 0 && iswspace(getCharAt(index))) - { - --index; - } + --index; + } - if (index < len - 1) - { - truncateTo(index + 1); - } + if (index < len) + { + truncateTo(index); + } + } + validate(); +} + +// ----------------------------------------------------- +void UnicodeString::trimEnd(const WideChar c) +{ + validate(); + + if (m_data) + { + // Clip trailing consecutive occurances of c from the string. + const int len = wcslen(peek()); + int index = len; + while (index > 0 && getCharAt(index - 1) == c) + { + --index; + } + + if (index < len) + { + truncateTo(index); } } validate(); @@ -267,16 +299,20 @@ void UnicodeString::removeLastChar() } // ----------------------------------------------------- -void UnicodeString::truncateBy(const UnsignedInt charCount) +void UnicodeString::truncateBy(const Int charCount) { validate(); if (m_data && charCount > 0) { - size_t len = wcslen(peek()); + const size_t len = wcslen(peek()); if (len > 0) { ensureUniqueBufferOfSize(len+1, true, NULL, NULL); - size_t count = min(charCount, len); + size_t count = charCount; + if (charCount > len) + { + count = len; + } peek()[len - count] = 0; } } @@ -284,12 +320,12 @@ void UnicodeString::truncateBy(const UnsignedInt charCount) } // ----------------------------------------------------- -void UnicodeString::truncateTo(const UnsignedInt maxLength) +void UnicodeString::truncateTo(const Int maxLength) { validate(); if (m_data) { - size_t len = wcslen(peek()); + const size_t len = wcslen(peek()); if (len > maxLength) { ensureUniqueBufferOfSize(len + 1, true, NULL, NULL); diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/DisplayString.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/DisplayString.cpp index e99ae39b1f..758611df2d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/DisplayString.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/DisplayString.cpp @@ -136,7 +136,7 @@ void DisplayString::removeLastChar( void ) // DisplayString::truncateBy ================================================== /** Remove the last charCount characters from the string text */ //============================================================================= -void DisplayString::truncateBy( const UnsignedInt charCount ) +void DisplayString::truncateBy( const Int charCount ) { m_textString.truncateBy(charCount); @@ -149,7 +149,7 @@ void DisplayString::truncateBy( const UnsignedInt charCount ) /** Remove the last characters from the string text so it's at the most * maxLength characters long */ //============================================================================= -void DisplayString::truncateTo( const UnsignedInt maxLength ) +void DisplayString::truncateTo( const Int maxLength ) { m_textString.truncateTo(maxLength); From 38ff97e05d4915fcd34c52eef6b331f379013e48 Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Sat, 12 Jul 2025 21:24:41 +0200 Subject: [PATCH 07/11] Use trimEnd methods. --- .../GUI/GUICallbacks/Menus/WOLLoginMenu.cpp | 25 ++++--------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp index 0e129bcd9f..8ceb97b9ac 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp @@ -1066,17 +1066,13 @@ WindowMsgHandledType WOLLoginMenuSystem( GameWindow *window, UnsignedInt msg, trimmedEmail.trim(); if (!trimmedNick.isEmpty()) { - if (trimmedNick.getCharAt(trimmedNick.getLength()-1) == L'\\') - trimmedNick.removeLastChar(); - if (trimmedNick.getCharAt(trimmedNick.getLength()-1) == L'/') - trimmedNick.removeLastChar(); + trimmedNick.trimEnd(L'\\'); + trimmedNick.trimEnd(L'/'); } if (!trimmedEmail.isEmpty()) { - if (trimmedEmail.getCharAt(trimmedEmail.getLength()-1) == L'\\') - trimmedEmail.removeLastChar(); - if (trimmedEmail.getCharAt(trimmedEmail.getLength()-1) == L'/') - trimmedEmail.removeLastChar(); + trimmedEmail.trimEnd(L'\\'); + trimmedEmail.trimEnd(L'/'); } if (trimmedEmail.getLength() != uEmail.getLength()) { @@ -1466,18 +1462,7 @@ WindowMsgHandledType WOLLoginMenuSystem( GameWindow *window, UnsignedInt msg, { UnicodeString uniLine; uniLine = UnicodeString(MultiByteToWideCharSingleLine(asciiLine.str()).c_str()); - int len = uniLine.getLength(); - int index = len - 1; - while (index >= 0 && iswspace(uniLine.getCharAt(index))) - { - --index; - } - - if (index < len - 1) - { - uniLine.truncateTo(index + 1); - } - + uniLine.trimEnd(); DEBUG_LOG(("adding TOS line: [%ls]\n", uniLine.str())); GadgetListBoxAddEntryText(listboxTOS, uniLine, tosColor, -1); } From c472df85cec2251871693682c6f50aba744fad67 Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Sat, 12 Jul 2025 21:58:09 +0200 Subject: [PATCH 08/11] Backport string functions to Generals. --- .../GameEngine/Include/Common/AsciiString.h | 23 +++++ .../GameEngine/Include/Common/UnicodeString.h | 23 +++++ .../Include/GameClient/DisplayString.h | 3 + .../Source/Common/System/AsciiString.cpp | 94 +++++++++++++++---- .../Source/Common/System/UnicodeString.cpp | 92 ++++++++++++++---- .../Source/GameClient/DisplayString.cpp | 25 +++++ 6 files changed, 225 insertions(+), 35 deletions(-) diff --git a/Generals/Code/GameEngine/Include/Common/AsciiString.h b/Generals/Code/GameEngine/Include/Common/AsciiString.h index bc0ed31b03..fcf50c38bf 100644 --- a/Generals/Code/GameEngine/Include/Common/AsciiString.h +++ b/Generals/Code/GameEngine/Include/Common/AsciiString.h @@ -228,6 +228,16 @@ class AsciiString */ void trim( void ); + /** + Remove trailing whitespace from the string. + */ + void trimEnd(void); + + /** + Remove all consecutive occurances of c from the end of the string. + */ + void trimEnd(const char c); + /** Make the string lowercase */ @@ -240,6 +250,19 @@ class AsciiString */ void removeLastChar(); + /** + Remove the final charCount characters in the string. If the string is empty, + do nothing. + */ + void truncateBy(const Int charCount); + + /** + Truncate the string to a length of maxLength characters, not including null termination, + by removing from the end. + If the string is empty or shorter than maxLength, do nothing. + */ + void truncateTo(const Int maxLength); + /** Analogous to sprintf() -- this formats a string according to the given sprintf-style format string (and the variable argument list) diff --git a/Generals/Code/GameEngine/Include/Common/UnicodeString.h b/Generals/Code/GameEngine/Include/Common/UnicodeString.h index e455f71ba6..9f0779365b 100644 --- a/Generals/Code/GameEngine/Include/Common/UnicodeString.h +++ b/Generals/Code/GameEngine/Include/Common/UnicodeString.h @@ -228,6 +228,16 @@ class UnicodeString */ void trim( void ); + /** + Remove trailing whitespace from the string. + */ + void trimEnd(void); + + /** + Remove all consecutive occurances of c from the end of the string. + */ + void trimEnd(const WideChar c); + /** Remove the final character in the string. If the string is empty, do nothing. (This is a rather dorky method, but used a lot in @@ -235,6 +245,19 @@ class UnicodeString */ void removeLastChar(); + /** + Remove the final charCount characters in the string. If the string is empty, + do nothing. + */ + void truncateBy(const Int charCount); + + /** + Truncate the string to a length of maxLength characters, not including null termination, + by removing from the end. + If the string is empty or shorter than maxLength, do nothing. + */ + void truncateTo(const Int maxLength); + /** Analogous to sprintf() -- this formats a string according to the given sprintf-style format string (and the variable argument list) diff --git a/Generals/Code/GameEngine/Include/GameClient/DisplayString.h b/Generals/Code/GameEngine/Include/GameClient/DisplayString.h index 642157e058..fe30c09316 100644 --- a/Generals/Code/GameEngine/Include/GameClient/DisplayString.h +++ b/Generals/Code/GameEngine/Include/GameClient/DisplayString.h @@ -100,6 +100,9 @@ class DisplayString : public MemoryPoolObject virtual void setClipRegion( IRegion2D *region ); ///< clip text in this region virtual void removeLastChar( void ); ///< remove the last character + virtual void truncateBy(const Int charCount); ///< remove the last charCount characters + virtual void truncateTo(const Int maxLength); ///< remove characters, if needed, until the string is maxLength long excluding null terminator + virtual void appendChar( WideChar c ); ///< append character to end DisplayString *next( void ); ///< return next string diff --git a/Generals/Code/GameEngine/Source/Common/System/AsciiString.cpp b/Generals/Code/GameEngine/Source/Common/System/AsciiString.cpp index 6f639e18ef..42f50b2852 100644 --- a/Generals/Code/GameEngine/Source/Common/System/AsciiString.cpp +++ b/Generals/Code/GameEngine/Source/Common/System/AsciiString.cpp @@ -289,21 +289,52 @@ void AsciiString::trim() set(c); } - if (m_data) // another check, because the previous set() could erase m_data + trimEnd(); + } + validate(); +} + +// ----------------------------------------------------- +void AsciiString::trimEnd() +{ + validate(); + + if (m_data) + { + // Clip trailing white space from the string. + const int len = strlen(peek()); + int index = len; + while (index > 0 && isspace(getCharAt(index - 1))) { - // Clip trailing white space from the string. - int len = strlen(peek()); - for (int index = len-1; index >= 0; index--) - { - if (isspace(getCharAt(index))) - { - removeLastChar(); - } - else - { - break; - } - } + --index; + } + + if (index < len) + { + truncateTo(index); + } + } + validate(); +} + +// ----------------------------------------------------- +void AsciiString::trimEnd(const char c) +{ + validate(); + + if (m_data) + { + // Clip trailing consecutive occurances of c from the string. + const int len = strlen(peek()); + int index = len; + while (index > 0 && getCharAt(index - 1) == c) + { + --index; + } + + if (index < len) + { + truncateTo(index); } } validate(); @@ -331,15 +362,42 @@ void AsciiString::toLower() // ----------------------------------------------------- void AsciiString::removeLastChar() +{ + truncateBy(1); +} + +// ----------------------------------------------------- +void AsciiString::truncateBy(const Int charCount) { validate(); - if (m_data) + if (m_data && charCount > 0) { - int len = strlen(peek()); + const size_t len = strlen(peek()); if (len > 0) { - ensureUniqueBufferOfSize(len+1, true, NULL, NULL); - peek()[len - 1] = 0; + ensureUniqueBufferOfSize(len + 1, true, NULL, NULL); + size_t count = charCount; + if (charCount > len) + { + count = len; + } + peek()[len - count] = 0; + } + } + validate(); +} + +// ----------------------------------------------------- +void AsciiString::truncateTo(const Int maxLength) +{ + validate(); + if (m_data) + { + const size_t len = strlen(peek()); + if (len > maxLength) + { + ensureUniqueBufferOfSize(len + 1, true, NULL, NULL); + peek()[maxLength] = 0; } } validate(); diff --git a/Generals/Code/GameEngine/Source/Common/System/UnicodeString.cpp b/Generals/Code/GameEngine/Source/Common/System/UnicodeString.cpp index b08523232d..153465d71b 100644 --- a/Generals/Code/GameEngine/Source/Common/System/UnicodeString.cpp +++ b/Generals/Code/GameEngine/Source/Common/System/UnicodeString.cpp @@ -241,37 +241,95 @@ void UnicodeString::trim() set(c); } - if (m_data) // another check, because the previous set() could erase m_data + trimEnd(); + } + validate(); +} + +// ----------------------------------------------------- +void UnicodeString::trimEnd() +{ + validate(); + + if (m_data) + { + // Clip trailing white space from the string. + const int len = wcslen(peek()); + int index = len; + while (index > 0 && iswspace(getCharAt(index - 1))) + { + --index; + } + + if (index < len) + { + truncateTo(index); + } + } + validate(); +} + +// ----------------------------------------------------- +void UnicodeString::trimEnd(const WideChar c) +{ + validate(); + + if (m_data) + { + // Clip trailing consecutive occurances of c from the string. + const int len = wcslen(peek()); + int index = len; + while (index > 0 && getCharAt(index - 1) == c) + { + --index; + } + + if (index < len) { - // Clip trailing white space from the string. - int len = wcslen(peek()); - for (int index = len-1; index >= 0; index--) + truncateTo(index); + } + } + validate(); +} + +// ----------------------------------------------------- +void UnicodeString::removeLastChar() +{ + truncateBy(1); +} + +// ----------------------------------------------------- +void UnicodeString::truncateBy(const Int charCount) +{ + validate(); + if (m_data && charCount > 0) + { + const size_t len = wcslen(peek()); + if (len > 0) + { + ensureUniqueBufferOfSize(len + 1, true, NULL, NULL); + size_t count = charCount; + if (charCount > len) { - if (iswspace(getCharAt(index))) - { - removeLastChar(); - } - else - { - break; - } + count = len; } + peek()[len - count] = 0; } } validate(); } // ----------------------------------------------------- -void UnicodeString::removeLastChar() +void UnicodeString::truncateTo(const Int maxLength) { validate(); if (m_data) { - int len = wcslen(peek()); - if (len > 0) + const size_t len = wcslen(peek()); + if (len > maxLength) { - ensureUniqueBufferOfSize(len+1, true, NULL, NULL); - peek()[len - 1] = 0; + ensureUniqueBufferOfSize(len + 1, true, NULL, NULL); + peek()[maxLength] = 0; } } validate(); diff --git a/Generals/Code/GameEngine/Source/GameClient/DisplayString.cpp b/Generals/Code/GameEngine/Source/GameClient/DisplayString.cpp index dc41dfba13..036d204902 100644 --- a/Generals/Code/GameEngine/Source/GameClient/DisplayString.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/DisplayString.cpp @@ -133,6 +133,31 @@ void DisplayString::removeLastChar( void ) } // end removeLastChar +// DisplayString::truncateBy ================================================== +/** Remove the last charCount characters from the string text */ +//============================================================================= +void DisplayString::truncateBy(const Int charCount) +{ + m_textString.truncateBy(charCount); + + // our text has now changed + notifyTextChanged(); + +} // end truncateBy + +// DisplayString::truncateTo ================================================== +/** Remove the last characters from the string text so it's at the most + * maxLength characters long */ + //============================================================================= +void DisplayString::truncateTo(const Int maxLength) +{ + m_textString.truncateTo(maxLength); + + // our text has now changed + notifyTextChanged(); + +} // end truncateTo + // DisplayString::appendChar ================================================== /** Append character to the end of the string */ //============================================================================= From 103fb4112f2b281a40033cd18db939a4bdd444f1 Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Sat, 12 Jul 2025 22:20:29 +0200 Subject: [PATCH 09/11] Backport to Generals: Use trimEnd, truncateBy and truncateTo instead of removeLastChar. --- .../GameEngine/Source/Common/CommandLine.cpp | 5 +--- .../GameEngine/Source/Common/GameEngine.cpp | 4 +-- .../GameEngine/Source/Common/Recorder.cpp | 4 +-- .../Source/Common/StatsCollector.cpp | 5 +--- .../Common/System/SaveGame/GameState.cpp | 5 ++-- .../Source/Common/UserPreferences.cpp | 11 ++------ .../GUI/GUICallbacks/Menus/LanLobbyMenu.cpp | 10 +++---- .../Menus/NetworkDirectConnect.cpp | 9 +++---- .../GUI/GUICallbacks/Menus/ReplayMenu.cpp | 3 +-- .../GUICallbacks/Menus/WOLBuddyOverlay.cpp | 5 +--- .../GUI/GUICallbacks/Menus/WOLLoginMenu.cpp | 26 ++++--------------- .../GameEngine/Source/GameClient/MapUtil.cpp | 11 +++----- .../Source/GameNetwork/GameInfo.cpp | 4 +-- .../Source/GameNetwork/GameSpy/LadderDefs.cpp | 3 +-- .../GameEngine/Source/GameNetwork/LANAPI.cpp | 3 +-- .../WorldBuilder/src/WorldBuilderDoc.cpp | 7 +++-- 16 files changed, 33 insertions(+), 82 deletions(-) diff --git a/Generals/Code/GameEngine/Source/Common/CommandLine.cpp b/Generals/Code/GameEngine/Source/Common/CommandLine.cpp index 5e95fbfff9..ba058e1e45 100644 --- a/Generals/Code/GameEngine/Source/Common/CommandLine.cpp +++ b/Generals/Code/GameEngine/Source/Common/CommandLine.cpp @@ -95,10 +95,7 @@ static void ConvertShortMapPathToLongMapPath(AsciiString &mapName) DEBUG_CRASH(("Invalid map name %s", mapName.str())); } // remove the .map from the end. - token.removeLastChar(); - token.removeLastChar(); - token.removeLastChar(); - token.removeLastChar(); + token.truncateBy(4); actualpath.concat(token); actualpath.concat('\\'); diff --git a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp index 6407b8d2c6..f82dbdc025 100644 --- a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp @@ -897,9 +897,7 @@ void updateTGAtoDDS() } // replace tga with dds - filenameDDS.removeLastChar(); // a - filenameDDS.removeLastChar(); // g - filenameDDS.removeLastChar(); // t + filenameDDS.truncateBy(3); // "tga" filenameDDS.concat("dds"); Bool needsToBeUpdated = FALSE; diff --git a/Generals/Code/GameEngine/Source/Common/Recorder.cpp b/Generals/Code/GameEngine/Source/Common/Recorder.cpp index ca0b7ca5fd..37297a7356 100644 --- a/Generals/Code/GameEngine/Source/Common/Recorder.cpp +++ b/Generals/Code/GameEngine/Source/Common/Recorder.cpp @@ -297,9 +297,7 @@ void RecorderClass::cleanUpReplayFile( void ) return; AsciiString debugFname = fname; - debugFname.removeLastChar(); - debugFname.removeLastChar(); - debugFname.removeLastChar(); + debugFname.truncateBy(3); debugFname.concat("txt"); UnsignedInt fileSize = 0; FILE *fp = fopen(logFileName, "rb"); diff --git a/Generals/Code/GameEngine/Source/Common/StatsCollector.cpp b/Generals/Code/GameEngine/Source/Common/StatsCollector.cpp index 26ffa4ef19..6df9fe6774 100644 --- a/Generals/Code/GameEngine/Source/Common/StatsCollector.cpp +++ b/Generals/Code/GameEngine/Source/Common/StatsCollector.cpp @@ -317,10 +317,7 @@ void StatsCollector::createFileName( void ) const char *fname = name.reverseFind('\\'); if (fname) name = fname+1; - name.removeLastChar(); // p - name.removeLastChar(); // a - name.removeLastChar(); // m - name.removeLastChar(); // . + name.truncateBy(4); // ".map" m_statsFileName.clear(); #if defined(RTS_DEBUG) if (TheGlobalData->m_saveStats) diff --git a/Generals/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp b/Generals/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp index 8ca2f3c210..fc4facd526 100644 --- a/Generals/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp +++ b/Generals/Code/GameEngine/Source/Common/System/SaveGame/GameState.cpp @@ -408,9 +408,8 @@ static void findHighFileNumber( AsciiString filename, void *userData ) // strip off the extension at the end of the filename AsciiString nameOnly = filename; - for( size_t count = 0; count < strlen( SAVE_GAME_EXTENSION ); count++ ) - nameOnly.removeLastChar(); - + nameOnly.truncateBy( strlen( SAVE_GAME_EXTENSION ) ); + // convert filename (which is only numbers) to a number Int fileNumber = atoi( nameOnly.str() ); diff --git a/Generals/Code/GameEngine/Source/Common/UserPreferences.cpp b/Generals/Code/GameEngine/Source/Common/UserPreferences.cpp index 5c1580eec8..48f4edd93f 100644 --- a/Generals/Code/GameEngine/Source/Common/UserPreferences.cpp +++ b/Generals/Code/GameEngine/Source/Common/UserPreferences.cpp @@ -802,11 +802,7 @@ Bool LadderPreferences::loadProfile( Int profileID ) continue; p.port = atoi( ptr + 1 ); - Int i=0; - for (; i g_lanPlayerNameLength) - defaultName.removeLastChar(); + defaultName.truncateTo(g_lanPlayerNameLength); + GadgetTextEntrySetText( textEntryPlayerName, defaultName); // Clear the text entry line GadgetTextEntrySetText(textEntryChat, UnicodeString::TheEmptyString); @@ -431,8 +431,7 @@ void LanLobbyMenuInit( WindowLayout *layout, void *userData ) GadgetListBoxReset(listboxPlayers); GadgetListBoxReset(listboxGames); - while (defaultName.getLength() > g_lanPlayerNameLength) - defaultName.removeLastChar(); + defaultName.truncateTo(g_lanPlayerNameLength); TheLAN->RequestSetName(defaultName); TheLAN->RequestLocations(); @@ -815,8 +814,7 @@ WindowMsgHandledType LanLobbyMenuSystem( GameWindow *window, UnsignedInt msg, else txtInput = UnicodeString::TheEmptyString; - while (txtInput.getLength() > g_lanPlayerNameLength) - txtInput.removeLastChar(); + txtInput.truncateTo(g_lanPlayerNameLength); if (!txtInput.isEmpty() && txtInput.getCharAt(txtInput.getLength()-1) == L',') txtInput.removeLastChar(); // we use , for strtok's so we can't allow them in names. :( diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/NetworkDirectConnect.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/NetworkDirectConnect.cpp index 899eb8c0bb..f40785fb1f 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/NetworkDirectConnect.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/NetworkDirectConnect.cpp @@ -197,8 +197,7 @@ void HostDirectConnectGame() prefs["UserName"] = UnicodeStringToQuotedPrintable(name); prefs.write(); - while (name.getLength() > g_lanPlayerNameLength) - name.removeLastChar(); + name.truncateTo(g_lanPlayerNameLength); TheLAN->RequestSetName(name); TheLAN->RequestGameCreate(localIPString, TRUE); } @@ -241,8 +240,7 @@ void JoinDirectConnectGame() UpdateRemoteIPList(); PopulateRemoteIPComboBox(); - while (name.getLength() > g_lanPlayerNameLength) - name.removeLastChar(); + name.truncateTo(g_lanPlayerNameLength); TheLAN->RequestSetName(name); TheLAN->RequestGameJoinDirectConnect(ipaddress); @@ -500,8 +498,7 @@ WindowMsgHandledType NetworkDirectConnectSystem( GameWindow *window, UnsignedInt prefs["UserName"] = UnicodeStringToQuotedPrintable(name); prefs.write(); - while (name.getLength() > g_lanPlayerNameLength) - name.removeLastChar(); + name.truncateTo(g_lanPlayerNameLength); TheLAN->RequestSetName(name); buttonPushed = true; diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/ReplayMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/ReplayMenu.cpp index c3ddc3041e..efda7e5c8a 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/ReplayMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/ReplayMenu.cpp @@ -124,8 +124,7 @@ static Bool readReplayMapInfo(const AsciiString& filename, RecorderClass::Replay static void removeReplayExtension(UnicodeString& replayName) { const Int extensionLength = TheRecorder->getReplayExtention().getLength(); - for (Int k=0; k < extensionLength; ++k) - replayName.removeLastChar(); + replayName.truncateBy(extensionLength); } //------------------------------------------------------------------------------------------------- diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLBuddyOverlay.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLBuddyOverlay.cpp index 33cfafb8e8..bc0f0e4b15 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLBuddyOverlay.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLBuddyOverlay.cpp @@ -550,10 +550,7 @@ void HandleBuddyResponses( void ) } // end if UnicodeString snippet = message.m_message; - while (snippet.getLength() > 11) - { - snippet.removeLastChar(); - } + snippet.truncateTo(11); UnicodeString s; s.format(TheGameText->fetch("Buddy:MessageNotification"), nick.str(), snippet.str()); lastNotificationWasStatus = FALSE; diff --git a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp index d7475ae1c9..62e1d845ff 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/WOLLoginMenu.cpp @@ -1066,17 +1066,13 @@ WindowMsgHandledType WOLLoginMenuSystem( GameWindow *window, UnsignedInt msg, trimmedEmail.trim(); if (!trimmedNick.isEmpty()) { - if (trimmedNick.getCharAt(trimmedNick.getLength()-1) == L'\\') - trimmedNick.removeLastChar(); - if (trimmedNick.getCharAt(trimmedNick.getLength()-1) == L'/') - trimmedNick.removeLastChar(); + trimmedNick.trimEnd(L'\\'); + trimmedNick.trimEnd(L'/'); } if (!trimmedEmail.isEmpty()) { - if (trimmedEmail.getCharAt(trimmedEmail.getLength()-1) == L'\\') - trimmedEmail.removeLastChar(); - if (trimmedEmail.getCharAt(trimmedEmail.getLength()-1) == L'/') - trimmedEmail.removeLastChar(); + trimmedEmail.trimEnd(L'\\'); + trimmedEmail.trimEnd(L'/'); } if (trimmedEmail.getLength() != uEmail.getLength()) { @@ -1466,19 +1462,7 @@ WindowMsgHandledType WOLLoginMenuSystem( GameWindow *window, UnsignedInt msg, { UnicodeString uniLine; uniLine = UnicodeString(MultiByteToWideCharSingleLine(asciiLine.str()).c_str()); - int len = uniLine.getLength(); - for (int index = len-1; index >= 0; index--) - { - if (iswspace(uniLine.getCharAt(index))) - { - uniLine.removeLastChar(); - } - else - { - break; - } - } - //uniLine.trim(); + uniLine.trimEnd(); DEBUG_LOG(("adding TOS line: [%ls]\n", uniLine.str())); GadgetListBoxAddEntryText(listboxTOS, uniLine, tosColor, -1); } diff --git a/Generals/Code/GameEngine/Source/GameClient/MapUtil.cpp b/Generals/Code/GameEngine/Source/GameClient/MapUtil.cpp index 681bc1dfe0..b19023d89d 100644 --- a/Generals/Code/GameEngine/Source/GameClient/MapUtil.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/MapUtil.cpp @@ -572,8 +572,7 @@ Bool MapCache::loadUserMaps() { AsciiString endingStr; AsciiString fname = s+1; - for (size_t i=0; iinitMapStringFile(stringFileName); md.m_displayName = TheGameText->fetch(munkee); @@ -1066,10 +1064,7 @@ Image *getMapPreviewImage( AsciiString mapName ) AsciiString name; AsciiString tempName; AsciiString filename; - tgaName.removeLastChar(); // p - tgaName.removeLastChar(); // a - tgaName.removeLastChar(); // m - tgaName.removeLastChar(); // . + tgaName.truncateBy(4); // ".map" name = tgaName;//.reverseFind('\\') + 1; filename = tgaName.reverseFind('\\') + 1; //tgaName = name; diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp index 324fa10e78..8b6b171a38 100644 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp +++ b/Generals/Code/GameEngine/Source/GameNetwork/GameInfo.cpp @@ -512,9 +512,7 @@ void GameInfo::setMap( AsciiString mapName ) { m_mapMask = 1; AsciiString path = mapName; - path.removeLastChar(); - path.removeLastChar(); - path.removeLastChar(); + path.truncateBy(3); path.concat("tga"); DEBUG_LOG(("GameInfo::setMap() - Looking for '%s'\n", path.str())); File *fp = TheFileSystem->openFile(path.str()); diff --git a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp index 650f48b9bf..9e21e8fd95 100644 --- a/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp +++ b/Generals/Code/GameEngine/Source/GameNetwork/GameSpy/LadderDefs.cpp @@ -87,8 +87,7 @@ static LadderInfo *parseLadder(AsciiString raw) line.nextToken(&tokenHomepage, " "); lad->name = MultiByteToWideCharSingleLine(tokenName.str()).c_str(); - while (lad->name.getLength() > 20) - lad->name.removeLastChar(); // Per Harvard's request, ladder names are limited to 20 chars + lad->name.truncateTo(20); // Per Harvard's request, ladder names are limited to 20 chars lad->address = tokenAddr; lad->port = atoi(tokenPort.str()); lad->homepageURL = tokenHomepage; diff --git a/Generals/Code/GameEngine/Source/GameNetwork/LANAPI.cpp b/Generals/Code/GameEngine/Source/GameNetwork/LANAPI.cpp index 1d6214326f..1c95f5f60b 100644 --- a/Generals/Code/GameEngine/Source/GameNetwork/LANAPI.cpp +++ b/Generals/Code/GameEngine/Source/GameNetwork/LANAPI.cpp @@ -894,8 +894,7 @@ void LANAPI::RequestGameCreate( UnicodeString gameName, Bool isDirectConnect ) else s.concat(gameName); - while (s.getLength() > g_lanGameNameLength) - s.removeLastChar(); + s.truncateTo(g_lanGameNameLength); DEBUG_LOG(("Setting local game name to '%ls'\n", s.str())); diff --git a/Generals/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp b/Generals/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp index e3be477347..2045e571d9 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WorldBuilderDoc.cpp @@ -1348,8 +1348,11 @@ BOOL CWorldBuilderDoc::OnOpenDocument(LPCTSTR lpszPathName) // clear out map-specific text TheGameText->reset(); AsciiString s = lpszPathName; - while (s.getLength() && s.getCharAt(s.getLength()-1) != '\\') - s.removeLastChar(); + const char* lastSep = s.reverseFind('\\'); + if (lastSep != NULL) + { + s.truncateTo(lastSep - s.str() + 1); + } s.concat("map.str"); DEBUG_LOG(("Looking for map-specific text in [%s]\n", s.str())); TheGameText->initMapStringFile(s); From b3f335d81aa1ab0407a2c6664adf0fb3f20adeca Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Sun, 13 Jul 2025 19:40:59 +0200 Subject: [PATCH 10/11] Revert ReplaySimulation changes as per review discussions. --- .../Source/Common/ReplaySimulation.cpp | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Core/GameEngine/Source/Common/ReplaySimulation.cpp b/Core/GameEngine/Source/Common/ReplaySimulation.cpp index bade41e93e..76b242a9c7 100644 --- a/Core/GameEngine/Source/Common/ReplaySimulation.cpp +++ b/Core/GameEngine/Source/Common/ReplaySimulation.cpp @@ -215,18 +215,19 @@ std::vector ReplaySimulation::resolveFilenameWildcards(const std::v AsciiString dir1 = TheRecorder->getReplayDir(); AsciiString dir2 = *filename; AsciiString wildcard = *filename; - const char* lastSep = dir2.reverseFind('\\'); - if (lastSep == NULL) { - lastSep = dir2.reverseFind('/'); - } - - if (lastSep != NULL) - { - // include one extra char so the separator itself gets included - int lenToLastSep = lastSep - dir2.str() + 1; - dir2.truncateTo(lenToLastSep); - wildcard.set(wildcard.str() + lenToLastSep); + int len = dir2.getLength(); + while (len) + { + char c = dir2.getCharAt(len - 1); + if (c == '/' || c == '\\') + { + wildcard.set(wildcard.str() + dir2.getLength()); + break; + } + dir2.removeLastChar(); + len--; + } } FilenameList files; From 4569dff68157dab9aba9842c9527bb7bf274b423 Mon Sep 17 00:00:00 2001 From: Slurmlord Date: Mon, 14 Jul 2025 01:17:18 +0200 Subject: [PATCH 11/11] Revert ReplaySimulation to origin/main, remove superfluous newlines in comments. --- Core/GameEngine/Source/Common/ReplaySimulation.cpp | 4 ++-- Generals/Code/GameEngine/Include/Common/AsciiString.h | 3 +-- Generals/Code/GameEngine/Include/Common/UnicodeString.h | 3 +-- GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h | 3 +-- GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h | 3 +-- 5 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Core/GameEngine/Source/Common/ReplaySimulation.cpp b/Core/GameEngine/Source/Common/ReplaySimulation.cpp index 76b242a9c7..354925c8fc 100644 --- a/Core/GameEngine/Source/Common/ReplaySimulation.cpp +++ b/Core/GameEngine/Source/Common/ReplaySimulation.cpp @@ -219,10 +219,10 @@ std::vector ReplaySimulation::resolveFilenameWildcards(const std::v int len = dir2.getLength(); while (len) { - char c = dir2.getCharAt(len - 1); + char c = dir2.getCharAt(len-1); if (c == '/' || c == '\\') { - wildcard.set(wildcard.str() + dir2.getLength()); + wildcard.set(wildcard.str()+dir2.getLength()); break; } dir2.removeLastChar(); diff --git a/Generals/Code/GameEngine/Include/Common/AsciiString.h b/Generals/Code/GameEngine/Include/Common/AsciiString.h index fcf50c38bf..27e474133b 100644 --- a/Generals/Code/GameEngine/Include/Common/AsciiString.h +++ b/Generals/Code/GameEngine/Include/Common/AsciiString.h @@ -258,8 +258,7 @@ class AsciiString /** Truncate the string to a length of maxLength characters, not including null termination, - by removing from the end. - If the string is empty or shorter than maxLength, do nothing. + by removing from the end. If the string is empty or shorter than maxLength, do nothing. */ void truncateTo(const Int maxLength); diff --git a/Generals/Code/GameEngine/Include/Common/UnicodeString.h b/Generals/Code/GameEngine/Include/Common/UnicodeString.h index 9f0779365b..eb27882b55 100644 --- a/Generals/Code/GameEngine/Include/Common/UnicodeString.h +++ b/Generals/Code/GameEngine/Include/Common/UnicodeString.h @@ -253,8 +253,7 @@ class UnicodeString /** Truncate the string to a length of maxLength characters, not including null termination, - by removing from the end. - If the string is empty or shorter than maxLength, do nothing. + by removing from the end. If the string is empty or shorter than maxLength, do nothing. */ void truncateTo(const Int maxLength); diff --git a/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h b/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h index bcb8474821..213f048182 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/AsciiString.h @@ -258,8 +258,7 @@ class AsciiString /** Truncate the string to a length of maxLength characters, not including null termination, - by removing from the end. - If the string is empty or shorter than maxLength, do nothing. + by removing from the end. If the string is empty or shorter than maxLength, do nothing. */ void truncateTo(const Int maxLength); diff --git a/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h b/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h index af5be37be6..b138ab6929 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/UnicodeString.h @@ -253,8 +253,7 @@ class UnicodeString /** Truncate the string to a length of maxLength characters, not including null termination, - by removing from the end. - If the string is empty or shorter than maxLength, do nothing. + by removing from the end. If the string is empty or shorter than maxLength, do nothing. */ void truncateTo(const Int maxLength);