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};
7990static 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// -------------------------------------------------------------------------------------------------
351360static 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// -------------------------------------------------------------------------------------------------
0 commit comments