@@ -878,24 +878,59 @@ void ApplyCache(const std::string& key, T& result)
878878 try
879879 {
880880 if (std::is_same<T, double >::value)
881- result = stod (entry.value );
881+ {
882+ double out = 0.0 ;
883+
884+ if (!ParseDouble (entry.value , &out))
885+ {
886+ throw std::invalid_argument (" Argument is not parseable as a double." );
887+ }
888+
889+ // Have to do the copy here and below, because otherwise the compiler complains about putting &result directly
890+ // above, since this is a template.
891+ result = out;
892+ }
882893 else if (std::is_same<T, int64_t >::value)
883- result = atoi64 (entry.value );
894+ {
895+ int64_t out = 0 ;
896+
897+ if (!ParseInt64 (entry.value , &out))
898+ {
899+ throw std::invalid_argument (" Argument is not parseable as an int64_t." );
900+ }
901+
902+ result = out;
903+ }
884904 else if (std::is_same<T, unsigned int >::value)
885- // Throw away (zero out) negative integer
886- // This approach limits the range to the non-negative signed int, but that is good enough.
887- result = (unsigned int )std::max (0 , stoi (entry.value ));
905+ {
906+ unsigned int out = 0 ;
907+
908+ if (!ParseUInt (entry.value , &out))
909+ {
910+ throw std::invalid_argument (" Argument is not parseable as an unsigned int." );
911+ }
912+
913+ result = out;
914+ }
888915 else if (std::is_same<T, bool >::value)
889916 {
890917 if (entry.value == " false" || entry.value == " 0" )
918+ {
891919 result = boost::lexical_cast<T>(false );
920+ }
892921 else if (entry.value == " true" || entry.value == " 1" )
922+ {
893923 result = boost::lexical_cast<T>(true );
924+ }
894925 else
926+ {
895927 throw std::invalid_argument (" Argument not true or false" );
928+ }
896929 }
897930 else
931+ {
898932 result = boost::lexical_cast<T>(entry.value );
933+ }
899934 }
900935 catch (const std::exception&)
901936 {
@@ -1879,20 +1914,18 @@ bool ProcessProjectTeamFile(const std::string& project, const fs::path& file, co
18791914
18801915 int64_t nTeamID = 0 ;
18811916
1882- try
1883- {
1884- nTeamID = atoi64 (sTeamID );
1885- }
1886- catch (const std::exception&)
1917+ if (!ParseInt64 (sTeamID , &nTeamID))
18871918 {
1888- _log (logattribute::ERR, " ProccessProjectTeamFile " , tfm::format (" Ignoring bad team id for team %s." , sTeamName ));
1919+ _log (logattribute::ERR, __func__ , tfm::format (" Ignoring bad team id for team %s." , sTeamName ));
18891920 continue ;
18901921 }
18911922
18921923 mTeamIdsForProject [sTeamName ] = nTeamID;
18931924 }
18941925 else
1926+ {
18951927 builder.append (line);
1928+ }
18961929 }
18971930
18981931 if (mTeamIdsForProject .empty ())
@@ -2284,13 +2317,9 @@ bool ProcessProjectRacFileByCPID(const std::string& project, const fs::path& fil
22842317 const std::string& sTeamID = ExtractXML (data, " <teamid>" , " </teamid>" );
22852318 int64_t nTeamID = 0 ;
22862319
2287- try
2320+ if (! ParseInt64 ( sTeamID , &nTeamID))
22882321 {
2289- nTeamID = atoi64 (sTeamID );
2290- }
2291- catch (const std::exception&)
2292- {
2293- _log (logattribute::ERR, " ProcessProjectRacFileByCPID" , " Bad team id in user stats file data." );
2322+ _log (logattribute::ERR, __func__, " Bad team id in user stats file data." );
22942323 continue ;
22952324 }
22962325
@@ -2550,13 +2579,9 @@ bool LoadTeamIDList(const fs::path& file)
25502579 sProject = iter;
25512580 else
25522581 {
2553- try
2554- {
2555- nTeamID = atoi64 (iter);
2556- }
2557- catch (std::exception&)
2582+ if (!ParseInt64 (iter, &nTeamID))
25582583 {
2559- _log (logattribute::ERR, " LoadTeamIDList " , " Ignoring invalid team id found in team id file." );
2584+ _log (logattribute::ERR, __func__ , " Ignoring invalid team id found in team id file." );
25602585 continue ;
25612586 }
25622587
@@ -2898,7 +2923,16 @@ bool LoadScraperFileManifest(const fs::path& file)
28982923 nhash.SetHex (vline[0 ].c_str ());
28992924 LoadEntry.hash = nhash;
29002925
2901- LoadEntry.current = std::stoi (vline[1 ]);
2926+ // We will use the ParseUInt from strencodings to avoid the locale specific stoi.
2927+ unsigned int parsed_current = 0 ;
2928+
2929+ if (!ParseUInt (vline[1 ], &parsed_current))
2930+ {
2931+ _log (logattribute::ERR, __func__, " The \" current\" field not parsed correctly for a manifest entry. Skipping." );
2932+ continue ;
2933+ }
2934+
2935+ LoadEntry.current = parsed_current;
29022936
29032937 std::istringstream sstimestamp (vline[2 ]);
29042938 sstimestamp >> ntimestamp;
@@ -2913,7 +2947,17 @@ bool LoadScraperFileManifest(const fs::path& file)
29132947 {
29142948 // Intended for explorer mode, where files not to be included in CScraperManifest
29152949 // are to be maintained, such as team and host files.
2916- LoadEntry.excludefromcsmanifest = std::stoi (vline[5 ]);
2950+ unsigned int parsed_exclude = 0 ;
2951+
2952+ if (!ParseUInt (vline[5 ], &parsed_exclude))
2953+ {
2954+ // This shouldn't happen given the conditional above, but to be thorough...
2955+ _log (logattribute::ERR, __func__, " The \" excludefromcsmanifest\" field not parsed correctly for a manifest "
2956+ " entry. Skipping." );
2957+ continue ;
2958+ }
2959+
2960+ LoadEntry.excludefromcsmanifest = parsed_exclude;
29172961 }
29182962 else
29192963 {
@@ -3158,10 +3202,46 @@ bool ProcessProjectStatsFromStreamByCPID(const std::string& project, boostio::fi
31583202 const std::string& sRAC = fields[2 ];
31593203 const std::string& cpid = fields[3 ];
31603204
3161- // Replace blank strings with zeros.
3162- statsentry.statsvalue .dTC = (sTC .empty ()) ? 0.0 : std::stod (sTC );
3163- statsentry.statsvalue .dRAT = (sRAT .empty ()) ? 0.0 : std::stod (sRAT );
3164- statsentry.statsvalue .dRAC = (sRAC .empty ()) ? 0.0 : std::stod (sRAC );
3205+ // Replace blank strings with zeros. Continue to next record with a logged error if there is a parsing failure.
3206+ if (sTC .empty ())
3207+ {
3208+ statsentry.statsvalue .dTC = 0.0 ;
3209+ }
3210+ else
3211+ {
3212+ if (!ParseDouble (sTC , &statsentry.statsvalue .dTC ))
3213+ {
3214+ _log (logattribute::ERR, __func__, " Cannot parse sTC " + sTC + " for cpid " + cpid);
3215+ continue ;
3216+ }
3217+ }
3218+
3219+ if (sRAT .empty ())
3220+ {
3221+ statsentry.statsvalue .dRAT = 0.0 ;
3222+ }
3223+ else
3224+ {
3225+ if (!ParseDouble (sRAT , &statsentry.statsvalue .dRAT ))
3226+ {
3227+ _log (logattribute::ERR, __func__, " Cannot parse sRAT " + sRAT + " for cpid " + cpid);
3228+ continue ;
3229+ }
3230+ }
3231+
3232+ if (sRAC .empty ())
3233+ {
3234+ statsentry.statsvalue .dRAC = 0.0 ;
3235+ }
3236+ else
3237+ {
3238+ if (!ParseDouble (sRAC , &statsentry.statsvalue .dRAC ))
3239+ {
3240+ _log (logattribute::ERR, __func__, " Cannot parse sRAC " + sRAC + " for cpid " + cpid);
3241+ continue ;
3242+ }
3243+ }
3244+
31653245 // At the individual (byCPIDbyProject) level the AvgRAC is the same as the RAC.
31663246 statsentry.statsvalue .dAvgRAC = statsentry.statsvalue .dRAC ;
31673247 // Mag is dealt with on the second pass... so is left at 0.0 on the first pass.
0 commit comments