Initial support for NavData/<type>/*.dat[.gz] files in scenery paths
Load every file matching the pattern NavData/apt/*.dat[.gz] inside each scenery path. These files are loaded in the same order as the components of globals->get_unmangled_fg_scenery() they reside in. Inside a given component, the order is determined by pathSortPredicate() in simgear/misc/sg_dir.cxx (lexicographic order at the time of this writing). For compatibility with existing scenery, $FG_ROOT/Airports/apt.dat.gz is also loaded last. The idea is that such files will have the same precedence order as the globals->get_unmangled_fg_scenery() scenery components they come from. This commit doesn't handle this fully yet, though: it blindly loads all these files. A future commit will ensure that no airport is loaded twice due to overlapping apt.dat files. This commit however handles all the logic of navdata cache rebuilding when the list, the order of apt.dat files, or any of their timestamps changes. Although only apt.dat files receive a new treatment in this commit, the changes to NavDataCache.[ch]xx are already generic so that extension of this method to fix.dat, nav.dat, etc. will require almost no change to NavDataCache.[ch]xx (however, changes will probably be needed in the various loaders: in fixlist.[ch]xx, navdb.[ch]xx, etc.). src/Navaids/CacheSchema.h: - increment the SCHEMA_VERSION by 1. This ensures among others that if someone uses a FlightGear version posterior to this change with new-style scenery (having NavData/apt/*.dat[.gz] files inside scenery paths), then goes back to a FlightGear version anterior to this change, his NavCache is rebuilt ignoring the in-scenery-paths NavData/apt/*.dat[.gz] files, as expected with the old FlightGear version. src/Navaids/NavDataCache.cxx: - NavDataCachePrivate: replace aptDatPath (SGPath) with aptDatPaths (PathList). - NavDataCachePrivate::getDatFilesPaths(): new method that returns the list of $scenery_path/NavData/<type>/*.dat[.gz] files found inside scenery paths (where <type> is one of 'apt', 'fix', etc.), plus the historical file (e.g., $FG_ROOT/Airports/apt.dat.gz for the 'apt' type). - NavDataCachePrivate::areDatFilesModified(): new method that tells whether any of these files (for a given type) has changed since the last NavCache rebuild, or if their ordered list has changed. - NavDataCachePrivate::isCachedFileModified(): minor changes. - NavDataCache::updateListsOfDatFiles(): new method that updates the lists of dat files used for NavCache freshness checking and rebuilding, i.e. currently sets/updates d->aptDatPaths using the new method d->getDatFilesPaths(), and d->metarDatPath, d->navDatPath, d->fixDatPath, d->poiDatPath, etc. as usual. This method will be useful for instance in the built-in launcher after updating scenery paths and before calling NavDataCache::isRebuildRequired(). - NavDataCache::NavDataCache(): use NavDataCache::updateListsOfDatFiles() to initialize d->aptDatPaths, d->metarDatPath, d->navDatPath, d->fixDatPath, d->poiDatPath, etc. - NavDataCache::isRebuildRequired(): use NavDataCachePrivate::areDatFilesModified() instead of just checking $FG_ROOT/Airports/apt.dat.gz. - NavDataCache::doRebuild(): load all apt.dat files listed in d->aptDatPaths, instead of only $FG_ROOT/Airports/apt.dat.gz. Write their ordered list and timestamps in the NavCache. src/Navaids/NavDataCache.hxx: - declare the new method NavDataCache::updateListsOfDatFiles(). - NavDataCache::DatFileType: new enum with values DATFILETYPE_APT, DATFILETYPE_METAR, DATFILETYPE_AWY, DATFILETYPE_NAV, DATFILETYPE_FIX, DATFILETYPE_POI, DATFILETYPE_CARRIER and DATFILETYPE_TACAN_FREQ. Maybe some of the corresponding files won't have to be moved to scenery paths, but simply listing them in the enum doesn't change how they are dealt with. Those for which per-scenery-path locations doesn't make sense can just be removed from the enum. - NavDataCache::datTypeStr: new static string_list giving an std::string such as 'apt' for each value of the NavDataCache::DatFileType enum. - NavDataCache::defaultDatFile: new static string_list giving a path (relative to $FG_ROOT) to the historical/default file for each value of the NavDataCache::DatFileType enum. src/Airports/apt_loader.cxx and src/Airports/apt_loader.hxx: - always include a path to the apt.dat file being processed in log messages, since they can now apply to many files; - be clearer about code 99: it should normally be at the end of apt.dat files, but technically, it is not an EOF; - use the expression "row code" consistently with the apt.dat format spec (for now: only in places where there is another change to do). src/GUI/QtLauncher.cxx and src/GUI/QtLauncher_private.hxx: - turn QtLauncher::setSceneryPaths() into a static method and call it in runLauncherDialog() before instantiating NavDataCache, so that NavDataCache::updateListsOfDatFiles() (called from NavDataCache's constructor) can see all configured scenery paths.
This commit is contained in:
parent
dfdd52a81b
commit
670cf9a894
7 changed files with 277 additions and 54 deletions
|
@ -55,7 +55,8 @@
|
|||
#include <iostream>
|
||||
#include <sstream> // std::istringstream
|
||||
|
||||
using namespace std;
|
||||
using std::vector;
|
||||
using std::string;
|
||||
|
||||
static FGPositioned::Type fptypeFromRobinType(int aType)
|
||||
{
|
||||
|
@ -86,13 +87,18 @@ APTLoader::~APTLoader() { }
|
|||
|
||||
void APTLoader::parseAPT(const SGPath &aptdb_file)
|
||||
{
|
||||
string apt_dat = aptdb_file.utf8Str(); // full path to the file being parsed
|
||||
sg_gzifstream in(aptdb_file);
|
||||
|
||||
if ( !in.is_open() ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << aptdb_file );
|
||||
throw sg_io_exception("cannot open apt.dat file", aptdb_file);
|
||||
const std::string errMsg = simgear::strutils::error_string(errno);
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"Cannot open file '" << apt_dat << "': " << errMsg );
|
||||
throw sg_io_exception("Cannot open file (" + errMsg + ")",
|
||||
sg_location(aptdb_file));
|
||||
}
|
||||
|
||||
SG_LOG( SG_GENERAL, SG_INFO, "Opened apt.dat file: '" << apt_dat << "'" );
|
||||
string line;
|
||||
|
||||
unsigned int line_id = 0;
|
||||
|
@ -110,15 +116,16 @@ void APTLoader::parseAPT(const SGPath &aptdb_file)
|
|||
if ( stripped_line != "I" && stripped_line != "A" ) {
|
||||
std::string pb = "invalid first line (neither 'I' nor 'A')";
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, aptdb_file << ": " << pb);
|
||||
throw sg_format_exception("cannot parse apt.dat file: " + pb,
|
||||
aptdb_file.utf8Str());
|
||||
throw sg_format_exception("cannot parse '" + apt_dat + "': " + pb,
|
||||
stripped_line);
|
||||
}
|
||||
} else { // second line of the file
|
||||
std::istringstream s(line);
|
||||
int apt_dat_format_version;
|
||||
s >> apt_dat_format_version;
|
||||
SG_LOG( SG_GENERAL, SG_INFO,
|
||||
"apt.dat format version: " << apt_dat_format_version );
|
||||
"apt.dat format version (" << apt_dat << "): " <<
|
||||
apt_dat_format_version );
|
||||
}
|
||||
} // end of the apt.dat header
|
||||
|
||||
|
@ -143,7 +150,7 @@ void APTLoader::parseAPT(const SGPath &aptdb_file)
|
|||
if ( line_id == 1 /* Airport */ ||
|
||||
line_id == 16 /* Seaplane base */ ||
|
||||
line_id == 17 /* Heliport */ ) {
|
||||
parseAirportLine(simgear::strutils::split(line));
|
||||
parseAirportLine(apt_dat, simgear::strutils::split(line));
|
||||
} else if ( line_id == 10 ) { // Runway v810
|
||||
parseRunwayLine810(simgear::strutils::split(line));
|
||||
} else if ( line_id == 100 ) { // Runway v850
|
||||
|
@ -174,7 +181,7 @@ void APTLoader::parseAPT(const SGPath &aptdb_file)
|
|||
} else if ( line_id == 0 ) {
|
||||
// ??
|
||||
} else if ( line_id >= 50 && line_id <= 56) {
|
||||
parseCommLine(line_id, simgear::strutils::split(line));
|
||||
parseCommLine(apt_dat, line_id, simgear::strutils::split(line));
|
||||
} else if ( line_id == 110 ) {
|
||||
pavement = true;
|
||||
parsePavementLine850(simgear::strutils::split(line, 0, 4));
|
||||
|
@ -190,16 +197,18 @@ void APTLoader::parseAPT(const SGPath &aptdb_file)
|
|||
} else if ( line_id >= 1000 ) {
|
||||
// airport traffic flow (ignore)
|
||||
} else if ( line_id == 99 ) {
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG, "End of file reached" );
|
||||
SG_LOG( SG_GENERAL, SG_DEBUG,
|
||||
apt_dat << ": code 99 found (normally at end of file)" );
|
||||
} else {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"Unknown line(#" << line_num << ") in apt.dat file: " << line );
|
||||
throw sg_format_exception("malformed line in apt.dat:", line);
|
||||
std::ostringstream oss;
|
||||
oss << apt_dat << ":" << line_num << ": unknown row code " << line_id;
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, oss.str() << " (" << line << ")" );
|
||||
throw sg_format_exception(oss.str(), line);
|
||||
}
|
||||
}
|
||||
|
||||
throwExceptionIfStreamError(in, aptdb_file);
|
||||
finishAirport();
|
||||
finishAirport(apt_dat);
|
||||
}
|
||||
|
||||
// Tell whether an apt.dat line is blank or a comment line
|
||||
|
@ -222,7 +231,7 @@ void APTLoader::throwExceptionIfStreamError(const sg_gzifstream& input_stream,
|
|||
}
|
||||
}
|
||||
|
||||
void APTLoader::finishAirport()
|
||||
void APTLoader::finishAirport(const string& aptDat)
|
||||
{
|
||||
if (currentAirportID == 0) {
|
||||
return;
|
||||
|
@ -230,8 +239,8 @@ void APTLoader::finishAirport()
|
|||
|
||||
if (!rwy_count) {
|
||||
currentAirportID = 0;
|
||||
SG_LOG(SG_GENERAL, SG_ALERT, "ERROR: No runways for " << last_apt_id
|
||||
<< ", skipping." );
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, "Error in '" << aptDat <<
|
||||
"': no runways for " << last_apt_id << ", skipping." );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -244,13 +253,14 @@ void APTLoader::finishAirport()
|
|||
currentAirportID = 0;
|
||||
}
|
||||
|
||||
void APTLoader::parseAirportLine(const vector<string>& token)
|
||||
void APTLoader::parseAirportLine(const string& aptDat,
|
||||
const vector<string>& token)
|
||||
{
|
||||
const string& id(token[4]);
|
||||
double elev = atof( token[1].c_str() );
|
||||
|
||||
// finish the previous airport
|
||||
finishAirport();
|
||||
finishAirport(aptDat);
|
||||
|
||||
last_apt_elev = elev;
|
||||
|
||||
|
@ -488,11 +498,12 @@ void APTLoader::parsePavementNodeLine850(int num, const vector<string>& token)
|
|||
}
|
||||
}
|
||||
|
||||
void APTLoader::parseCommLine(int lineId, const vector<string>& token)
|
||||
void APTLoader::parseCommLine(const string& aptDat, int lineId,
|
||||
const vector<string>& token)
|
||||
{
|
||||
if ( rwy_count <= 0 ) {
|
||||
SG_LOG( SG_GENERAL, SG_ALERT,
|
||||
"No runways; skipping comm for " + last_apt_id);
|
||||
aptDat << ": no runways, skipping comm for " << last_apt_id );
|
||||
}
|
||||
|
||||
SGGeod pos = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count,
|
||||
|
@ -538,7 +549,8 @@ void APTLoader::parseCommLine(int lineId, const vector<string>& token)
|
|||
cache->insertCommStation(ty, name, pos, freqKhz, rangeNm, currentAirportID);
|
||||
}
|
||||
else SG_LOG( SG_GENERAL, SG_DEBUG,
|
||||
"Found unnamed comm. Skipping: " << lineId );
|
||||
aptDat << ": found unnamed comm (row ID " << lineId <<
|
||||
"), skipping" );
|
||||
}
|
||||
|
||||
// Load the airport data base from the specified aptdb file. The
|
||||
|
|
|
@ -60,8 +60,9 @@ private:
|
|||
bool isBlankOrCommentLine(const std::string& line);
|
||||
void throwExceptionIfStreamError(const sg_gzifstream& input_stream,
|
||||
const SGPath& path);
|
||||
void parseAirportLine(const std::vector<std::string>& token);
|
||||
void finishAirport();
|
||||
void parseAirportLine(const std::string& aptDat,
|
||||
const std::vector<std::string>& token);
|
||||
void finishAirport(const std::string& aptDat);
|
||||
void parseRunwayLine810(const std::vector<std::string>& token);
|
||||
void parseRunwayLine850(const std::vector<std::string>& token);
|
||||
void parseWaterRunwayLine850(const std::vector<std::string>& token);
|
||||
|
@ -69,7 +70,8 @@ private:
|
|||
void parsePavementLine850(const std::vector<std::string>& token);
|
||||
void parsePavementNodeLine850(int num, const std::vector<std::string>& token);
|
||||
|
||||
void parseCommLine(int lineId, const std::vector<std::string>& token);
|
||||
void parseCommLine(const std::string& aptDat, int lineId,
|
||||
const std::vector<std::string>& token);
|
||||
|
||||
double rwy_lat_accum;
|
||||
double rwy_lon_accum;
|
||||
|
|
|
@ -471,6 +471,8 @@ void initApp(int& argc, char** argv)
|
|||
|
||||
bool runLauncherDialog()
|
||||
{
|
||||
// Used for NavDataCache initialization: needed to find the apt.dat files
|
||||
QtLauncher::setSceneryPaths();
|
||||
// startup the nav-cache now. This pre-empts normal startup of
|
||||
// the cache, but no harm done. (Providing scenery paths are consistent)
|
||||
|
||||
|
@ -678,7 +680,7 @@ QtLauncher::~QtLauncher()
|
|||
globals->get_subsystem<FGHTTPClient>()->client()->cancelRequest(m_mpServerRequest);
|
||||
}
|
||||
|
||||
void QtLauncher::setSceneryPaths()
|
||||
void QtLauncher::setSceneryPaths() // static method
|
||||
{
|
||||
globals->clear_fg_scenery();
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public:
|
|||
|
||||
void setInAppMode();
|
||||
|
||||
void setSceneryPaths();
|
||||
static void setSceneryPaths();
|
||||
|
||||
static void restartTheApp(QStringList fgArgs);
|
||||
protected:
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef FG_NAVCACHE_SCHEMA_HXX
|
||||
#define FG_NAVCACHE_SCHEMA_HXX
|
||||
|
||||
const int SCHEMA_VERSION = 15;
|
||||
const int SCHEMA_VERSION = 16;
|
||||
|
||||
#define SCHEMA_SQL \
|
||||
"CREATE TABLE properties (key VARCHAR, value VARCHAR);" \
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <simgear/misc/sg_dir.hxx>
|
||||
#include <simgear/misc/strutils.hxx>
|
||||
#include <simgear/threads/SGThread.hxx>
|
||||
#include <simgear/threads/SGGuard.hxx>
|
||||
|
@ -332,6 +333,9 @@ public:
|
|||
}
|
||||
|
||||
bool isCachedFileModified(const SGPath& path, bool verbose);
|
||||
PathList getDatFilesPaths(NavDataCache::DatFileType datFileType) const;
|
||||
bool areDatFilesModified(NavDataCache::DatFileType datFileType,
|
||||
const PathList& datFiles, bool verbose);
|
||||
|
||||
void callSqlite(int result, const string& sql)
|
||||
{
|
||||
|
@ -848,7 +852,8 @@ public:
|
|||
bool transactionAborted;
|
||||
sqlite3_stmt_ptr beginTransactionStmt, commitTransactionStmt, rollbackTransactionStmt;
|
||||
|
||||
SGPath aptDatPath, metarDatPath, navDatPath, fixDatPath, poiDatPath,
|
||||
PathList aptDatPaths;
|
||||
SGPath metarDatPath, navDatPath, fixDatPath, poiDatPath,
|
||||
carrierDatPath, airwayDatPath;
|
||||
|
||||
sqlite3_stmt_ptr readPropertyQuery, writePropertyQuery,
|
||||
|
@ -978,7 +983,9 @@ FGPositioned* NavDataCache::NavDataCachePrivate::loadById(sqlite3_int64 rowid,
|
|||
bool NavDataCache::NavDataCachePrivate::isCachedFileModified(const SGPath& path, bool verbose)
|
||||
{
|
||||
if (!path.exists()) {
|
||||
throw sg_io_exception("isCachedFileModified: Missing file:", path);
|
||||
throw sg_exception(
|
||||
"NavCache: missing file '" + path.utf8Str() + "'",
|
||||
string("NavDataCache::NavDataCachePrivate::isCachedFileModified()"));
|
||||
}
|
||||
|
||||
sqlite_bind_temp_stdstring(statCacheCheck, 1, path.realpath().utf8Str());
|
||||
|
@ -999,15 +1006,166 @@ bool NavDataCache::NavDataCachePrivate::isCachedFileModified(const SGPath& path,
|
|||
|
||||
isModified = (delta != 0);
|
||||
} else {
|
||||
SG_LOG(SG_NAVCACHE, logLevel, "NavCache: initial build required for " << path);
|
||||
SG_LOG(SG_NAVCACHE, logLevel, "NavCache: (re-)build required because '" <<
|
||||
path.utf8Str() << "' is not in the cache");
|
||||
}
|
||||
|
||||
reset(statCacheCheck);
|
||||
return isModified;
|
||||
}
|
||||
|
||||
// Return the list of $scenery_path/NavData/<type>/*.dat[.gz] files found
|
||||
// inside scenery paths, plus the default file for the given type (e.g.,
|
||||
// $FG_ROOT/Airports/apt.dat.gz for the 'apt' type).
|
||||
PathList NavDataCache::NavDataCachePrivate::getDatFilesPaths(
|
||||
NavDataCache::DatFileType datFileType) const
|
||||
{
|
||||
PathList result;
|
||||
SGPath visitedPath; // to avoid duplicates and time wasting
|
||||
const string datFilesSubDir = "NavData/" +
|
||||
NavDataCache::datTypeStr[datFileType];
|
||||
const PathList& sceneryPaths = globals->get_unmangled_fg_scenery();
|
||||
|
||||
for (PathList::const_iterator dirsIt = sceneryPaths.begin();
|
||||
dirsIt != sceneryPaths.end(); dirsIt++) {
|
||||
if (dirsIt->isNull() || *dirsIt == visitedPath) {
|
||||
continue; // duplicate or empty path
|
||||
} else if (! dirsIt->isDir()) {
|
||||
SG_LOG(SG_NAVCACHE, SG_WARN, *dirsIt <<
|
||||
": given as a scenery path, but is not a directory");
|
||||
visitedPath = *dirsIt; // to avoid duplicate log messages
|
||||
continue;
|
||||
}
|
||||
|
||||
visitedPath = *dirsIt;
|
||||
SGPath datFilesDir = visitedPath;
|
||||
datFilesDir.append(datFilesSubDir);
|
||||
|
||||
if (datFilesDir.isDir()) {
|
||||
// Deterministic because the return value of simgear::Dir::children() is
|
||||
// already sorted
|
||||
const PathList files = simgear::Dir(datFilesDir).children(
|
||||
simgear::Dir::TYPE_FILE | simgear::Dir::NO_DOT_OR_DOTDOT);
|
||||
|
||||
for (PathList::const_iterator filesIt = files.begin();
|
||||
filesIt != files.end(); filesIt++) {
|
||||
const std::string name = filesIt->file();
|
||||
if (simgear::strutils::ends_with(name, ".dat") ||
|
||||
simgear::strutils::ends_with(name, ".dat.gz"))
|
||||
result.push_back(*filesIt);
|
||||
}
|
||||
}
|
||||
} // of loop over 'sceneryPaths'
|
||||
|
||||
// Add the default file (e.g., $FG_ROOT/Airports/apt.dat.gz), at least for
|
||||
// now
|
||||
SGPath defaultDatFile(globals->get_fg_root());
|
||||
defaultDatFile.append(NavDataCache::defaultDatFile[datFileType]);
|
||||
if ((result.empty() || result.back() != defaultDatFile) &&
|
||||
defaultDatFile.isFile()) {
|
||||
result.push_back(defaultDatFile);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Compare:
|
||||
// - the list of dat files given by 'datFiles';
|
||||
// - the list obtained from the record with key '<type>.dat files' of the
|
||||
// NavDataCache 'properties' table, where <type> is one of 'apt', 'metar',
|
||||
// 'fix', 'poi', etc..
|
||||
//
|
||||
// This comparison is sensitive to the number and order of the files,
|
||||
// their respective SGPath::realpath() and SGPath::modTime().
|
||||
bool NavDataCache::NavDataCachePrivate::areDatFilesModified(
|
||||
NavDataCache::DatFileType datFileType, const PathList& datFiles, bool verbose)
|
||||
{
|
||||
// 'apt' or 'metar' or 'fix' or...
|
||||
const string datTypeStr = NavDataCache::datTypeStr[datFileType];
|
||||
const string_list cachedFiles = outer->readOrderedStringListProperty(
|
||||
datTypeStr + ".dat files", &SGPath::pathListSep);
|
||||
PathList::const_iterator datFilesIt = datFiles.begin();
|
||||
string_list::const_iterator cachedFilesIt = cachedFiles.begin();
|
||||
// Same logic as in NavDataCachePrivate::isCachedFileModified()
|
||||
sgDebugPriority logLevel = verbose ? SG_WARN : SG_DEBUG;
|
||||
|
||||
if (cachedFilesIt == cachedFiles.end() && datFilesIt != datFiles.end()) {
|
||||
SG_LOG(SG_NAVCACHE, logLevel,
|
||||
"NavCache: rebuild required for " << datTypeStr << ".dat files "
|
||||
"(no file in cache, but " << datFiles.size() << " such file" <<
|
||||
(datFiles.size() > 1 ? "s" : "") << " found in scenery paths)");
|
||||
return true;
|
||||
}
|
||||
|
||||
while (datFilesIt != datFiles.end()) {
|
||||
const SGPath& path = *(datFilesIt++);
|
||||
|
||||
if (!path.exists()) {
|
||||
throw sg_exception(
|
||||
"NavCache: non-existent file '" + path.utf8Str() + "'",
|
||||
string("NavDataCache::NavDataCachePrivate::areDatFilesModified()"));
|
||||
}
|
||||
|
||||
if (cachedFilesIt == cachedFiles.end()) {
|
||||
SG_LOG(SG_NAVCACHE, logLevel,
|
||||
"NavCache: rebuild required for " << datTypeStr << ".dat files "
|
||||
"(less files in cache than in scenery paths)");
|
||||
return true;
|
||||
} else {
|
||||
string cachedFile = *(cachedFilesIt++);
|
||||
string fileOnDisk = path.realpath().utf8Str();
|
||||
|
||||
if (cachedFile != fileOnDisk || isCachedFileModified(path, verbose)) {
|
||||
// isCachedFileModified() does all the logging, so we only have to
|
||||
// tell what is happening in case that method was not called.
|
||||
if (cachedFile != fileOnDisk) {
|
||||
SG_LOG(SG_NAVCACHE, logLevel,
|
||||
"NavCache: rebuild required because '" << cachedFile <<
|
||||
"' (in cache) != '" << fileOnDisk << "' (on disk)");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} // of loop over the elements of 'datFiles'
|
||||
|
||||
if (cachedFilesIt != cachedFiles.end()) {
|
||||
SG_LOG(SG_NAVCACHE, logLevel,
|
||||
"NavCache: rebuild required for " << datTypeStr << ".dat files "
|
||||
"(more files in cache than in scenery paths)");
|
||||
return true;
|
||||
}
|
||||
|
||||
SG_LOG(SG_NAVCACHE, SG_DEBUG,
|
||||
"NavCache: no rebuild required for " << datTypeStr << ".dat files");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// NavDataCache's static member variables
|
||||
static NavDataCache* static_instance = NULL;
|
||||
|
||||
const string_list NavDataCache::datTypeStr = {
|
||||
string("apt"),
|
||||
string("metar"),
|
||||
string("awy"),
|
||||
string("nav"),
|
||||
string("fix"),
|
||||
string("poi"),
|
||||
string("carrier"),
|
||||
string("TACAN_freq")
|
||||
};
|
||||
|
||||
const string_list NavDataCache::defaultDatFile = {
|
||||
string("Airports/apt.dat.gz"),
|
||||
string("Airports/metar.dat.gz"),
|
||||
string("Navaids/awy.dat.gz"),
|
||||
string("Navaids/nav.dat.gz"),
|
||||
string("Navaids/fix.dat.gz"),
|
||||
string("Navaids/poi.dat.gz"),
|
||||
string("Navaids/carrier.dat.gz"),
|
||||
string("Navaids/TACAN_freq.dat.gz")
|
||||
};
|
||||
|
||||
NavDataCache::NavDataCache()
|
||||
{
|
||||
const int MAX_TRIES = 3;
|
||||
|
@ -1050,26 +1208,8 @@ NavDataCache::NavDataCache()
|
|||
Octree::global_spatialOctree =
|
||||
new Octree::Branch(SGBox<double>(-earthExtent, earthExtent), 1);
|
||||
|
||||
d->aptDatPath = SGPath(globals->get_fg_root());
|
||||
d->aptDatPath.append("Airports/apt.dat.gz");
|
||||
|
||||
d->metarDatPath = SGPath(globals->get_fg_root());
|
||||
d->metarDatPath.append("Airports/metar.dat.gz");
|
||||
|
||||
d->navDatPath = SGPath(globals->get_fg_root());
|
||||
d->navDatPath.append("Navaids/nav.dat.gz");
|
||||
|
||||
d->fixDatPath = SGPath(globals->get_fg_root());
|
||||
d->fixDatPath.append("Navaids/fix.dat.gz");
|
||||
|
||||
d->poiDatPath = SGPath(globals->get_fg_root());
|
||||
d->poiDatPath.append("Navaids/poi.dat.gz");
|
||||
|
||||
d->carrierDatPath = SGPath(globals->get_fg_root());
|
||||
d->carrierDatPath.append("Navaids/carrier_nav.dat.gz");
|
||||
|
||||
d->airwayDatPath = SGPath(globals->get_fg_root());
|
||||
d->airwayDatPath.append("Navaids/awy.dat.gz");
|
||||
// Update d->aptDatPaths, d->metarDatPath, d->navDatPath, etc.
|
||||
updateListsOfDatFiles();
|
||||
}
|
||||
|
||||
NavDataCache::~NavDataCache()
|
||||
|
@ -1090,6 +1230,38 @@ NavDataCache* NavDataCache::instance()
|
|||
return static_instance;
|
||||
}
|
||||
|
||||
// Update the lists of dat files used for NavCache freshness checking and
|
||||
// rebuilding.
|
||||
void NavDataCache::updateListsOfDatFiles() {
|
||||
// All $scenery_path/NavData/apt/*.dat[.gz] files found inside scenery
|
||||
// paths, plus $FG_ROOT/Airports/apt.dat.gz (order matters).
|
||||
d->aptDatPaths = d->getDatFilesPaths(DATFILETYPE_APT);
|
||||
// Trivial extension to the other types of dat files:
|
||||
// d->navDatPaths = d->getDatFilesPaths(DATFILETYPE_NAV);
|
||||
// d->fixDatPaths = d->getDatFilesPaths(DATFILETYPE_FIX);
|
||||
// etc.
|
||||
//
|
||||
// These ones are still managed the "old" way (no search through scenery
|
||||
// paths).
|
||||
d->metarDatPath = SGPath(globals->get_fg_root());
|
||||
d->metarDatPath.append("Airports/metar.dat.gz");
|
||||
|
||||
d->navDatPath = SGPath(globals->get_fg_root());
|
||||
d->navDatPath.append("Navaids/nav.dat.gz");
|
||||
|
||||
d->fixDatPath = SGPath(globals->get_fg_root());
|
||||
d->fixDatPath.append("Navaids/fix.dat.gz");
|
||||
|
||||
d->poiDatPath = SGPath(globals->get_fg_root());
|
||||
d->poiDatPath.append("Navaids/poi.dat.gz");
|
||||
|
||||
d->carrierDatPath = SGPath(globals->get_fg_root());
|
||||
d->carrierDatPath.append("Navaids/carrier_nav.dat.gz");
|
||||
|
||||
d->airwayDatPath = SGPath(globals->get_fg_root());
|
||||
d->airwayDatPath.append("Navaids/awy.dat.gz");
|
||||
}
|
||||
|
||||
bool NavDataCache::isRebuildRequired()
|
||||
{
|
||||
if (d->readOnly) {
|
||||
|
@ -1101,7 +1273,7 @@ bool NavDataCache::isRebuildRequired()
|
|||
return true;
|
||||
}
|
||||
|
||||
if (d->isCachedFileModified(d->aptDatPath, true) ||
|
||||
if (d->areDatFilesModified(DATFILETYPE_APT, d->aptDatPaths, true) ||
|
||||
d->isCachedFileModified(d->metarDatPath, true) ||
|
||||
d->isCachedFileModified(d->navDatPath, true) ||
|
||||
d->isCachedFileModified(d->fixDatPath, true) ||
|
||||
|
@ -1167,14 +1339,26 @@ void NavDataCache::doRebuild()
|
|||
SGTimeStamp st;
|
||||
{
|
||||
Transaction txn(this);
|
||||
string_list aptDatFiles;
|
||||
|
||||
st.stamp();
|
||||
airportDBLoad(d->aptDatPath);
|
||||
SG_LOG(SG_NAVCACHE, SG_INFO, "apt.dat load took:" << st.elapsedMSec());
|
||||
for (PathList::const_iterator it = d->aptDatPaths.begin();
|
||||
it != d->aptDatPaths.end(); it++) {
|
||||
aptDatFiles.push_back(it->realpath().utf8Str());
|
||||
airportDBLoad(*it);
|
||||
stampCacheFile(*it); // this uses the realpath() of the file
|
||||
}
|
||||
|
||||
// Store the list of apt.dat files we have loaded
|
||||
writeOrderedStringListProperty(
|
||||
datTypeStr[DATFILETYPE_APT] + ".dat files", aptDatFiles,
|
||||
&SGPath::pathListSep);
|
||||
SG_LOG(SG_NAVCACHE, SG_INFO,
|
||||
datTypeStr[DATFILETYPE_APT] + ".dat files load took:" <<
|
||||
st.elapsedMSec());
|
||||
|
||||
setRebuildPhaseProgress(REBUILD_UNKNOWN);
|
||||
metarDataLoad(d->metarDatPath);
|
||||
stampCacheFile(d->aptDatPath);
|
||||
stampCacheFile(d->metarDatPath);
|
||||
|
||||
st.stamp();
|
||||
|
|
|
@ -63,6 +63,10 @@ public:
|
|||
|
||||
SGPath path() const;
|
||||
|
||||
// Update d->aptDatPaths, d->metarDatPath, d->navDatPath, d->fixDatPath,
|
||||
// d->poiDatPath, etc. by looking into $scenery_path/NavData for each
|
||||
// scenery path.
|
||||
void updateListsOfDatFiles();
|
||||
/**
|
||||
* predicate - check if the cache needs to be rebuilt.
|
||||
* This can happen is the cache file is missing or damaged, or one of the
|
||||
|
@ -294,6 +298,25 @@ private:
|
|||
void commitTransaction();
|
||||
void abortTransaction();
|
||||
|
||||
enum DatFileType {
|
||||
DATFILETYPE_APT = 0,
|
||||
DATFILETYPE_METAR,
|
||||
DATFILETYPE_AWY,
|
||||
DATFILETYPE_NAV,
|
||||
DATFILETYPE_FIX,
|
||||
DATFILETYPE_POI,
|
||||
DATFILETYPE_CARRIER,
|
||||
DATFILETYPE_TACAN_FREQ
|
||||
};
|
||||
|
||||
// datTypeStr[DATFILETYPE_APT] = "apt", etc. This gives, among other things,
|
||||
// the subdirectory of $scenery_path/NavData where each type of dat file is
|
||||
// looked for.
|
||||
static const string_list datTypeStr;
|
||||
// defaultDatFile[DATFILETYPE_APT] = std::string("Airports/apt.dat.gz"), etc.
|
||||
// This tells where to find the historical dat files: those under $FG_ROOT.
|
||||
static const string_list defaultDatFile;
|
||||
|
||||
class NavDataCachePrivate;
|
||||
std::auto_ptr<NavDataCachePrivate> d;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue