From 42d12a644ed4cb3249ee0b5804f5e6e9ddfe5c6c Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Wed, 5 Jul 2023 21:50:36 +0200 Subject: [PATCH] Fix bug in 'V_StripLastDir' and 'CUtlString::DirName' In some code paths of 'V_StripLastDir', the string length value was never set. The return type of this function has changed to return always return the length of the new string. An additional bug in 'CUtlString::DirName' has been fixed, where the length was only set if the trailing slashed weren't stripped. --- r5dev/public/tier1/strtools.h | 2 +- r5dev/tier1/strtools.cpp | 56 +++++++++++++++++++++-------------- r5dev/tier1/utlstring.cpp | 9 +++--- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/r5dev/public/tier1/strtools.h b/r5dev/public/tier1/strtools.h index 9d7604c3..e1b09264 100644 --- a/r5dev/public/tier1/strtools.h +++ b/r5dev/public/tier1/strtools.h @@ -124,7 +124,7 @@ inline void V_MakeAbsolutePath(char* pOut, size_t outLen, const char* pPath, con } // Remove the final directory from the path -bool V_StripLastDir(char* dirName, size_t maxLen, size_t* newLen); +size_t V_StripLastDir(char* dirName, size_t maxLen); // Returns a pointer to the unqualified file name (no path) of a file name const char* V_UnqualifiedFileName(const char* in); // Given a path and a filename, composes "path\filename", inserting the (OS correct) separator if necessary diff --git a/r5dev/tier1/strtools.cpp b/r5dev/tier1/strtools.cpp index ecb38482..ff6160d2 100644 --- a/r5dev/tier1/strtools.cpp +++ b/r5dev/tier1/strtools.cpp @@ -772,19 +772,22 @@ V_MakeAbsolutePath(char* pOut, size_t outLen, const char* pPath, const char* pSt // Input : *dirName - // maxLen - // *newLen - -// Output : Returns true on success, false on failure. +// Output : Returns the new length of the string //----------------------------------------------------------------------------- -bool V_StripLastDir(char* dirName, size_t maxLen, size_t* newLen) +size_t V_StripLastDir(char* dirName, size_t maxLen) { - if (dirName[0] == 0 || - !V_stricmp(dirName, "./") || - !V_stricmp(dirName, ".\\")) - return false; + Assert(dirName); + + if (dirName[0] == '\0') + return 0; size_t len = V_strlen(dirName); - Assert(len < maxLen); + if (!V_stricmp(dirName, "./") || + !V_stricmp(dirName, ".\\")) + return len; + // skip trailing slash if (PATHSEPARATOR(dirName[len - 1])) { @@ -796,9 +799,10 @@ bool V_StripLastDir(char* dirName, size_t maxLen, size_t* newLen) { if (PATHSEPARATOR(dirName[len - 1])) { - dirName[len] = 0; + dirName[len] = '\0'; V_FixSlashes(dirName, CORRECT_PATH_SEPARATOR); - return true; + + return len; } else if (dirName[len - 1] == ':') { @@ -809,27 +813,33 @@ bool V_StripLastDir(char* dirName, size_t maxLen, size_t* newLen) } // If we hit a drive letter, then we're done. - // Ex: If they passed in c:\, then V_StripLastDir should return "" and false. + // Ex: If they passed in c:\, then V_StripLastDir should + // turn the string into "" and return 0. if (bHitColon) { - dirName[0] = 0; - return false; + dirName[0] = '\0'; + return 0; } - // Allow it to return an empty string and true. This can happen if something like "tf2/" is passed in. - // The correct behavior is to strip off the last directory ("tf2") and return true. - if (len == 0 && !bHitColon) + // Allow it to return an empty string and 0. This can happen if something like "tf2/" is passed in. + // The correct behavior is to strip off the last directory ("tf2") and return the new length. + if (len == 0) { - V_snprintf(dirName, maxLen, ".%c", CORRECT_PATH_SEPARATOR); - return true; + int ret = V_snprintf(dirName, maxLen, ".%c", CORRECT_PATH_SEPARATOR); + + // snprintf failed, turn the string into "" and return 0. + if (ret < 0) + { + Assert(0); + + dirName[0] = '\0'; + return 0; + } + + return ret; } - if (newLen) - { - *newLen = len; - } - - return true; + return len; } //----------------------------------------------------------------------------- diff --git a/r5dev/tier1/utlstring.cpp b/r5dev/tier1/utlstring.cpp index adf4bda5..2a6cf36c 100644 --- a/r5dev/tier1/utlstring.cpp +++ b/r5dev/tier1/utlstring.cpp @@ -430,7 +430,8 @@ void CUtlString::StripTrailingSlash() int64 nLastChar = Length() - 1; char c = m_Storage[ nLastChar ]; - if ( c == '\\' || c == '/' ) + + if ( PATHSEPARATOR( c ) ) { m_Storage[ nLastChar ] = 0; m_Storage.SetLength( m_Storage.Length() - 1 ); @@ -607,14 +608,12 @@ CUtlString CUtlString::UnqualifiedFilename() const CUtlString CUtlString::DirName( bool bStripTrailingSlash ) const { CUtlString ret( this->String() ); - size_t len = 0; + size_t len = V_StripLastDir( (char*)ret.m_Storage.Get(), ret.m_Storage.Length() ); - V_StripLastDir( (char*)ret.m_Storage.Get(), ret.m_Storage.Length(), &len ); + ret.SetLength( len ); if (bStripTrailingSlash) ret.StripTrailingSlash(); - else - ret.SetLength(len); // StripTrailingSlash sets this, but if we skip it then nothing sets it. return ret; }