diff --git a/Core/Libraries/Source/Lib/Include/Lib/PathUtil.h b/Core/Libraries/Source/Lib/Include/Lib/PathUtil.h index 9de3eab27ae..0a845a06860 100644 --- a/Core/Libraries/Source/Lib/Include/Lib/PathUtil.h +++ b/Core/Libraries/Source/Lib/Include/Lib/PathUtil.h @@ -120,6 +120,22 @@ inline char* getFileName(char* path) return lastSeparator ? lastSeparator + 1 : path; } +inline bool appendPathSeparator(char* path, size_t size) +{ + const size_t len = strlen(path); + if (len == 0 || isPathSeparator(path[len - 1])) + { + return true; + } + if (len + 1 >= size) + { + return false; + } + path[len] = getNativePathSeparator(); + path[len + 1] = '\0'; + return true; +} + inline const char* getExtension(const char* path) { const char* lastDot = strrchr(path, '.'); diff --git a/Core/Libraries/Source/WWVegas/WW3D2/agg_def.cpp b/Core/Libraries/Source/WWVegas/WW3D2/agg_def.cpp index 88aeb6522fa..2b4339d9196 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/agg_def.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/agg_def.cpp @@ -346,9 +346,8 @@ AggregateDefClass::Load_Assets (const char *passet_name) char path[MAX_PATH]; ::GetCurrentDirectory (sizeof (path), path); - // Ensure the path is directory delimited - if (!isPathSeparator(path[::lstrlen(path)-1])) { - ::lstrcat (path, "\\"); + if (!appendPathSeparator (path, ARRAY_SIZE (path))) { + return false; } // Assume the filename is simply the "asset name" + the w3d extension diff --git a/Core/Libraries/Source/WWVegas/WWLib/ffactory.cpp b/Core/Libraries/Source/WWVegas/WWLib/ffactory.cpp index 0c8392a439a..e57c5ecbe15 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/ffactory.cpp +++ b/Core/Libraries/Source/WWVegas/WWLib/ffactory.cpp @@ -147,11 +147,8 @@ void SimpleFileFactoryClass::Prepend_Sub_Directory( const char * sub_directory ) // Ensure sub_directory ends with a slash, and append a semicolon char temp_sub_dir[1024]; strlcpy(temp_sub_dir, sub_directory, ARRAY_SIZE(temp_sub_dir)); - if (!isPathSeparator(temp_sub_dir[sub_len - 1])) { - temp_sub_dir[sub_len] = '\\'; - temp_sub_dir[sub_len + 1] = 0; - sub_len++; - } + appendPathSeparator(temp_sub_dir, ARRAY_SIZE(temp_sub_dir)); + sub_len = strlen(temp_sub_dir); temp_sub_dir[sub_len] = ';'; temp_sub_dir[sub_len + 1] = 0; @@ -182,11 +179,8 @@ void SimpleFileFactoryClass::Append_Sub_Directory( const char * sub_directory ) // Ensure sub_directory ends with a slash char temp_sub_dir[1024]; strlcpy(temp_sub_dir, sub_directory, ARRAY_SIZE(temp_sub_dir)); - if (!isPathSeparator(temp_sub_dir[sub_len - 1])) { - temp_sub_dir[sub_len] = '\\'; - temp_sub_dir[sub_len + 1] = 0; - sub_len++; - } + appendPathSeparator(temp_sub_dir, ARRAY_SIZE(temp_sub_dir)); + sub_len = strlen(temp_sub_dir); // BEGIN SERIALIZATION diff --git a/Core/Tools/Autorun/Wnd_file.cpp b/Core/Tools/Autorun/Wnd_file.cpp index 853cdad3231..d2545878b37 100644 --- a/Core/Tools/Autorun/Wnd_file.cpp +++ b/Core/Tools/Autorun/Wnd_file.cpp @@ -274,8 +274,8 @@ void Delete_Msg_File () //---------------------------------------------------------------------- // strcat( strcpy( DebugFile, ".\\" ), DEBUG_FILE ); GetWindowsDirectory( DebugFile, MAX_PATH ); - if ( !isPathSeparator( DebugFile[ strlen( DebugFile )-1 ] ) ) { - strcat( DebugFile, "\\" ); + if ( !appendPathSeparator( DebugFile, ARRAY_SIZE( DebugFile ) ) ) { + return; } strcat( DebugFile, DEBUG_FILE ); diff --git a/Core/Tools/ImagePacker/Source/WindowProcedures/DirectorySelect.cpp b/Core/Tools/ImagePacker/Source/WindowProcedures/DirectorySelect.cpp index d1e15a5491c..1cd7a638bdd 100644 --- a/Core/Tools/ImagePacker/Source/WindowProcedures/DirectorySelect.cpp +++ b/Core/Tools/ImagePacker/Source/WindowProcedures/DirectorySelect.cpp @@ -126,8 +126,7 @@ BOOL CALLBACK DirectorySelectProc( HWND hWndDialog, UINT message, // set the current directory in the top label GetCurrentDirectory( _MAX_PATH, buffer ); - if( !isPathSeparator( buffer[ strlen( buffer ) - 1 ] ) ) - strlcat(buffer, "\\", ARRAY_SIZE(buffer)); + appendPathSeparator( buffer, ARRAY_SIZE( buffer ) ); SetDlgItemText( hWndDialog, STATIC_CURRENT_DIR, buffer ); // load the drive box @@ -189,7 +188,17 @@ BOOL CALLBACK DirectorySelectProc( HWND hWndDialog, UINT message, // construct directory to add, make sure we have a '\' on the // end cause we assume that in the image file name code // - sprintf( toAdd, "%s%s\\", buffer, text ); + // TheSuperHackers @bugfix bobtista 18/10/2026 Skip folders whose path does not fit instead of overflowing toAdd. + const Int toAddLen = snprintf( toAdd, ARRAY_SIZE( toAdd ), "%s%s\\", buffer, text ); + if( toAddLen < 0 || toAddLen >= (Int)ARRAY_SIZE( toAdd ) ) + { + char message[ _MAX_PATH + 32 ]; + + snprintf( message, ARRAY_SIZE( message ), "Ignoring folder '%s', path is too long.", text ); + MessageBox( nullptr, message, "Folder Path Too Long", + MB_OK | MB_ICONINFORMATION ); + continue; + } // do not add directory if it's already in the listbox if( SendDlgItemMessage( TheImagePacker->getWindowHandle(), @@ -198,7 +207,7 @@ BOOL CALLBACK DirectorySelectProc( HWND hWndDialog, UINT message, { char message[ _MAX_PATH + 32 ]; - sprintf( message, "Ignoring folder '%s', already in list.", toAdd ); + snprintf( message, ARRAY_SIZE( message ), "Ignoring folder '%s', already in list.", toAdd ); MessageBox( nullptr, message, "Folder Already In List", MB_OK | MB_ICONINFORMATION ); continue; @@ -261,8 +270,7 @@ BOOL CALLBACK DirectorySelectProc( HWND hWndDialog, UINT message, // construct new direcotry name and update status text GetCurrentDirectory( _MAX_PATH, buffer ); - if( !isPathSeparator( buffer[ strlen( buffer ) - 1 ] ) ) - strlcat(buffer, "\\", ARRAY_SIZE(buffer)); + appendPathSeparator( buffer, ARRAY_SIZE( buffer ) ); SetDlgItemText( hWndDialog, STATIC_CURRENT_DIR, buffer ); EnableWindow( GetDlgItem( hWndDialog, BUTTON_ADD ), FALSE ); @@ -352,8 +360,7 @@ BOOL CALLBACK DirectorySelectProc( HWND hWndDialog, UINT message, // construct new direcotry name and update status text GetCurrentDirectory( _MAX_PATH, buffer ); - if( !isPathSeparator( buffer[ strlen( buffer ) - 1 ] ) ) - strlcat(buffer, "\\", ARRAY_SIZE(buffer)); + appendPathSeparator( buffer, ARRAY_SIZE( buffer ) ); SetDlgItemText( hWndDialog, STATIC_CURRENT_DIR, buffer ); EnableWindow( GetDlgItem( hWndDialog, BUTTON_ADD ), FALSE ); diff --git a/Core/Tools/W3DView/Utils.h b/Core/Tools/W3DView/Utils.h index 0f9e4695e08..03a79e60930 100644 --- a/Core/Tools/W3DView/Utils.h +++ b/Core/Tools/W3DView/Utils.h @@ -69,7 +69,7 @@ __inline void Delimit_Path (LPTSTR path) __inline void Delimit_Path (CString &path) { - if (!isPathSeparator (path[::lstrlen (path) - 1])) { + if (::lstrlen (path) > 0 && !isPathSeparator (path[::lstrlen (path) - 1])) { path += CString ("\\"); } } diff --git a/Core/Tools/W3DView/W3DViewDoc.cpp b/Core/Tools/W3DView/W3DViewDoc.cpp index 88358e65285..f9ccdfc192d 100644 --- a/Core/Tools/W3DView/W3DViewDoc.cpp +++ b/Core/Tools/W3DView/W3DViewDoc.cpp @@ -1446,11 +1446,7 @@ CW3DViewDoc::SaveSettings TCHAR szPath[MAX_PATH] = { 0 }; ::GetCurrentDirectory (sizeof (szPath), szPath); - if (!isPathSeparator (szPath[::lstrlen (szPath)-1])) - { - // Ensure the path is directory delimited - strlcat(szPath, "\\", ARRAY_SIZE(szPath)); - } + appendPathSeparator (szPath, ARRAY_SIZE (szPath)); // Prepend the filename with its new path stringCompleteFilename = CString (szPath) + stringCompleteFilename; diff --git a/Generals/Code/Tools/WorldBuilder/src/SaveMap.cpp b/Generals/Code/Tools/WorldBuilder/src/SaveMap.cpp index 0be1f8251b8..3ff040879ed 100644 --- a/Generals/Code/Tools/WorldBuilder/src/SaveMap.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/SaveMap.cpp @@ -129,11 +129,8 @@ void SaveMap::populateMapListbox( Bool systemMaps ) strcpy(dirBuf, ".\\Maps\\"); else snprintf(dirBuf, ARRAY_SIZE(dirBuf), "%sMaps\\", TheGlobalData->getPath_UserData().str()); - int len = strlen(dirBuf); - - if (len > 0 && !isPathSeparator(dirBuf[len - 1])) { - dirBuf[len++] = '\\'; - dirBuf[len] = 0; + if (!appendPathSeparator(dirBuf, ARRAY_SIZE(dirBuf))) { + return; } CListBox *pList = (CListBox *)this->GetDlgItem(IDC_SAVE_LIST); if (pList == nullptr) return; diff --git a/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp b/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp index 543307ca9a1..620a807264e 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp @@ -418,11 +418,8 @@ void WorldHeightMapEdit::loadDirectoryOfImages(const char *pFilePath) char fileBuf[_MAX_PATH]; strlcpy(dirBuf, pFilePath, ARRAY_SIZE(dirBuf)); - int len = strlen(dirBuf); - - if (len > 0 && !isPathSeparator(dirBuf[len - 1])) { - dirBuf[len++] = '\\'; - dirBuf[len] = 0; + if (!appendPathSeparator(dirBuf, ARRAY_SIZE(dirBuf))) { + return; } FilenameList filenameList; diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/SaveMap.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/SaveMap.cpp index 2db1be92d07..a7e266b9703 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/SaveMap.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/SaveMap.cpp @@ -129,11 +129,8 @@ void SaveMap::populateMapListbox( Bool systemMaps ) strcpy(dirBuf, ".\\Maps\\"); else snprintf(dirBuf, ARRAY_SIZE(dirBuf), "%sMaps\\", TheGlobalData->getPath_UserData().str()); - int len = strlen(dirBuf); - - if (len > 0 && !isPathSeparator(dirBuf[len - 1])) { - dirBuf[len++] = '\\'; - dirBuf[len] = 0; + if (!appendPathSeparator(dirBuf, ARRAY_SIZE(dirBuf))) { + return; } CListBox *pList = (CListBox *)this->GetDlgItem(IDC_SAVE_LIST); if (pList == nullptr) return; diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp index 34c466da43e..7ded9e3b92f 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/WHeightMapEdit.cpp @@ -418,11 +418,8 @@ void WorldHeightMapEdit::loadDirectoryOfImages(const char *pFilePath) char fileBuf[_MAX_PATH]; strlcpy(dirBuf, pFilePath, ARRAY_SIZE(dirBuf)); - int len = strlen(dirBuf); - - if (len > 0 && !isPathSeparator(dirBuf[len - 1])) { - dirBuf[len++] = '\\'; - dirBuf[len] = 0; + if (!appendPathSeparator(dirBuf, ARRAY_SIZE(dirBuf))) { + return; } FilenameList filenameList;