Handle exceptions in int conversions (#2092)

* RageUtil: Add exception-safe wrappers around std::stoi, stol, stoll

* Replace use of std::stoi with exception-safe StringToInt
This commit is contained in:
Gareth Francis
2021-02-15 12:36:51 -08:00
committed by GitHub
parent c7c54bb013
commit aeb5c7598f
25 changed files with 124 additions and 73 deletions
+3 -3
View File
@@ -402,16 +402,16 @@ void BGAnimationLayer::LoadFromNode( const XNode* pNode )
{
m_Type = TYPE_TILES;
}
else if( std::stoi(type) == 1 )
else if( StringToInt(type) == 1 )
{
m_Type = TYPE_SPRITE;
bStretch = true;
}
else if( std::stoi(type) == 2 )
else if( StringToInt(type) == 2 )
{
m_Type = TYPE_PARTICLES;
}
else if( std::stoi(type) == 3 )
else if( StringToInt(type) == 3 )
{
m_Type = TYPE_TILES;
}
+10 -10
View File
@@ -87,7 +87,7 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou
}
else if( sValueName.EqualsNoCase("LIVES") )
{
out.m_iLives = max( std::stoi(sParams[1]), 0 );
out.m_iLives = max( StringToInt(sParams[1]), 0 );
}
else if( sValueName.EqualsNoCase("GAINSECONDS") )
{
@@ -97,7 +97,7 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou
{
if( sParams.params.size() == 2 )
{
out.m_iCustomMeter[Difficulty_Medium] = max( std::stoi(sParams[1]), 0 ); /* compat */
out.m_iCustomMeter[Difficulty_Medium] = max( StringToInt(sParams[1]), 0 ); /* compat */
}
else if( sParams.params.size() == 3 )
{
@@ -107,7 +107,7 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou
LOG->UserLog( "Course file", sPath, "contains an invalid #METER string: \"%s\"", sParams[1].c_str() );
continue;
}
out.m_iCustomMeter[cd] = max( std::stoi(sParams[2]), 0 );
out.m_iCustomMeter[cd] = max( StringToInt(sParams[2]), 0 );
}
}
@@ -168,7 +168,7 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou
// most played
if( sParams[1].Left(strlen("BEST")) == "BEST" )
{
int iChooseIndex = std::stoi( sParams[1].Right(sParams[1].size()-strlen("BEST")) ) - 1;
int iChooseIndex = StringToInt( sParams[1].Right(sParams[1].size()-strlen("BEST")) ) - 1;
if( iChooseIndex > iNumSongs )
{
// looking up a song that doesn't exist.
@@ -185,7 +185,7 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou
// least played
else if( sParams[1].Left(strlen("WORST")) == "WORST" )
{
int iChooseIndex = std::stoi( sParams[1].Right(sParams[1].size()-strlen("WORST")) ) - 1;
int iChooseIndex = StringToInt( sParams[1].Right(sParams[1].size()-strlen("WORST")) ) - 1;
if( iChooseIndex > iNumSongs )
{
// looking up a song that doesn't exist.
@@ -202,14 +202,14 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou
// best grades
else if( sParams[1].Left(strlen("GRADEBEST")) == "GRADEBEST" )
{
new_entry.iChooseIndex = std::stoi( sParams[1].Right(sParams[1].size()-strlen("GRADEBEST")) ) - 1;
new_entry.iChooseIndex = StringToInt( sParams[1].Right(sParams[1].size()-strlen("GRADEBEST")) ) - 1;
CLAMP( new_entry.iChooseIndex, 0, 500 );
new_entry.songSort = SongSort_TopGrades;
}
// worst grades
else if( sParams[1].Left(strlen("GRADEWORST")) == "GRADEWORST" )
{
new_entry.iChooseIndex = std::stoi( sParams[1].Right(sParams[1].size()-strlen("GRADEWORST")) ) - 1;
new_entry.iChooseIndex = StringToInt( sParams[1].Right(sParams[1].size()-strlen("GRADEWORST")) ) - 1;
CLAMP( new_entry.iChooseIndex, 0, 500 );
new_entry.songSort = SongSort_LowestGrades;
}
@@ -308,7 +308,7 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou
else if( !sMod.CompareNoCase("nodifficult") )
new_entry.bNoDifficult = true;
else if( sMod.length() > 5 && !sMod.Left(5).CompareNoCase("award") )
new_entry.iGainLives = std::stoi( sMod.substr(5) );
new_entry.iGainLives = StringToInt( sMod.substr(5) );
else
continue;
mods.erase( mods.begin() + j );
@@ -330,8 +330,8 @@ bool CourseLoaderCRS::LoadFromMsd( const RString &sPath, const MsdFile &msd, Cou
else if( bFromCache && !sValueName.EqualsNoCase("RADAR") )
{
StepsType st = (StepsType) std::stoi(sParams[1]);
CourseDifficulty cd = (CourseDifficulty) std::stoi( sParams[2] );
StepsType st = (StepsType) StringToInt(sParams[1]);
CourseDifficulty cd = (CourseDifficulty) StringToInt( sParams[2] );
RadarValues rv;
rv.FromString( sParams[3] );
+3 -3
View File
@@ -267,14 +267,14 @@ void FileTransfer::HTTPUpdate()
m_sResponseName = "Malformed response.";
return;
}
m_iResponseCode = std::stoi(m_sBUFFER.substr(i+1,j-i));
m_iResponseCode = StringToInt(m_sBUFFER.substr(i+1,j-i));
m_sResponseName = m_sBUFFER.substr( j+1, k-j );
i = m_sBUFFER.find("Content-Length:");
j = m_sBUFFER.find("\n", i+1 );
if( i != string::npos )
m_iTotalBytes = std::stoi(m_sBUFFER.substr(i+16,j-i));
m_iTotalBytes = StringToInt(m_sBUFFER.substr(i+16,j-i));
else
m_iTotalBytes = -1; // We don't know, so go until disconnect
@@ -345,7 +345,7 @@ bool FileTransfer::ParseHTTPAddress( const RString &URL, RString &sProto, RStrin
sServer = asMatches[1];
if( asMatches[3] != "" )
{
iPort = std::stoi(asMatches[3]);
iPort = StringToInt(asMatches[3]);
if( iPort == 0 )
return false;
}
+2 -2
View File
@@ -488,7 +488,7 @@ void Font::LoadFontPageSettings( FontPageSettings &cfg, IniFile &ini, const RStr
// If val is an integer, it's a width, eg. "10=27".
if( IsAnInt(sName) )
{
cfg.m_mapGlyphWidths[std::stoi(sName)] = pValue->GetValue<int>();
cfg.m_mapGlyphWidths[StringToInt(sName)] = pValue->GetValue<int>();
continue;
}
@@ -603,7 +603,7 @@ void Font::LoadFontPageSettings( FontPageSettings &cfg, IniFile &ini, const RStr
row_str.c_str());
continue;
}
const int row = std::stoi(row_str);
const int row = StringToInt(row_str);
const int first_frame = row * num_frames_wide;
if(row >= num_frames_high)
+2 -2
View File
@@ -377,12 +377,12 @@ void GameCommand::LoadOne( const Command& cmd )
else if( sName == "weight" )
{
m_iWeightPounds = std::stoi( sValue );
m_iWeightPounds = StringToInt( sValue );
}
else if( sName == "goalcalories" )
{
m_iGoalCalories = std::stoi( sValue );
m_iGoalCalories = StringToInt( sValue );
}
else if( sName == "goaltype" )
+1 -1
View File
@@ -246,7 +246,7 @@ void GameState::ApplyCmdline()
RString sPlayer;
for( int i = 0; GetCommandlineArgument( "player", &sPlayer, i ); ++i )
{
int pn = std::stoi( sPlayer )-1;
int pn = StringToInt( sPlayer )-1;
if( !IsAnInt( sPlayer ) || pn < 0 || pn >= NUM_PLAYERS )
RageException::Throw( "Invalid argument \"--player=%s\".", sPlayer.c_str() );
+2 -2
View File
@@ -310,7 +310,7 @@ RString NoteSkinManager::GetMetric( const RString &sButtonName, const RString &s
int NoteSkinManager::GetMetricI( const RString &sButtonName, const RString &sValueName )
{
return std::stoi( GetMetric(sButtonName,sValueName) );
return StringToInt( GetMetric(sButtonName,sValueName) );
}
float NoteSkinManager::GetMetricF( const RString &sButtonName, const RString &sValueName )
@@ -321,7 +321,7 @@ float NoteSkinManager::GetMetricF( const RString &sButtonName, const RString &sV
bool NoteSkinManager::GetMetricB( const RString &sButtonName, const RString &sValueName )
{
// Could also call GetMetricI here...hmm.
return std::stoi( GetMetric(sButtonName,sValueName) ) != 0;
return StringToInt( GetMetric(sButtonName,sValueName) ) != 0;
}
apActorCommands NoteSkinManager::GetMetricA( const RString &sButtonName, const RString &sValueName )
+3 -3
View File
@@ -483,7 +483,7 @@ struct bmsCommandTree
while (randomStack.size() < currentNode->branchHeight + 1) // if we're on branch level N we need N+1 values.
randomStack.push_back(0);
randomStack[currentNode->branchHeight] = rand() % std::stoi(value) + 1;
randomStack[currentNode->branchHeight] = rand() % StringToInt(value) + 1;
}
else
{
@@ -886,12 +886,12 @@ void BMSChartReader::ReadHeaders()
}
else if( it->first == "#playlevel" )
{
out->SetMeter( std::stoi(it->second) );
out->SetMeter( StringToInt(it->second) );
}
else if( it->first == "#difficulty")
{
// only set the difficulty if the #difficulty tag is between 1 and 6 (beginner~edit)
int diff = std::stoi(it->second)-1; // BMS uses 1 to 6, SM uses 0 to 5
int diff = StringToInt(it->second)-1; // BMS uses 1 to 6, SM uses 0 to 5
if(diff>=0 && diff<NUM_Difficulty) {
out->SetDifficulty( (Difficulty)diff );
}
+3 -3
View File
@@ -430,7 +430,7 @@ static bool LoadFromDWITokens(
if( sNumFeet.empty() )
sNumFeet = "1";
out.SetMeter(std::stoi(sNumFeet));
out.SetMeter(StringToInt(sNumFeet));
out.SetDifficulty( DwiCompatibleStringToDifficulty(sDescription) );
@@ -508,7 +508,7 @@ bool DWILoader::LoadNoteDataFromSimfile( const RString &path, Steps &out )
continue;
if (out.GetDifficulty() != DwiCompatibleStringToDifficulty(params[1]))
continue;
if (out.GetMeter() != std::stoi(params[2]))
if (out.GetMeter() != StringToInt(params[2]))
continue;
RString step1 = params[3];
RString step2 = (iNumParams==5) ? params[4] : RString("");
@@ -626,7 +626,7 @@ bool DWILoader::LoadFromDir( const RString &sPath_, Song &out, set<RString> &Bla
else if( sValueName.EqualsNoCase("GAP") )
// the units of GAP is 1/1000 second
out.m_SongTiming.m_fBeat0OffsetInSeconds = -std::stoi(sParams[1]) / 1000.0f;
out.m_SongTiming.m_fBeat0OffsetInSeconds = -StringToInt(sParams[1]) / 1000.0f;
else if( sValueName.EqualsNoCase("SAMPLESTART") )
out.m_fMusicSampleStartSeconds = ParseBrokenDWITimestamp(sParams[1], sParams[2], sParams[3]);
+3 -3
View File
@@ -130,7 +130,7 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, Song &song, bool
else if( sValueName=="TICKCOUNT" )
{
iTickCount = std::stoi( sParams[1] );
iTickCount = StringToInt( sParams[1] );
if( iTickCount <= 0 )
{
LOG->UserLog( "Song file", sPath, "has an invalid tick count: %d.", iTickCount );
@@ -141,7 +141,7 @@ static bool LoadFromKSFFile( const RString &sPath, Steps &out, Song &song, bool
else if( sValueName=="DIFFICULTY" )
{
out.SetMeter( max(std::stoi(sParams[1]), 1) );
out.SetMeter( max(StringToInt(sParams[1]), 1) );
}
// new cases from Aldo_MX's fork:
else if( sValueName=="PLAYER" )
@@ -515,7 +515,7 @@ static void ProcessTickcounts( const RString & value, int & ticks, TimingData &
/* TICKCOUNT will be used below if there are DM compliant BPM changes
* and stops. It will be called again in LoadFromKSFFile for the
* actual steps. */
ticks = std::stoi( value );
ticks = StringToInt( value );
CLAMP( ticks, 0, ROWS_PER_BEAT );
if( ticks == 0 )
+5 -5
View File
@@ -156,7 +156,7 @@ void SMSetSelectable(SMSongTagInfo& info)
* used 3.9+ features are not excluded here */
else if((*info.params)[1].EqualsNoCase("ES") || (*info.params)[1].EqualsNoCase("OMES"))
{ info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; }
else if(std::stoi((*info.params)[1]) > 0)
else if(StringToInt((*info.params)[1]) > 0)
{ info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; }
else
{ LOG->UserLog("Song file", info.path, "has an unknown #SELECTABLE value, \"%s\"; ignored.", (*info.params)[1].c_str()); }
@@ -337,7 +337,7 @@ void SMLoader::LoadFromTokens(
// have a meter on certain steps. Make the meter 1 in these instances.
sMeter = "1";
}
out.SetMeter( std::stoi(sMeter) );
out.SetMeter( StringToInt(sMeter) );
out.SetSMNoteData( sNoteData );
@@ -786,8 +786,8 @@ void SMLoader::ProcessTimeSignatures( TimingData &out, const RString line, const
}
const float fBeat = RowToBeat( vs2[0], rowsPerBeat );
const int iNumerator = std::stoi( vs2[1] );
const int iDenominator = std::stoi( vs2[2] );
const int iNumerator = StringToInt( vs2[1] );
const int iDenominator = StringToInt( vs2[2] );
if( fBeat < 0 )
{
@@ -879,7 +879,7 @@ void SMLoader::ProcessSpeeds( TimingData &out, const RString line, const int row
const float fDelay = StringToFloat( vs2[2] );
// XXX: ugly...
int iUnit = std::stoi(vs2[3]);
int iUnit = StringToInt(vs2[3]);
SpeedSegment::BaseUnit unit = (iUnit == 0) ?
SpeedSegment::UNIT_BEATS : SpeedSegment::UNIT_SECONDS;
+5 -5
View File
@@ -33,11 +33,11 @@ void SMALoader::ProcessMultipliers( TimingData &out, const int iRowsPerBeat, con
continue;
}
const float fComboBeat = RowToBeat( arrayMultiplierValues[0], iRowsPerBeat );
const int iCombos = std::stoi( arrayMultiplierValues[1] ); // always true.
const int iCombos = StringToInt( arrayMultiplierValues[1] ); // always true.
// hoping I'm right here: SMA files can use 6 values after the row/beat.
const int iMisses = (size == 2 || size == 4 ?
iCombos :
std::stoi(arrayMultiplierValues[2]));
StringToInt(arrayMultiplierValues[2]));
out.AddSegment( ComboSegment(BeatToNoteRow(fComboBeat), iCombos, iMisses) );
}
}
@@ -61,7 +61,7 @@ void SMALoader::ProcessBeatsPerMeasure( TimingData &out, const RString sParam )
continue;
}
const float fBeat = StringToFloat( vs2[0] );
const int iNumerator = std::stoi( vs2[1] );
const int iNumerator = StringToInt( vs2[1] );
if( fBeat < 0 )
{
@@ -296,7 +296,7 @@ bool SMALoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach
vector<RString> arrayBeatChangeValues;
split( arrayBeatChangeExpressions[0], "=", arrayBeatChangeValues );
iRowsPerBeat = std::stoi(arrayBeatChangeValues[1]);
iRowsPerBeat = StringToInt(arrayBeatChangeValues[1]);
}
else
{
@@ -328,7 +328,7 @@ bool SMALoader::LoadFromSimfile( const RString &sPath, Song &out, bool bFromCach
* used 3.9+ features are not excluded here */
else if(sParams[1].EqualsNoCase("ES") || sParams[1].EqualsNoCase("OMES"))
out.m_SelectionDisplay = out.SHOW_ALWAYS;
else if( std::stoi(sParams[1]) > 0 )
else if( StringToInt(sParams[1]) > 0 )
out.m_SelectionDisplay = out.SHOW_ALWAYS;
else
LOG->UserLog("Song file",
+7 -7
View File
@@ -199,7 +199,7 @@ void SetSelectable(SongTagInfo& info)
* used 3.9+ features are not excluded here */
else if((*info.params)[1].EqualsNoCase("ES") || (*info.params)[1].EqualsNoCase("OMES"))
{ info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; }
else if(std::stoi((*info.params)[1]) > 0)
else if(StringToInt((*info.params)[1]) > 0)
{ info.song->m_SelectionDisplay = info.song->SHOW_ALWAYS; }
else
{ LOG->UserLog("Song file", info.path, "has an unknown #SELECTABLE value, \"%s\"; ignored.", (*info.params)[1].c_str()); }
@@ -298,12 +298,12 @@ void SetSongFilename(SongTagInfo& info)
void SetHasMusic(SongTagInfo& info)
{
if(info.from_cache)
{ info.song->m_bHasMusic = std::stoi((*info.params)[1]) != 0; }
{ info.song->m_bHasMusic = StringToInt((*info.params)[1]) != 0; }
}
void SetHasBanner(SongTagInfo& info)
{
if(info.from_cache)
{ info.song->m_bHasBanner = std::stoi((*info.params)[1]) != 0; }
{ info.song->m_bHasBanner = StringToInt((*info.params)[1]) != 0; }
}
// Functions for steps tags go below this line. -Kyz
@@ -350,7 +350,7 @@ void SetDifficulty(StepsTagInfo& info)
}
void SetMeter(StepsTagInfo& info)
{
info.steps->SetMeter(std::stoi((*info.params)[1]));
info.steps->SetMeter(StringToInt((*info.params)[1]));
info.ssc_format= true;
}
void SetRadarValues(StepsTagInfo& info)
@@ -797,8 +797,8 @@ void SSCLoader::ProcessCombos( TimingData &out, const RString line, const int ro
continue;
}
const float fComboBeat = std::stof( arrayComboValues[0] );
const int iCombos = std::stoi( arrayComboValues[1] );
const int iMisses = (size == 2 ? iCombos : std::stoi(arrayComboValues[2]));
const int iCombos = StringToInt( arrayComboValues[1] );
const int iMisses = (size == 2 ? iCombos : StringToInt(arrayComboValues[2]));
out.AddSegment( ComboSegment( BeatToNoteRow(fComboBeat), iCombos, iMisses ) );
}
}
@@ -905,7 +905,7 @@ bool SSCLoader::LoadNoteDataFromSimfile( const RString & cachePath, Steps &out )
{ tryingSteps = false; }
break;
case LNDID_meter:
if(out.GetMeter() != std::stoi(matcher))
if(out.GetMeter() != StringToInt(matcher))
{ tryingSteps = false; }
break;
case LNDID_credit:
+3 -3
View File
@@ -162,7 +162,7 @@ public:
m_Def.m_bOneChoiceForAllPlayers = false;
ROW_INVALID_IF(lCmds.v[0].m_vsArgs.size() != 1, "Row command has invalid args to number of entries.", false);
const int NumCols = std::stoi( lCmds.v[0].m_vsArgs[0] );
const int NumCols = StringToInt( lCmds.v[0].m_vsArgs[0] );
ROW_INVALID_IF(NumCols < 1, "Not enough entries in list.", false);
for( unsigned i=1; i<lCmds.v.size(); i++ )
{
@@ -174,7 +174,7 @@ public:
else if( sName == "selectone" ) m_Def.m_selectType = SELECT_ONE;
else if( sName == "selectnone" ) m_Def.m_selectType = SELECT_NONE;
else if( sName == "showoneinrow" ) m_Def.m_layoutType = LAYOUT_SHOW_ONE_IN_ROW;
else if( sName == "default" ) m_Def.m_iDefault = std::stoi( cmd.GetArg(1).s ) - 1; // match ENTRY_MODE
else if( sName == "default" ) m_Def.m_iDefault = StringToInt( cmd.GetArg(1).s ) - 1; // match ENTRY_MODE
else if( sName == "reloadrowmessages" )
{
for( unsigned a=1; a<cmd.m_vsArgs.size(); a++ )
@@ -186,7 +186,7 @@ public:
for( unsigned a=1; a<cmd.m_vsArgs.size(); a++ )
{
RString sArg = cmd.m_vsArgs[a];
PlayerNumber pn = (PlayerNumber)(std::stoi(sArg)-1);
PlayerNumber pn = (PlayerNumber)(StringToInt(sArg)-1);
ASSERT( pn >= 0 && pn < NUM_PLAYERS );
m_Def.m_vEnabledForPlayers.insert( pn );
}
+1 -1
View File
@@ -607,7 +607,7 @@ bool PlayerOptions::FromOneModString( const RString &sOneMod, RString &sErrorOut
{
// XXX: We know what they want, is there any reason not to handle it?
// Yes. We should be strict in handling the format. -Chris
sErrorOut = ssprintf("Invalid player options \"%s\"; did you mean '*%d'?", s.c_str(), std::stoi(s) );
sErrorOut = ssprintf("Invalid player options \"%s\"; did you mean '*%d'?", s.c_str(), StringToInt(s) );
return false;
}
else
+1 -1
View File
@@ -2523,7 +2523,7 @@ RString Profile::MakeUniqueFileNameNoExtension( RString sDir, RString sFileNameB
continue;
ASSERT( matches.size() == 1 );
iIndex = std::stoi( matches[0] )+1;
iIndex = StringToInt( matches[0] )+1;
break;
}
+2 -2
View File
@@ -27,8 +27,8 @@ static void GetResolutionFromFileName( RString sPath, int &iWidth, int &iHeight
return;
// Check for nonsense values. Some people might not intend the hint. -Kyz
int maybe_width= std::stoi(asMatches[0]);
int maybe_height= std::stoi(asMatches[1]);
int maybe_width= StringToInt(asMatches[0]);
int maybe_height= StringToInt(asMatches[1]);
if(maybe_width <= 0 || maybe_height <= 0)
{
return;
+2 -2
View File
@@ -52,8 +52,8 @@ void RageTexture::GetFrameDimensionsFromFileName( RString sPath, int* piFramesWi
return;
}
// Check for nonsense values. Some people might not intend the hint. -Kyz
int maybe_width= std::stoi(asMatch[0]);
int maybe_height= std::stoi(asMatch[1]);
int maybe_width= StringToInt(asMatch[0]);
int maybe_height= StringToInt(asMatch[1]);
if(maybe_width <= 0 || maybe_height <= 0)
{
*piFramesWide = *piFramesHigh = 1;
+48 -3
View File
@@ -276,8 +276,8 @@ float HHMMSSToSeconds( const RString &sHHMMSS )
arrayBits.insert(arrayBits.begin(), "0" ); // pad missing bits
float fSeconds = 0;
fSeconds += std::stoi( arrayBits[0] ) * 60 * 60;
fSeconds += std::stoi( arrayBits[1] ) * 60;
fSeconds += StringToInt( arrayBits[0] ) * 60 * 60;
fSeconds += StringToInt( arrayBits[1] ) * 60;
fSeconds += StringToFloat( arrayBits[2] );
return fSeconds;
@@ -1900,6 +1900,51 @@ RString FloatToString( const float &num )
return ss.str();
}
int StringToInt( const std::string& str, std::size_t* pos, int base, int exceptVal )
{
try
{
return std::stoi(str, pos, base);
}
catch (const std::invalid_argument & e) {
LOG->Warn( "stoi(%s): %s", str.c_str(), e.what() );
}
catch (const std::out_of_range & e) {
LOG->Warn( "stoi(%s): %s", str.c_str(), e.what() );
}
return exceptVal;
}
long StringToLong( const std::string& str, std::size_t* pos, int base, long exceptVal )
{
try
{
return std::stol(str, pos, base);
}
catch (const std::invalid_argument & e) {
LOG->Warn( "stol(%s): %s", str.c_str(), e.what() );
}
catch (const std::out_of_range & e) {
LOG->Warn( "stol(%s): %s", str.c_str(), e.what() );
}
return exceptVal;
}
long long StringToLLong( const std::string& str, std::size_t* pos, int base, long long exceptVal )
{
try
{
return std::stoll(str, pos, base);
}
catch (const std::invalid_argument & e) {
LOG->Warn( "stoll(%s): %s", str.c_str(), e.what() );
}
catch (const std::out_of_range & e) {
LOG->Warn( "stoll(%s): %s", str.c_str(), e.what() );
}
return exceptVal;
}
const wchar_t INVALID_CHAR = 0xFFFD; /* U+FFFD REPLACEMENT CHARACTER */
wstring RStringToWstring( const RString &s )
@@ -2324,7 +2369,7 @@ namespace StringConversion
if( sValue.size() == 0 )
return false;
out = (std::stoi(sValue) != 0);
out = StringToInt(sValue) != 0;
return true;
}
+6
View File
@@ -418,6 +418,12 @@ inline bool operator>>(const RString& lhs, T& rhs)
return !!(istringstream(lhs) >> rhs);
}
// Exception-safe wrappers around stoi and friends
// Additional argument exceptVal will be returned if the conversion couldn't be performed
int StringToInt( const std::string& str, std::size_t* pos = 0, int base = 10, int exceptVal = 0 );
long StringToLong( const std::string& str, std::size_t* pos = 0, int base = 10, long exceptVal = 0 );
long long StringToLLong( const std::string& str, std::size_t* pos = 0, int base = 10, long long exceptVal = 0 );
RString WStringToRString( const wstring &sString );
RString WcharToUTF8( wchar_t c );
wstring RStringToWstring( const RString &sString );
+4 -4
View File
@@ -3679,7 +3679,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
}
else if( SM == SM_BackFromDifficultyMeterChange )
{
int i = std::stoi( ScreenTextEntry::s_sLastAnswer );
int i = StringToInt( ScreenTextEntry::s_sLastAnswer );
GAMESTATE->m_pCurSteps[PLAYER_1]->SetMeter(i);
SetDirty( true );
}
@@ -3733,7 +3733,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
}
else if ( SM == SM_BackFromTickcountChange && !ScreenTextEntry::s_bCancelledLast )
{
int iTick = std::stoi( ScreenTextEntry::s_sLastAnswer );
int iTick = StringToInt( ScreenTextEntry::s_sLastAnswer );
if ( iTick >= 0 && iTick <= ROWS_PER_BEAT )
GetAppropriateTimingForUpdate().AddSegment( TickcountSegment( GetRow(), iTick) );
@@ -3798,7 +3798,7 @@ void ScreenEdit::HandleScreenMessage( const ScreenMessage SM )
}
else
{
int tmp = std::stoi(ScreenTextEntry::s_sLastAnswer );
int tmp = StringToInt(ScreenTextEntry::s_sLastAnswer );
SpeedSegment::BaseUnit unit = (tmp == 0 ) ?
SpeedSegment::UNIT_BEATS : SpeedSegment::UNIT_SECONDS;
@@ -4571,7 +4571,7 @@ static void ChangeStepCredit( const RString &sNew )
static void ChangeStepMeter( const RString &sNew )
{
int diff = std::stoi(sNew);
int diff = StringToInt(sNew);
GAMESTATE->m_pCurSteps[PLAYER_1]->SetMeter(max(diff, 1));
}
+1 -1
View File
@@ -3234,7 +3234,7 @@ void ScreenGameplay::SaveReplay()
continue;
ASSERT( matches.size() == 1 );
iIndex = std::stoi( matches[0] )+1;
iIndex = StringToInt( matches[0] )+1;
break;
}
+3 -3
View File
@@ -630,14 +630,14 @@ void ScreenPackages::HTTPUpdate()
m_sResponseName = "Malformed response.";
return;
}
m_iResponseCode = std::stoi(m_sBUFFER.substr(i+1,j-i));
m_iResponseCode = StringToInt(m_sBUFFER.substr(i+1,j-i));
m_sResponseName = m_sBUFFER.substr( j+1, k-j );
i = m_sBUFFER.find("Content-Length:");
j = m_sBUFFER.find("\n", i+1 );
if( i != string::npos )
m_iTotalBytes = std::stoi(m_sBUFFER.substr(i+16,j-i));
m_iTotalBytes = StringToInt(m_sBUFFER.substr(i+16,j-i));
else
m_iTotalBytes = -1; //We don't know, so go until disconnect
@@ -704,7 +704,7 @@ bool ScreenPackages::ParseHTTPAddress( const RString &URL, RString &sProto, RStr
sServer = asMatches[1];
if( asMatches[3] != "" )
{
iPort = std::stoi(asMatches[3]);
iPort = StringToInt(asMatches[3]);
if( iPort == 0 )
return false;
}
+2 -2
View File
@@ -50,9 +50,9 @@ void XNode::Free()
}
void XNodeStringValue::GetValue( RString &out ) const { out = m_sValue; }
void XNodeStringValue::GetValue( int &out ) const { out = std::stoi(m_sValue); }
void XNodeStringValue::GetValue( int &out ) const { out = StringToInt(m_sValue); }
void XNodeStringValue::GetValue( float &out ) const { out = StringToFloat(m_sValue); }
void XNodeStringValue::GetValue( bool &out ) const { out = std::stoi(m_sValue) != 0; }
void XNodeStringValue::GetValue( bool &out ) const { out = StringToInt(m_sValue) != 0; }
void XNodeStringValue::GetValue( unsigned &out ) const { out = strtoul(m_sValue,nullptr,0); }
void XNodeStringValue::PushValue( lua_State *L ) const
{
+2 -2
View File
@@ -452,13 +452,13 @@ void actor_template_t::load_frames_from_file(RString const& fname, RString const
RString field_type= attr->first.Left(5);
if(field_type == "Frame")
{
int id= std::stoi(attr->first.Right(attr->first.size()-5));
int id= StringToInt(attr->first.Right(attr->first.size()-5));
make_space_for_frame(id);
attr->second->GetValue(frames[id].frame);
}
else if(field_type == "Delay")
{
int id= std::stoi(attr->first.Right(attr->first.size()-5));
int id= StringToInt(attr->first.Right(attr->first.size()-5));
make_space_for_frame(id);
attr->second->GetValue(frames[id].delay);
}