Skip to content

Commit 2fb2b35

Browse files
committed
Clean up file paths better
1 parent 11bd281 commit 2fb2b35

File tree

1 file changed

+63
-27
lines changed

1 file changed

+63
-27
lines changed

Client/mods/deathmatch/logic/CPacketHandler.cpp

Lines changed: 63 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ using std::list;
2626

2727
class CCore;
2828

29+
std::wstring utf8_mbstowcs(const std::string& str);
30+
std::string utf8_wcstombs(const std::wstring& wstr);
31+
2932
// TODO: Make this independant of g_pClientGame. Just moved it here to get it out of the
3033
// horribly big CClientGame file.
3134
bool CPacketHandler::ProcessPacket(unsigned char ucPacketID, NetBitStreamInterface& bitStream)
@@ -4937,21 +4940,39 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
49374940
unsigned short usNoClientCacheScriptCount = 0;
49384941

49394942
// Resource Name Size
4940-
unsigned char ucResourceNameSize;
4941-
bitStream.Read(ucResourceNameSize);
4943+
unsigned char ucResourceNameSizeTemp;
4944+
bitStream.Read(ucResourceNameSizeTemp);
49424945

4943-
// ucResourceNameSize > 255 ??
4944-
if (ucResourceNameSize > MAX_RESOURCE_NAME_LENGTH)
4946+
// ucResourceNameSizeTemp > 255 ??
4947+
if (ucResourceNameSizeTemp > MAX_RESOURCE_NAME_LENGTH)
49454948
{
49464949
RaiseFatalError(14);
49474950
return;
49484951
}
49494952

49504953
// 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+
}
49554976

49564977
// Resource ID
49574978
unsigned short usResourceID;
@@ -5012,7 +5033,7 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
50125033
// Resource Chunk Size
50135034
unsigned char ucChunkSize;
50145035
// Resource Chunk Data
5015-
char* szChunkData = NULL;
5036+
char* szChunkData = nullptr;
50165037
// Resource Chunk Sub Type
50175038
unsigned char ucChunkSubType;
50185039
// Resource Chunk checksum
@@ -5048,18 +5069,33 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
50485069
}
50495070
szChunkData[ucChunkSize] = NULL;
50505071

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+
50525087
// make the full file path (c:/path/to/mods/deathmatch/resources/resource/)
50535088
std::string strMetaPathTemp;
50545089
std::string strResPathTemp = pResource->GetResourceDirectoryPath(ACCESS_PUBLIC, strMetaPathTemp);
50555090
std::filesystem::path fsResPath = std::filesystem::path(strResPathTemp).lexically_normal();
50565091
std::string strResPath = fsResPath.string();
50575092
// 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;
50595095
std::filesystem::path fsResFilePath = std::filesystem::path(strResFilePathTemp).lexically_normal();
50605096
std::string strResFilePath = fsResFilePath.string();
50615097
// 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)
50635099
{
50645100
bFatalError = true;
50655101
AddReportLog(2081, SString("Path %s (expected %s)", strResFilePath.c_str(), strResPath.c_str()));
@@ -5068,33 +5104,33 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
50685104
{
50695105
bitStream.Read(ucChunkSubType);
50705106
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));
50725108
bitStream.Read(dChunkDataSize);
50735109

5074-
uint uiDownloadSize = (uint)dChunkDataSize;
5110+
uint uiDownloadSize = static_cast<uint>(dChunkDataSize);
50755111
uiTotalSizeProcessed += uiDownloadSize;
50765112
if (uiTotalSizeProcessed / 1024 / 1024 > 50)
50775113
g_pCore->UpdateDummyProgress(uiTotalSizeProcessed / 1024 / 1024, " MB");
50785114

50795115
// Create the resource downloadable
5080-
CDownloadableResource* pDownloadableResource = NULL;
5116+
CDownloadableResource* pDownloadableResource = nullptr;
50815117
switch (ucChunkSubType)
50825118
{
50835119
case CDownloadableResource::RESOURCE_FILE_TYPE_CLIENT_FILE:
50845120
{
50855121
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,
50875123
uiDownloadSize, chunkChecksum, bDownload);
50885124

50895125
break;
50905126
}
50915127
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);
50945130

50955131
break;
50965132
case CDownloadableResource::RESOURCE_FILE_TYPE_CLIENT_CONFIG:
5097-
pDownloadableResource = pResource->AddConfigFile(szChunkData, uiDownloadSize, chunkChecksum);
5133+
pDownloadableResource = pResource->AddConfigFile(szParsedChunkData, uiDownloadSize, chunkChecksum);
50985134

50995135
break;
51005136
default:
@@ -5105,19 +5141,21 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
51055141
// Does the Client and Server checksum differ?
51065142
if (pDownloadableResource && !pDownloadableResource->DoesClientAndServerChecksumMatch())
51075143
{
5144+
const SString strName = pDownloadableResource->GetName();
5145+
51085146
// Delete the file that already exists
5109-
FileDelete(pDownloadableResource->GetName());
5110-
if (FileExists(pDownloadableResource->GetName()))
5147+
FileDelete(strName);
5148+
if (FileExists(strName))
51115149
{
5112-
SString strMessage("Unable to delete old file %s", *ConformResourcePath(pDownloadableResource->GetName()));
5150+
SString strMessage("Unable to delete old file %s", *ConformResourcePath(strName));
51135151
g_pClientGame->TellServerSomethingImportant(1009, strMessage);
51145152
}
51155153

51165154
// Is it downloadable now?
51175155
if (pDownloadableResource->IsAutoDownload())
51185156
{
51195157
// Make sure the directory exists
5120-
MakeSureDirExists(pDownloadableResource->GetName());
5158+
MakeSureDirExists(strName);
51215159

51225160
// Queue the file to be downloaded
51235161
g_pClientGame->GetResourceFileDownloadManager()->AddPendingFileDownload(pDownloadableResource);
@@ -5134,7 +5172,7 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
51345172
{
51355173
// Delete the chunk data
51365174
delete[] szChunkData;
5137-
szChunkData = NULL;
5175+
szChunkData = nullptr;
51385176
}
51395177

51405178
if (bFatalError)
@@ -5159,14 +5197,12 @@ void CPacketHandler::Packet_ResourceStart(NetBitStreamInterface& bitStream)
51595197
}
51605198
}
51615199

5162-
delete[] szResourceName;
5163-
szResourceName = NULL;
5164-
51655200
g_pCore->UpdateDummyProgress(0);
51665201
totalSizeProcessedResetTimer.Reset();
51675202

51685203
if (bFatalError)
51695204
{
5205+
g_pClientGame->m_pResourceManager->Remove(pResource);
51705206
RaiseFatalError(2081);
51715207
}
51725208
}

0 commit comments

Comments
 (0)