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.
This commit is contained in:
Kawe Mazidjatari 2023-07-05 21:50:36 +02:00
parent 819b3aeb16
commit 42d12a644e
3 changed files with 38 additions and 29 deletions

View File

@ -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

View File

@ -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;
}
//-----------------------------------------------------------------------------

View File

@ -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;
}