fix.dat parser: fix line numbering and better handle malformed data
- Line numbering was incorrect, because "in >> lat >> lon >> ident;" happily skipped over blank lines without increasing the line number. - Safe stream input handling: first, std::getline() tries to read data, then we check whether that was successful (via the input stream's bool() method, implicitly called in the 'for' loop's exit check), and only if this is the case, we process the data that was read. The main problem with the previous code is that checking the stream's eofbit can't possibly predict whether a _future_ read will be successful---it may fail due to an I/O error, at least. - Currently, the code uses atof() to parse the latitude and longitude fields. This should be fast, though not good at detecting errors in the input; however, this is not worse than the previous code which didn't handle such cases at all. - Correctly deal with input lines containing a number of fields different from 3 (except for the header and the special '99' line): log a warning, ignore the line and continue. This adresses the problem described in <https://sourceforge.net/p/flightgear/mailman/flightgear-devel/thread/87shydeen1.fsf%40frougon.crabdance.com/#msg35034274>. In short, the previous code entered an endless loop trying to process 31.815914 -106.281897 EL PA from recent earth_fix.dat (obtained from <http://gateway.x-plane.com/navaids/LatestNavFix.zip>).
This commit is contained in:
parent
656326e48f
commit
cf9759f78f
1 changed files with 32 additions and 9 deletions
|
@ -25,11 +25,15 @@
|
|||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h> // atof()
|
||||
|
||||
#include <algorithm>
|
||||
#include <string> // std::getline()
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/strutils.hxx> // simgear::strutils::split()
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
|
@ -51,6 +55,8 @@ const unsigned int LINES_IN_FIX_DAT = 119724;
|
|||
void loadFixes(const SGPath& path)
|
||||
{
|
||||
sg_gzifstream in( path );
|
||||
const std::string utf8path = path.utf8Str();
|
||||
|
||||
if ( !in.is_open() ) {
|
||||
throw sg_io_exception("Cannot open file:", path);
|
||||
}
|
||||
|
@ -60,19 +66,36 @@ void loadFixes(const SGPath& path)
|
|||
in >> skipeol;
|
||||
|
||||
NavDataCache* cache = NavDataCache::instance();
|
||||
unsigned int lineNumber = 2;
|
||||
unsigned int lineNumber = 3;
|
||||
|
||||
// read in each remaining line of the file
|
||||
while ( ! in.eof() ) {
|
||||
for (std::string line; std::getline(in, line); lineNumber++) {
|
||||
std::vector<std::string> fields = simgear::strutils::split(line);
|
||||
std::vector<std::string>::size_type nb_fields = fields.size();
|
||||
const std::string endOfData = "99"; // special code in the fix.dat spec
|
||||
double lat, lon;
|
||||
std::string ident;
|
||||
in >> lat >> lon >> ident;
|
||||
if (lat > 95) break;
|
||||
|
||||
cache->insertFix(ident, SGGeod::fromDeg(lon, lat));
|
||||
in >> skipcomment;
|
||||
|
||||
++lineNumber;
|
||||
if (nb_fields == 0) { // blank line
|
||||
continue;
|
||||
} else if (nb_fields == 1) {
|
||||
if (fields[0] == endOfData)
|
||||
break;
|
||||
else {
|
||||
SG_LOG(SG_NAVAID, SG_WARN, utf8path << ": malformed line #" <<
|
||||
lineNumber << ": only one field, but it is not '99'");
|
||||
continue;
|
||||
}
|
||||
} else if (nb_fields != 3) {
|
||||
SG_LOG(SG_NAVAID, SG_WARN, utf8path << ": malformed line #" <<
|
||||
lineNumber << ": expected 3 fields, but got " << fields.size());
|
||||
continue;
|
||||
}
|
||||
|
||||
lat = atof(fields[0].c_str());
|
||||
lon = atof(fields[1].c_str());
|
||||
|
||||
cache->insertFix(fields[2], SGGeod::fromDeg(lon, lat));
|
||||
|
||||
if ((lineNumber % 100) == 0) {
|
||||
// every 100 lines
|
||||
unsigned int percent = (lineNumber * 100) / LINES_IN_FIX_DAT;
|
||||
|
|
Loading…
Add table
Reference in a new issue