Skip to content

Commit d82dd69

Browse files
committed
feat(utf8): address code review feedback - rename dest_size to destSize, add overlong encoding rejection, use ensureUniqueBufferOfSize directly in translate, revert unrelated changes
1 parent 452a8bf commit d82dd69

18 files changed

Lines changed: 428 additions & 106 deletions

File tree

Core/GameEngine/Include/GameNetwork/GameInfo.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ class GameSlot
100100
void setNATBehavior( FirewallHelperClass::FirewallBehaviorType NATBehavior) { m_NATBehavior = NATBehavior; }
101101
FirewallHelperClass::FirewallBehaviorType getNATBehavior() const { return m_NATBehavior; }
102102

103-
void saveOffOriginalInfo();
103+
void saveOriginalSetup();
104+
Bool hasSavedOriginalSetup() const { return m_hasSavedOriginalSetup; }
104105
Int getOriginalPlayerTemplate() const { return m_origPlayerTemplate; }
105106
Int getOriginalColor() const { return m_origColor; }
106107
Int getOriginalStartPos() const { return m_origStartPos; }
@@ -130,6 +131,7 @@ class GameSlot
130131
Bool m_isAccepted;
131132
Bool m_hasMap;
132133
Bool m_isMuted;
134+
Bool m_hasSavedOriginalSetup;
133135
Int m_color; ///< color, or -1 for random
134136
Int m_startPos; ///< start position, or -1 for random
135137
Int m_playerTemplate; ///< PlayerTemplate

Core/GameEngine/Source/Common/INI/INI.cpp

Lines changed: 127 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@
5959
#include "GameLogic/ScriptEngine.h"
6060
#include "GameLogic/Weapon.h"
6161

62+
#if __cplusplus >= 201611L
63+
#define USE_STD_FROM_CHARS_PARSING 1
64+
#else
65+
#define USE_STD_FROM_CHARS_PARSING 0
66+
#endif
67+
68+
#if USE_STD_FROM_CHARS_PARSING
69+
#include <charconv>
70+
#include <string_view>
71+
#include <type_traits>
72+
#endif
6273

6374
///////////////////////////////////////////////////////////////////////////////////////////////////
6475
// PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
@@ -78,70 +89,68 @@ struct BlockParse
7889
};
7990
static const BlockParse theTypeTable[] =
8091
{
81-
{ "AIData", INI::parseAIDataDefinition },
82-
{ "Animation", INI::parseAnim2DDefinition },
83-
{ "Armor", INI::parseArmorDefinition },
84-
{ "AudioEvent", INI::parseAudioEventDefinition },
85-
{ "AudioSettings", INI::parseAudioSettingsDefinition },
86-
{ "Bridge", INI::parseTerrainBridgeDefinition },
87-
{ "Campaign", INI::parseCampaignDefinition },
88-
{ "ChallengeGenerals", INI::parseChallengeModeDefinition },
89-
{ "CommandButton", INI::parseCommandButtonDefinition },
90-
{ "CommandMap", INI::parseMetaMapDefinition },
91-
{ "CommandSet", INI::parseCommandSetDefinition },
92-
{ "ControlBarScheme", INI::parseControlBarSchemeDefinition },
93-
{ "ControlBarResizer", INI::parseControlBarResizerDefinition },
94-
{ "CrateData", INI::parseCrateTemplateDefinition },
95-
{ "Credits", INI::parseCredits},
96-
{ "WindowTransition", INI::parseWindowTransitions},
97-
{ "DamageFX", INI::parseDamageFXDefinition },
98-
{ "DialogEvent", INI::parseDialogDefinition },
99-
{ "DrawGroupInfo", INI::parseDrawGroupNumberDefinition },
100-
{ "EvaEvent", INI::parseEvaEvent },
101-
{ "FXList", INI::parseFXListDefinition },
102-
{ "GameData", INI::parseGameDataDefinition },
103-
{ "InGameUI", INI::parseInGameUIDefinition },
104-
{ "Locomotor", INI::parseLocomotorTemplateDefinition },
105-
{ "Language", INI::parseLanguageDefinition },
106-
{ "MapCache", INI::parseMapCacheDefinition },
107-
{ "MapData", INI::parseMapDataDefinition },
108-
{ "MappedImage", INI::parseMappedImageDefinition },
109-
{ "MiscAudio", INI::parseMiscAudio},
110-
{ "Mouse", INI::parseMouseDefinition },
111-
{ "MouseCursor", INI::parseMouseCursorDefinition },
112-
{ "MultiplayerColor", INI::parseMultiplayerColorDefinition },
113-
{ "MultiplayerStartingMoneyChoice", INI::parseMultiplayerStartingMoneyChoiceDefinition },
114-
{ "OnlineChatColors", INI::parseOnlineChatColorDefinition },
115-
{ "MultiplayerSettings",INI::parseMultiplayerSettingsDefinition },
116-
{ "MusicTrack", INI::parseMusicTrackDefinition },
117-
{ "Object", INI::parseObjectDefinition },
118-
{ "ObjectCreationList", INI::parseObjectCreationListDefinition },
119-
{ "ObjectReskin", INI::parseObjectReskinDefinition },
120-
{ "ParticleSystem", INI::parseParticleSystemDefinition },
121-
{ "PlayerTemplate", INI::parsePlayerTemplateDefinition },
122-
{ "Road", INI::parseTerrainRoadDefinition },
123-
{ "Science", INI::parseScienceDefinition },
124-
{ "Rank", INI::parseRankDefinition },
125-
{ "SpecialPower", INI::parseSpecialPowerDefinition },
126-
{ "ShellMenuScheme", INI::parseShellMenuSchemeDefinition },
127-
{ "Terrain", INI::parseTerrainDefinition },
128-
{ "Upgrade", INI::parseUpgradeDefinition },
129-
{ "Video", INI::parseVideoDefinition },
130-
{ "WaterSet", INI::parseWaterSettingDefinition },
131-
{ "WaterTransparency", INI::parseWaterTransparencyDefinition},
132-
{ "Weather", INI::parseWeatherDefinition},
133-
{ "Weapon", INI::parseWeaponTemplateDefinition },
134-
{ "WebpageURL", INI::parseWebpageURLDefinition },
135-
{ "HeaderTemplate", INI::parseHeaderTemplateDefinition },
136-
{ "StaticGameLOD", INI::parseStaticGameLODDefinition },
137-
{ "DynamicGameLOD", INI::parseDynamicGameLODDefinition },
138-
{ "LODPreset", INI::parseLODPreset },
139-
{ "BenchProfile", INI::parseBenchProfile },
140-
{ "ReallyLowMHz", parseReallyLowMHz },
141-
{ "ScriptAction", ScriptEngine::parseScriptAction },
142-
{ "ScriptCondition", ScriptEngine::parseScriptCondition },
143-
144-
{ nullptr, nullptr },
92+
{ "AIData", INI::parseAIDataDefinition },
93+
{ "Animation", INI::parseAnim2DDefinition },
94+
{ "Armor", INI::parseArmorDefinition },
95+
{ "AudioEvent", INI::parseAudioEventDefinition },
96+
{ "AudioSettings", INI::parseAudioSettingsDefinition },
97+
{ "BenchProfile", INI::parseBenchProfile },
98+
{ "Bridge", INI::parseTerrainBridgeDefinition },
99+
{ "Campaign", INI::parseCampaignDefinition },
100+
{ "ChallengeGenerals", INI::parseChallengeModeDefinition },
101+
{ "CommandButton", INI::parseCommandButtonDefinition },
102+
{ "CommandMap", INI::parseMetaMapDefinition },
103+
{ "CommandSet", INI::parseCommandSetDefinition },
104+
{ "ControlBarResizer", INI::parseControlBarResizerDefinition },
105+
{ "ControlBarScheme", INI::parseControlBarSchemeDefinition },
106+
{ "CrateData", INI::parseCrateTemplateDefinition },
107+
{ "Credits", INI::parseCredits },
108+
{ "DamageFX", INI::parseDamageFXDefinition },
109+
{ "DialogEvent", INI::parseDialogDefinition },
110+
{ "DrawGroupInfo", INI::parseDrawGroupNumberDefinition },
111+
{ "DynamicGameLOD", INI::parseDynamicGameLODDefinition },
112+
{ "EvaEvent", INI::parseEvaEvent },
113+
{ "FXList", INI::parseFXListDefinition },
114+
{ "GameData", INI::parseGameDataDefinition },
115+
{ "HeaderTemplate", INI::parseHeaderTemplateDefinition },
116+
{ "InGameUI", INI::parseInGameUIDefinition },
117+
{ "LODPreset", INI::parseLODPreset },
118+
{ "Language", INI::parseLanguageDefinition },
119+
{ "Locomotor", INI::parseLocomotorTemplateDefinition },
120+
{ "MapCache", INI::parseMapCacheDefinition },
121+
{ "MapData", INI::parseMapDataDefinition },
122+
{ "MappedImage", INI::parseMappedImageDefinition },
123+
{ "MiscAudio", INI::parseMiscAudio },
124+
{ "Mouse", INI::parseMouseDefinition },
125+
{ "MouseCursor", INI::parseMouseCursorDefinition },
126+
{ "MultiplayerColor", INI::parseMultiplayerColorDefinition },
127+
{ "MultiplayerSettings", INI::parseMultiplayerSettingsDefinition },
128+
{ "MultiplayerStartingMoneyChoice", INI::parseMultiplayerStartingMoneyChoiceDefinition },
129+
{ "MusicTrack", INI::parseMusicTrackDefinition },
130+
{ "Object", INI::parseObjectDefinition },
131+
{ "ObjectCreationList", INI::parseObjectCreationListDefinition },
132+
{ "ObjectReskin", INI::parseObjectReskinDefinition },
133+
{ "OnlineChatColors", INI::parseOnlineChatColorDefinition },
134+
{ "ParticleSystem", INI::parseParticleSystemDefinition },
135+
{ "PlayerTemplate", INI::parsePlayerTemplateDefinition },
136+
{ "Rank", INI::parseRankDefinition },
137+
{ "ReallyLowMHz", parseReallyLowMHz },
138+
{ "Road", INI::parseTerrainRoadDefinition },
139+
{ "Science", INI::parseScienceDefinition },
140+
{ "ScriptAction", ScriptEngine::parseScriptAction },
141+
{ "ScriptCondition", ScriptEngine::parseScriptCondition },
142+
{ "ShellMenuScheme", INI::parseShellMenuSchemeDefinition },
143+
{ "SpecialPower", INI::parseSpecialPowerDefinition },
144+
{ "StaticGameLOD", INI::parseStaticGameLODDefinition },
145+
{ "Terrain", INI::parseTerrainDefinition },
146+
{ "Upgrade", INI::parseUpgradeDefinition },
147+
{ "Video", INI::parseVideoDefinition },
148+
{ "WaterSet", INI::parseWaterSettingDefinition },
149+
{ "WaterTransparency", INI::parseWaterTransparencyDefinition },
150+
{ "Weapon", INI::parseWeaponTemplateDefinition },
151+
{ "Weather", INI::parseWeatherDefinition },
152+
{ "WebpageURL", INI::parseWebpageURLDefinition },
153+
{ "WindowTransition", INI::parseWindowTransitions },
145154
};
146155

147156

@@ -350,13 +359,14 @@ void INI::unPrepFile()
350359
//-------------------------------------------------------------------------------------------------
351360
static INIBlockParse findBlockParse(const char* token)
352361
{
353-
for (const BlockParse* parse = theTypeTable; parse->token; ++parse)
362+
for (size_t i = 0; i < ARRAY_SIZE(theTypeTable); ++i)
354363
{
355-
if (strcmp( parse->token, token ) == 0)
364+
if (strcmp(theTypeTable[i].token, token) == 0)
356365
{
357-
return parse->parse;
366+
return theTypeTable[i].parse;
358367
}
359368
}
369+
360370
return nullptr;
361371
}
362372

@@ -1625,40 +1635,86 @@ void INI::initFromINIMulti( void *what, const MultiIniFieldParse& parseTableList
16251635
return TheScienceStore->friend_lookupScience( token );
16261636
}
16271637

1638+
#if USE_STD_FROM_CHARS_PARSING
1639+
1640+
template <typename Type>
1641+
Type scanType(std::string_view token)
1642+
{
1643+
// TheSuperHackers @info std::from_chars cannot parse "-1" as uint32 so the result needs to be int64 for integers.
1644+
std::conditional_t<std::is_integral_v<Type>, Int64, Real> result{};
1645+
const auto [ptr, ec] = std::from_chars(token.data(), token.data() + token.size(), result);
1646+
1647+
if (ec != std::errc{})
1648+
{
1649+
throw INI_INVALID_DATA;
1650+
}
1651+
1652+
return static_cast<Type>(result);
1653+
}
1654+
1655+
#endif
1656+
16281657
//-------------------------------------------------------------------------------------------------
16291658
/*static*/ Int INI::scanInt(const char* token)
16301659
{
1660+
#if USE_STD_FROM_CHARS_PARSING == 1
1661+
return scanType<Int>(token);
1662+
#else
16311663
Int value;
16321664
if (sscanf( token, "%d", &value ) != 1)
16331665
throw INI_INVALID_DATA;
1666+
1667+
#if USE_STD_FROM_CHARS_PARSING == -1
1668+
if (value != scanType<Int>(token))
1669+
throw INI_INVALID_DATA;
1670+
#endif
1671+
16341672
return value;
1673+
#endif
16351674
}
16361675

16371676
//-------------------------------------------------------------------------------------------------
16381677
/*static*/ UnsignedInt INI::scanUnsignedInt(const char* token)
16391678
{
1679+
#if USE_STD_FROM_CHARS_PARSING == 1
1680+
return scanType<UnsignedInt>(token);
1681+
#else
16401682
UnsignedInt value;
16411683
if (sscanf( token, "%u", &value ) != 1) // unsigned int is %u, not %d
16421684
throw INI_INVALID_DATA;
1685+
1686+
#if USE_STD_FROM_CHARS_PARSING == -1
1687+
if (value != scanType<UnsignedInt>(token))
1688+
throw INI_INVALID_DATA;
1689+
#endif
1690+
16431691
return value;
1692+
#endif
16441693
}
16451694

16461695
//-------------------------------------------------------------------------------------------------
16471696
/*static*/ Real INI::scanReal(const char* token)
16481697
{
1698+
#if USE_STD_FROM_CHARS_PARSING == 1
1699+
return scanType<Real>(token);
1700+
#else
16491701
Real value;
16501702
if (sscanf( token, "%f", &value ) != 1)
16511703
throw INI_INVALID_DATA;
1704+
1705+
#if USE_STD_FROM_CHARS_PARSING == -1
1706+
if (value != scanType<Real>(token))
1707+
throw INI_INVALID_DATA;
1708+
#endif
1709+
16521710
return value;
1711+
#endif
16531712
}
16541713

16551714
//-------------------------------------------------------------------------------------------------
16561715
/*static*/ Real INI::scanPercentToReal(const char* token)
16571716
{
1658-
Real value;
1659-
if (sscanf( token, "%f", &value ) != 1)
1660-
throw INI_INVALID_DATA;
1661-
return value / 100.0f;
1717+
return scanReal(token) / 100.0f;
16621718
}
16631719

16641720
//-------------------------------------------------------------------------------------------------

Core/GameEngine/Source/Common/System/AsciiString.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,16 @@ void AsciiString::translate(const UnicodeString& stringSrc)
274274
{
275275
validate();
276276
// TheSuperHackers @fix bobtista 02/04/2026 Implement UTF-8 conversion replacing 7-bit ASCII only implementation
277-
clear();
278277
const WideChar* src = stringSrc.str();
279278
size_t srcLen = wcslen(src);
280279
size_t size = Get_Utf8_Size(src, srcLen);
281280
if (size == 0)
281+
{
282+
clear();
282283
return;
283-
char* buf = getBufferForRead((Int)size);
284+
}
285+
ensureUniqueBufferOfSize((Int)size + 1, false, nullptr, nullptr);
286+
char* buf = peek();
284287
if (!Unicode_To_Utf8(buf, src, srcLen, size))
285288
clear();
286289
else

Core/GameEngine/Source/Common/System/UnicodeString.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,16 @@ void UnicodeString::translate(const AsciiString& stringSrc)
223223
{
224224
validate();
225225
// TheSuperHackers @fix bobtista 02/04/2026 Implement UTF-8 conversion replacing 7-bit ASCII only implementation
226-
clear();
227226
const char* src = stringSrc.str();
228227
size_t srcLen = strlen(src);
229228
size_t size = Get_Unicode_Size(src, srcLen);
230229
if (size == 0)
230+
{
231+
clear();
231232
return;
232-
WideChar* buf = getBufferForRead((Int)size);
233+
}
234+
ensureUniqueBufferOfSize((Int)size + 1, false, nullptr, nullptr);
235+
WideChar* buf = peek();
233236
if (!Utf8_To_Unicode(buf, src, srcLen, size))
234237
clear();
235238
else

0 commit comments

Comments
 (0)