Lat-lon parsing: catch exceptions from std::stod
The standard library throws exceptions in some cases, catch those and return false. Extend the test coverage for some of the problematic cases.
This commit is contained in:
@@ -1136,44 +1136,49 @@ bool matchPropPathToTemplate(const std::string& path, const std::string& templat
|
||||
|
||||
bool parseStringAsLatLonValue(const std::string& s, double& degrees)
|
||||
{
|
||||
string ss = simplify(s);
|
||||
auto spacePos = ss.find_first_of(" *");
|
||||
|
||||
if (spacePos == std::string::npos) {
|
||||
degrees = std::stod(ss);
|
||||
} else {
|
||||
degrees = std::stod(ss.substr(0, spacePos));
|
||||
try {
|
||||
string ss = simplify(s);
|
||||
auto spacePos = ss.find_first_of(" *");
|
||||
|
||||
double minutes = 0.0, seconds = 0.0;
|
||||
|
||||
// check for minutes marker
|
||||
auto quotePos = ss.find('\'');
|
||||
if (quotePos == std::string::npos) {
|
||||
const auto minutesStr = ss.substr(spacePos+1);
|
||||
if (!minutesStr.empty()) {
|
||||
minutes = std::stod(minutesStr);
|
||||
if (spacePos == std::string::npos) {
|
||||
degrees = std::stod(ss);
|
||||
} else {
|
||||
degrees = std::stod(ss.substr(0, spacePos));
|
||||
|
||||
double minutes = 0.0, seconds = 0.0;
|
||||
|
||||
// check for minutes marker
|
||||
auto quotePos = ss.find('\'');
|
||||
if (quotePos == std::string::npos) {
|
||||
const auto minutesStr = ss.substr(spacePos+1);
|
||||
if (!minutesStr.empty()) {
|
||||
minutes = std::stod(minutesStr);
|
||||
}
|
||||
} else {
|
||||
minutes = std::stod(ss.substr(spacePos+1, quotePos - spacePos));
|
||||
const auto secondsStr = ss.substr(quotePos+1);
|
||||
if (!secondsStr.empty()) {
|
||||
seconds = std::stod(secondsStr);
|
||||
}
|
||||
}
|
||||
|
||||
if ((seconds < 0.0) || (minutes < 0.0)) {
|
||||
// don't allow sign information in minutes or seconds
|
||||
return false;
|
||||
}
|
||||
|
||||
double offset = (minutes / 60.0) + (seconds / 3600.0);
|
||||
degrees += (degrees >= 0.0) ? offset : -offset;
|
||||
}
|
||||
} else {
|
||||
minutes = std::stod(ss.substr(spacePos+1, quotePos - spacePos));
|
||||
const auto secondsStr = ss.substr(quotePos+1);
|
||||
if (!secondsStr.empty()) {
|
||||
seconds = std::stod(secondsStr);
|
||||
|
||||
// since we simplified, any trailing N/S/E/W must be the last char
|
||||
const char lastChar = ::toupper(ss.back());
|
||||
if ((lastChar == 'W') || (lastChar == 'S')) {
|
||||
degrees = -degrees;
|
||||
}
|
||||
}
|
||||
|
||||
if ((seconds < 0.0) || (minutes < 0.0)) {
|
||||
// don't allow sign information in minutes or seconds
|
||||
return false;
|
||||
}
|
||||
|
||||
double offset = (minutes / 60.0) + (seconds / 3600.0);
|
||||
degrees += (degrees >= 0.0) ? offset : -offset;
|
||||
}
|
||||
|
||||
// since we simplified, any trailing N/S/E/W must be the last char
|
||||
const char lastChar = ::toupper(ss.back());
|
||||
if ((lastChar == 'W') || (lastChar == 'S')) {
|
||||
degrees = -degrees;
|
||||
} catch (std::exception&) {
|
||||
// std::stdo can throw
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -676,6 +676,13 @@ void test_parseGeod()
|
||||
SG_VERIFY(strutils::parseStringAsGeod("\t40 30'50\"S, 12 34'56\"W ", &a, true));
|
||||
SG_CHECK_EQUAL_EP(a.getLongitudeDeg(), -12.58222222);
|
||||
SG_CHECK_EQUAL_EP(a.getLatitudeDeg(), -40.5138888);
|
||||
|
||||
|
||||
// malformed inputs
|
||||
|
||||
SG_VERIFY(strutils::parseStringAsGeod("12.345,", &a, true) == false);
|
||||
double d;
|
||||
SG_VERIFY(strutils::parseStringAsLatLonValue("", d) == false);
|
||||
}
|
||||
|
||||
void test_formatGeod()
|
||||
|
||||
Reference in New Issue
Block a user