2000-04-21 18:30:59 +00:00
|
|
|
// fixlist.cxx -- fix list management class
|
|
|
|
//
|
|
|
|
// Written by Curtis Olson, started April 2000.
|
|
|
|
//
|
2004-11-19 22:10:41 +00:00
|
|
|
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
|
2000-04-21 18:30:59 +00:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful, but
|
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
// General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
2006-02-21 01:16:04 +00:00
|
|
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2000-04-21 18:30:59 +00:00
|
|
|
//
|
|
|
|
// $Id$
|
|
|
|
|
|
|
|
|
2001-05-15 22:30:39 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
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>).
2016-04-28 07:58:49 +00:00
|
|
|
#include <stdlib.h> // atof()
|
|
|
|
|
2008-08-22 19:49:03 +00:00
|
|
|
#include <algorithm>
|
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>).
2016-04-28 07:58:49 +00:00
|
|
|
#include <string> // std::getline()
|
2016-04-28 10:22:22 +00:00
|
|
|
#include <errno.h>
|
2008-08-22 19:49:03 +00:00
|
|
|
|
2000-04-21 18:30:59 +00:00
|
|
|
#include <simgear/debug/logstream.hxx>
|
2001-03-25 14:20:12 +00:00
|
|
|
#include <simgear/misc/sgstream.hxx>
|
2008-12-23 14:41:58 +00:00
|
|
|
#include <simgear/misc/sg_path.hxx>
|
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>).
2016-04-28 07:58:49 +00:00
|
|
|
#include <simgear/misc/strutils.hxx> // simgear::strutils::split()
|
2000-09-27 20:16:22 +00:00
|
|
|
#include <simgear/math/sg_geodesy.hxx>
|
2013-10-15 21:16:50 +00:00
|
|
|
#include <simgear/structure/exception.hxx>
|
2000-04-21 18:30:59 +00:00
|
|
|
|
|
|
|
#include "fixlist.hxx"
|
2009-05-14 20:55:09 +00:00
|
|
|
#include <Navaids/fix.hxx>
|
2012-08-27 23:26:36 +00:00
|
|
|
#include <Navaids/NavDataCache.hxx>
|
2008-08-22 11:22:22 +00:00
|
|
|
|
2012-08-27 23:26:36 +00:00
|
|
|
FGFix::FGFix(PositionedID aGuid, const std::string& aIdent, const SGGeod& aPos) :
|
|
|
|
FGPositioned(aGuid, FIX, aIdent, aPos)
|
2008-09-10 08:54:49 +00:00
|
|
|
{
|
2000-04-21 18:30:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-27 23:26:36 +00:00
|
|
|
namespace flightgear
|
|
|
|
{
|
2015-03-19 17:01:38 +00:00
|
|
|
|
|
|
|
const unsigned int LINES_IN_FIX_DAT = 119724;
|
2016-04-28 09:33:59 +00:00
|
|
|
|
|
|
|
FixesLoader::FixesLoader() : _cache(NavDataCache::instance())
|
|
|
|
{ }
|
|
|
|
|
|
|
|
FixesLoader::~FixesLoader()
|
|
|
|
{ }
|
|
|
|
|
|
|
|
// Load fixes from the specified fix.dat (or fix.dat.gz) file
|
|
|
|
void FixesLoader::loadFixes(const SGPath& path)
|
2012-08-27 23:26:36 +00:00
|
|
|
{
|
2016-06-23 13:26:34 +00:00
|
|
|
sg_gzifstream in( path );
|
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>).
2016-04-28 07:58:49 +00:00
|
|
|
const std::string utf8path = path.utf8Str();
|
|
|
|
|
2012-08-27 23:26:36 +00:00
|
|
|
if ( !in.is_open() ) {
|
2013-10-15 21:16:50 +00:00
|
|
|
throw sg_io_exception("Cannot open file:", path);
|
2012-08-27 23:26:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// toss the first two lines of the file
|
2016-04-28 10:22:22 +00:00
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
in >> skipeol;
|
|
|
|
throwExceptionIfStreamError(in, path);
|
|
|
|
}
|
|
|
|
|
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>).
2016-04-28 07:58:49 +00:00
|
|
|
unsigned int lineNumber = 3;
|
2015-03-19 17:01:38 +00:00
|
|
|
|
2012-08-27 23:26:36 +00:00
|
|
|
// read in each remaining line of the file
|
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>).
2016-04-28 07:58:49 +00:00
|
|
|
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
|
2012-08-27 23:26:36 +00:00
|
|
|
double lat, lon;
|
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>).
2016-04-28 07:58:49 +00:00
|
|
|
|
|
|
|
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());
|
|
|
|
|
2016-04-28 09:33:59 +00:00
|
|
|
_cache->insertFix(fields[2], SGGeod::fromDeg(lon, lat));
|
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>).
2016-04-28 07:58:49 +00:00
|
|
|
|
2015-03-19 17:01:38 +00:00
|
|
|
if ((lineNumber % 100) == 0) {
|
|
|
|
// every 100 lines
|
|
|
|
unsigned int percent = (lineNumber * 100) / LINES_IN_FIX_DAT;
|
2016-04-28 09:33:59 +00:00
|
|
|
_cache->setRebuildPhaseProgress(NavDataCache::REBUILD_FIXES, percent);
|
2015-03-19 17:01:38 +00:00
|
|
|
}
|
2012-08-27 23:26:36 +00:00
|
|
|
}
|
2008-09-10 08:54:49 +00:00
|
|
|
|
2016-04-28 10:22:22 +00:00
|
|
|
throwExceptionIfStreamError(in, path);
|
2000-04-21 18:30:59 +00:00
|
|
|
}
|
2015-03-19 17:01:38 +00:00
|
|
|
|
2016-04-28 10:22:22 +00:00
|
|
|
void FixesLoader::throwExceptionIfStreamError(
|
|
|
|
const sg_gzifstream& input_stream, const SGPath& path)
|
|
|
|
{
|
|
|
|
if (input_stream.bad()) {
|
|
|
|
const std::string errMsg = simgear::strutils::error_string(errno);
|
|
|
|
|
|
|
|
SG_LOG(SG_NAVAID, SG_ALERT,
|
|
|
|
"Error while reading '" << path.utf8Str() << "': " << errMsg);
|
|
|
|
throw sg_io_exception("Error reading file (" + errMsg + ")",
|
|
|
|
sg_location(path));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-08-27 23:26:36 +00:00
|
|
|
} // of namespace flightgear;
|