@@ -26,6 +26,9 @@ using std::list;
26
26
27
27
class CCore ;
28
28
29
+ std::wstring utf8_mbstowcs (const std::string& str);
30
+ std::string utf8_wcstombs (const std::wstring& wstr);
31
+
29
32
// TODO: Make this independant of g_pClientGame. Just moved it here to get it out of the
30
33
// horribly big CClientGame file.
31
34
bool CPacketHandler::ProcessPacket (unsigned char ucPacketID, NetBitStreamInterface& bitStream)
@@ -4937,21 +4940,39 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
4937
4940
unsigned short usNoClientCacheScriptCount = 0 ;
4938
4941
4939
4942
// Resource Name Size
4940
- unsigned char ucResourceNameSize ;
4941
- bitStream.Read (ucResourceNameSize );
4943
+ unsigned char ucResourceNameSizeTemp ;
4944
+ bitStream.Read (ucResourceNameSizeTemp );
4942
4945
4943
- // ucResourceNameSize > 255 ??
4944
- if (ucResourceNameSize > MAX_RESOURCE_NAME_LENGTH)
4946
+ // ucResourceNameSizeTemp > 255 ??
4947
+ if (ucResourceNameSizeTemp > MAX_RESOURCE_NAME_LENGTH)
4945
4948
{
4946
4949
RaiseFatalError (14 );
4947
4950
return ;
4948
4951
}
4949
4952
4950
4953
// Resource Name
4951
- char * szResourceName = new char [ucResourceNameSize + 1 ];
4952
- bitStream.Read (szResourceName, ucResourceNameSize);
4953
- if (ucResourceNameSize)
4954
- szResourceName[ucResourceNameSize] = NULL ;
4954
+ auto szResourceNameTemp = new char [ucResourceNameSizeTemp + 1 ];
4955
+ bitStream.Read (szResourceNameTemp, ucResourceNameSizeTemp);
4956
+ if (ucResourceNameSizeTemp)
4957
+ szResourceNameTemp[ucResourceNameSizeTemp] = NULL ;
4958
+
4959
+ // Clean resource name (remove Windows unsupported characters from filename)
4960
+ std::string strResourceName = szResourceNameTemp;
4961
+ delete[] szResourceNameTemp;
4962
+ szResourceNameTemp = nullptr ;
4963
+ std::wstring wstrResourceNameTemp = utf8_mbstowcs (strResourceName);
4964
+ constexpr std::array arrRemoveDirChars = {' /' , ' \\ ' , ' :' , ' *' , ' ?' , ' "' , ' <' , ' >' , ' |' };
4965
+ for (auto szChar : arrRemoveDirChars)
4966
+ wstrResourceNameTemp.erase (std::remove (wstrResourceNameTemp.begin (), wstrResourceNameTemp.end (), szChar), wstrResourceNameTemp.end ());
4967
+ strResourceName = utf8_wcstombs (wstrResourceNameTemp);
4968
+ const char * szResourceName = strResourceName.c_str ();
4969
+
4970
+ // Must have at least one character left in the resource name
4971
+ if (strResourceName.length () < 1 )
4972
+ {
4973
+ RaiseFatalError (15 );
4974
+ return ;
4975
+ }
4955
4976
4956
4977
// Resource ID
4957
4978
unsigned short usResourceID;
@@ -5012,7 +5033,7 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
5012
5033
// Resource Chunk Size
5013
5034
unsigned char ucChunkSize;
5014
5035
// Resource Chunk Data
5015
- char * szChunkData = NULL ;
5036
+ char * szChunkData = nullptr ;
5016
5037
// Resource Chunk Sub Type
5017
5038
unsigned char ucChunkSubType;
5018
5039
// Resource Chunk checksum
@@ -5048,18 +5069,33 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
5048
5069
}
5049
5070
szChunkData[ucChunkSize] = NULL ;
5050
5071
5051
- std::string strChunkData = szChunkData;
5072
+ // Clean resource name (remove Windows unsupported characters from filename)
5073
+ std::string strChunkData = szChunkData;
5074
+ std::wstring wstrChunkDataTemp = utf8_mbstowcs (strChunkData);
5075
+ constexpr std::array arrRemoveFileChars = {' :' , ' *' , ' ?' , ' "' , ' <' , ' >' , ' |' };
5076
+ for (auto szChar : arrRemoveFileChars)
5077
+ wstrChunkDataTemp.erase (std::remove (wstrChunkDataTemp.begin (), wstrChunkDataTemp.end (), szChar), wstrChunkDataTemp.end ());
5078
+ strChunkData = utf8_wcstombs (wstrChunkDataTemp);
5079
+ if (strChunkData.empty ())
5080
+ {
5081
+ bFatalError = true ;
5082
+ AddReportLog (2081 , " Empty" );
5083
+ break ;
5084
+ }
5085
+ const char * szParsedChunkData = strChunkData.c_str ();
5086
+
5052
5087
// make the full file path (c:/path/to/mods/deathmatch/resources/resource/)
5053
5088
std::string strMetaPathTemp;
5054
5089
std::string strResPathTemp = pResource->GetResourceDirectoryPath (ACCESS_PUBLIC, strMetaPathTemp);
5055
5090
std::filesystem::path fsResPath = std::filesystem::path (strResPathTemp).lexically_normal ();
5056
5091
std::string strResPath = fsResPath.string ();
5057
5092
// make the full file path (c:/path/to/mods/deathmatch/resources/resource/file.lua)
5058
- std::string strResFilePathTemp = strResPath + static_cast <char >(std::filesystem::path::preferred_separator) + strChunkData;
5093
+ std::string strResFilePathTemp = strResPath + static_cast <char >(std::filesystem::path::preferred_separator);
5094
+ strResFilePathTemp += strChunkData;
5059
5095
std::filesystem::path fsResFilePath = std::filesystem::path (strResFilePathTemp).lexically_normal ();
5060
5096
std::string strResFilePath = fsResFilePath.string ();
5061
5097
// check that full file path contains full resource path
5062
- if (strResFilePath.rfind (strResPath. c_str () , 0 ) != 0 )
5098
+ if (strResFilePath.rfind (strResPath, 0 ) != 0 )
5063
5099
{
5064
5100
bFatalError = true ;
5065
5101
AddReportLog (2081 , SString (" Path %s (expected %s)" , strResFilePath.c_str (), strResPath.c_str ()));
@@ -5068,33 +5104,33 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
5068
5104
{
5069
5105
bitStream.Read (ucChunkSubType);
5070
5106
bitStream.Read (chunkChecksum.ulCRC );
5071
- bitStream.Read (( char *) chunkChecksum.md5 .data , sizeof (chunkChecksum.md5 .data ));
5107
+ bitStream.Read (reinterpret_cast < char *>( chunkChecksum.md5 .data ) , sizeof (chunkChecksum.md5 .data ));
5072
5108
bitStream.Read (dChunkDataSize);
5073
5109
5074
- uint uiDownloadSize = ( uint) dChunkDataSize;
5110
+ uint uiDownloadSize = static_cast < uint>( dChunkDataSize) ;
5075
5111
uiTotalSizeProcessed += uiDownloadSize;
5076
5112
if (uiTotalSizeProcessed / 1024 / 1024 > 50 )
5077
5113
g_pCore->UpdateDummyProgress (uiTotalSizeProcessed / 1024 / 1024 , " MB" );
5078
5114
5079
5115
// Create the resource downloadable
5080
- CDownloadableResource* pDownloadableResource = NULL ;
5116
+ CDownloadableResource* pDownloadableResource = nullptr ;
5081
5117
switch (ucChunkSubType)
5082
5118
{
5083
5119
case CDownloadableResource::RESOURCE_FILE_TYPE_CLIENT_FILE:
5084
5120
{
5085
5121
bool bDownload = bitStream.ReadBit ();
5086
- pDownloadableResource = pResource->AddResourceFile (CDownloadableResource::RESOURCE_FILE_TYPE_CLIENT_FILE, szChunkData ,
5122
+ pDownloadableResource = pResource->AddResourceFile (CDownloadableResource::RESOURCE_FILE_TYPE_CLIENT_FILE, szParsedChunkData ,
5087
5123
uiDownloadSize, chunkChecksum, bDownload);
5088
5124
5089
5125
break ;
5090
5126
}
5091
5127
case CDownloadableResource::RESOURCE_FILE_TYPE_CLIENT_SCRIPT:
5092
- pDownloadableResource = pResource->AddResourceFile (CDownloadableResource::RESOURCE_FILE_TYPE_CLIENT_SCRIPT, szChunkData,
5093
- uiDownloadSize, chunkChecksum, true );
5128
+ pDownloadableResource = pResource->AddResourceFile (CDownloadableResource::RESOURCE_FILE_TYPE_CLIENT_SCRIPT,
5129
+ szParsedChunkData, uiDownloadSize, chunkChecksum, true );
5094
5130
5095
5131
break ;
5096
5132
case CDownloadableResource::RESOURCE_FILE_TYPE_CLIENT_CONFIG:
5097
- pDownloadableResource = pResource->AddConfigFile (szChunkData , uiDownloadSize, chunkChecksum);
5133
+ pDownloadableResource = pResource->AddConfigFile (szParsedChunkData , uiDownloadSize, chunkChecksum);
5098
5134
5099
5135
break ;
5100
5136
default :
@@ -5105,19 +5141,21 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
5105
5141
// Does the Client and Server checksum differ?
5106
5142
if (pDownloadableResource && !pDownloadableResource->DoesClientAndServerChecksumMatch ())
5107
5143
{
5144
+ const SString strName = pDownloadableResource->GetName ();
5145
+
5108
5146
// Delete the file that already exists
5109
- FileDelete (pDownloadableResource-> GetName () );
5110
- if (FileExists (pDownloadableResource-> GetName () ))
5147
+ FileDelete (strName );
5148
+ if (FileExists (strName ))
5111
5149
{
5112
- SString strMessage (" Unable to delete old file %s" , *ConformResourcePath (pDownloadableResource-> GetName () ));
5150
+ SString strMessage (" Unable to delete old file %s" , *ConformResourcePath (strName ));
5113
5151
g_pClientGame->TellServerSomethingImportant (1009 , strMessage);
5114
5152
}
5115
5153
5116
5154
// Is it downloadable now?
5117
5155
if (pDownloadableResource->IsAutoDownload ())
5118
5156
{
5119
5157
// Make sure the directory exists
5120
- MakeSureDirExists (pDownloadableResource-> GetName () );
5158
+ MakeSureDirExists (strName );
5121
5159
5122
5160
// Queue the file to be downloaded
5123
5161
g_pClientGame->GetResourceFileDownloadManager ()->AddPendingFileDownload (pDownloadableResource);
@@ -5134,7 +5172,7 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
5134
5172
{
5135
5173
// Delete the chunk data
5136
5174
delete[] szChunkData;
5137
- szChunkData = NULL ;
5175
+ szChunkData = nullptr ;
5138
5176
}
5139
5177
5140
5178
if (bFatalError)
@@ -5159,14 +5197,12 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
5159
5197
}
5160
5198
}
5161
5199
5162
- delete[] szResourceName;
5163
- szResourceName = NULL ;
5164
-
5165
5200
g_pCore->UpdateDummyProgress (0 );
5166
5201
totalSizeProcessedResetTimer.Reset ();
5167
5202
5168
5203
if (bFatalError)
5169
5204
{
5205
+ g_pClientGame->m_pResourceManager ->Remove (pResource);
5170
5206
RaiseFatalError (2081 );
5171
5207
}
5172
5208
}
0 commit comments