7 #include <QDomDocument>
8 #include <QDomNodeList>
13 #include <QStandardPaths>
14 #include <QStringBuilder>
15 #include <QStringList>
16 #include <QTextStream>
26 using namespace swift::config;
28 namespace swift::misc::simulation::fscommon
30 using FsRegistryPathPair = QList<QPair<QString, QString>>;
32 const QStringList &CFsDirectories::getLogCategories()
34 static const QStringList cats({ CLogCategories::validation(), CLogCategories::driver() });
38 QString fsxDirFromRegistryImpl()
41 const FsRegistryPathPair fsxRegistryPathPairs = {
42 { QStringLiteral(
"HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft Games\\Flight Simulator\\10.0"),
43 QStringLiteral(
"AppPath") },
45 "HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft Games\\Flight Simulator - Steam Edition\\10.0"),
46 QStringLiteral(
"AppPath") },
47 { QStringLiteral(
"HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Microsoft Games\\Flight Simulator\\10.0"),
48 QStringLiteral(
"SetupPath") },
50 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Microsoft Games\\Flight Simulator\\10.0"),
51 QStringLiteral(
"SetupPath") }
54 for (
const auto ®istryPair : fsxRegistryPathPairs)
56 const QSettings fsxRegistry(registryPair.first, QSettings::NativeFormat);
57 fsxPath = fsxRegistry.value(registryPair.second).toString().trimmed();
59 if (fsxPath.isEmpty()) {
continue; }
60 fsxPath = CFileUtils::normalizeFilePathToQtStandard(fsxPath);
63 const QDir dir(fsxPath);
64 if (dir.exists()) {
break; }
67 return CFileUtils::normalizeFilePathToQtStandard(fsxPath);
70 const QString &CFsDirectories::fsxDirFromRegistry()
72 static const QString fsxPath(fsxDirFromRegistryImpl());
78 const QString dir(CFsDirectories::fsxDirFromRegistry());
79 if (!dir.isEmpty()) {
return dir; }
80 QStringList someDefaultDirs(
81 {
"C:/Program Files (x86)/Microsoft Games/Microsoft Flight Simulator X",
"C:/FSX" });
85 someDefaultDirs.push_back(
"P:/FSX (MSI)");
87 return CFileUtils::findFirstExisting(someDefaultDirs);
90 const QString &CFsDirectories::fsxDir()
92 static const QString dir(fsxDirImpl());
96 static QString msfsDirImpl()
99 const QStringList locations = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
100 for (
const QString &path : locations)
102 const QString msfsPackage = CFileUtils::appendFilePaths(CFileUtils::appendFilePaths(path,
"Packages"),
103 "Microsoft.FlightSimulator_8wekyb3d8bbwe");
104 const QDir d(msfsPackage);
105 if (!d.exists()) {
continue; }
109 for (QString path : locations)
113 path.replace(
"Local",
"Roaming");
114 const QString msfsPackage = CFileUtils::appendFilePaths(path,
"Microsoft Flight Simulator");
115 const QString fileName = CFileUtils::appendFilePaths(msfsPackage,
"UserCfg.opt");
116 const QFileInfo fi(fileName);
117 if (!fi.exists()) {
continue; }
123 const QString &CFsDirectories::msfsDir()
125 static const QString dir(msfsDirImpl());
129 QString msfsPackagesDirImpl()
131 QString userCfg =
"";
133 QString msfsDirectory(CFsDirectories::msfsDir());
136 if (msfsDirectory.contains(
"Roaming", Qt::CaseInsensitive))
138 userCfg = CFileUtils::appendFilePaths(msfsDirectory,
"UserCfg.opt");
143 CFileUtils::appendFilePaths(CFileUtils::appendFilePaths(msfsDirectory,
"LocalCache"),
"UserCfg.opt");
146 QFile file(CFileUtils::normalizeFilePathToQtStandard(userCfg));
147 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return {}; }
149 QTextStream in(&file);
152 QString line = in.readLine();
153 if (line.contains(
"InstalledPackagesPath"))
156 QStringList split = line.split(
"\"");
158 if (split.size() != 3) {
return {}; }
159 QString packagePath =
split[1].remove(
"\"");
160 const QDir dir(packagePath);
161 if (dir.exists()) {
return packagePath; }
167 const QString &CFsDirectories::msfsPackagesDir()
169 static const QString dir(msfsPackagesDirImpl());
173 static QString msfs2024DirImpl()
175 const QStringList locations = QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation);
176 for (
const QString &path : locations)
178 const QString msfs2024Package = CFileUtils::appendFilePaths(CFileUtils::appendFilePaths(path,
"Packages"),
179 "Microsoft.Limitless_8wekyb3d8bbwe");
180 const QDir d(msfs2024Package);
181 if (!d.exists()) {
continue; }
182 return msfs2024Package;
185 for (QString path : locations)
189 path.replace(
"Local",
"Roaming");
190 const QString msfsPackage = CFileUtils::appendFilePaths(path,
"Microsoft Flight Simulator 2024");
191 const QString fileName = CFileUtils::appendFilePaths(msfsPackage,
"UserCfg.opt");
192 const QFileInfo fi(fileName);
193 if (!fi.exists()) {
continue; }
199 const QString &CFsDirectories::msfs2024Dir()
201 static const QString dir(msfs2024DirImpl());
205 QString msfs2024PackagesDirImpl()
207 QString userCfg =
"";
209 QString msfs2024Directory(CFsDirectories::msfs2024Dir());
211 if (msfs2024Directory.contains(
"Roaming", Qt::CaseInsensitive))
213 userCfg = CFileUtils::appendFilePaths(msfs2024Directory,
"UserCfg.opt");
217 userCfg = CFileUtils::appendFilePaths(CFileUtils::appendFilePaths(msfs2024Directory,
"LocalCache"),
222 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return {}; }
224 QTextStream in(&file);
227 QString line = in.readLine();
228 if (line.contains(
"InstalledPackagesPath"))
231 QStringList split = line.split(
"\"");
233 if (split.size() != 3) {
return {}; }
234 QString packagePath =
split[1].remove(
"\"");
235 const QDir dir(packagePath);
236 if (dir.exists()) {
return packagePath; }
242 const QString &CFsDirectories::msfs2024PackagesDir()
244 static const QString dir(msfs2024PackagesDirImpl());
248 QString fsxSimObjectsDirFromRegistryImpl()
250 const QString fsxPath = CFileUtils::normalizeFilePathToQtStandard(CFsDirectories::fsxDirFromRegistry());
251 if (fsxPath.isEmpty()) {
return {}; }
252 return CFsDirectories::fsxSimObjectsDirFromSimDir(fsxPath);
255 const QString &CFsDirectories::fsxSimObjectsDirFromRegistry()
257 static const QString fsxPath(fsxSimObjectsDirFromRegistryImpl());
261 QString fsxSimObjectsDirImpl()
263 QString dir(CFsDirectories::fsxDir());
264 if (dir.isEmpty()) {
return {}; }
265 return CFsDirectories::fsxSimObjectsDirFromSimDir(dir);
268 QString msfsSimObjectsDirImpl()
270 QString dir(CFsDirectories::msfsDir());
271 if (dir.isEmpty()) {
return {}; }
272 return CFileUtils::normalizeFilePathToQtStandard(msfsPackagesDirImpl());
275 QString msfs2024SimObjectsDirImpl()
277 QString dir(CFsDirectories::msfs2024Dir());
278 if (dir.isEmpty()) {
return {}; }
279 return CFileUtils::normalizeFilePathToQtStandard(msfs2024PackagesDirImpl());
282 const QString &CFsDirectories::fsxSimObjectsDir()
284 static const QString dir(fsxSimObjectsDirImpl());
288 const QString &CFsDirectories::msfsSimObjectsDir()
290 static const QString dir(msfsSimObjectsDirImpl());
294 const QString &CFsDirectories::msfs2024SimObjectsDir()
296 static const QString dir(msfs2024SimObjectsDirImpl());
299 QString CFsDirectories::fsxSimObjectsDirFromSimDir(
const QString &simDir)
301 if (simDir.isEmpty()) {
return {}; }
302 return CFileUtils::appendFilePaths(CFileUtils::normalizeFilePathToQtStandard(simDir),
"SimObjects");
305 const QStringList &CFsDirectories::fsxSimObjectsExcludeDirectoryPatterns()
307 static const QStringList exclude {
"SimObjects/Animals",
"SimObjects/Misc",
"SimObjects/GroundVehicles",
308 "SimObjects/Boats" };
312 const QStringList &CFsDirectories::msfs20SimObjectsExcludeDirectoryPatterns()
314 static const QStringList exclude {
315 "OneStore/asobo-discovery",
316 "OneStore/asobo-flight",
317 "OneStore/asobo-landingchallenge",
318 "OneStore/asobo-mission",
319 "OneStore/asobo-tutorials",
320 "OneStore/asobo-vcockpits",
321 "OneStore/asobo-simobjects",
322 "OneStore/asobo-services",
323 "OneStore/asobo-vcockpits",
326 "OneStore/asobo-vfx",
329 "OneStore/microsoft-airport",
330 "OneStore/microsoft-bushtrip",
331 "OneStore/microsoft-discovery",
339 const QStringList &CFsDirectories::msfs2024SimObjectsExcludeDirectoryPatterns()
341 static const QStringList exclude {
349 QString p3dDirFromRegistryImpl()
352 FsRegistryPathPair p3dRegistryPathPairs = {
354 { QStringLiteral(
"HKEY_CURRENT_USER\\Software\\Lockheed Martin\\Prepar3d v6"), QStringLiteral(
"AppPath") },
355 { QStringLiteral(
"HKEY_CURRENT_USER\\Software\\Lockheed Martin\\Prepar3d v5"), QStringLiteral(
"AppPath") },
356 { QStringLiteral(
"HKEY_CURRENT_USER\\Software\\Lockheed Martin\\Prepar3d v4"), QStringLiteral(
"AppPath") },
357 { QStringLiteral(
"HKEY_CURRENT_USER\\Software\\Lockheed Martin\\Prepar3d v3"), QStringLiteral(
"AppPath") },
358 { QStringLiteral(
"HKEY_CURRENT_USER\\Software\\Lockheed Martin\\Prepar3d v2"), QStringLiteral(
"AppPath") },
359 { QStringLiteral(
"HKEY_CURRENT_USER\\Software\\LockheedMartin\\Prepar3d"), QStringLiteral(
"AppPath") }
361 for (
const auto ®istryPair : p3dRegistryPathPairs)
363 const QSettings p3dRegistry(registryPair.first, QSettings::NativeFormat);
364 p3dPath = p3dRegistry.value(registryPair.second).toString().trimmed();
366 if (p3dPath.isEmpty()) {
continue; }
367 p3dPath = CFileUtils::normalizeFilePathToQtStandard(p3dPath);
370 const QDir dir(p3dPath);
371 if (dir.exists()) {
break; }
377 const QString &CFsDirectories::p3dDirFromRegistry()
379 static const QString p3dPath = CFileUtils::normalizeFilePathToQtStandard(p3dDirFromRegistryImpl());
385 QString dir(CFsDirectories::p3dDirFromRegistry());
386 if (!dir.isEmpty()) {
return dir; }
387 const QStringList someDefaultDirs({
"C:/Program Files (x86)/Lockheed Martin/Prepar3D v4",
388 "C:/Program Files (x86)/Lockheed Martin/Prepar3D v3",
389 "C:/Program Files (x86)/Lockheed Martin/Prepar3D v2",
390 "C:/Program Files (x86)/Lockheed Martin/Prepar3D" });
391 return CFileUtils::findFirstExisting(someDefaultDirs);
394 const QString &CFsDirectories::p3dDir()
396 static const QString dir(p3dDirImpl());
400 QString p3dSimObjectsDirFromRegistryImpl()
402 const QString p3dPath = CFsDirectories::p3dDirFromRegistry();
403 if (p3dPath.isEmpty()) {
return {}; }
404 return CFsDirectories::fsxSimObjectsDirFromSimDir(p3dPath);
407 const QString &CFsDirectories::p3dSimObjectsDirFromRegistry()
409 static const QString p3dPath(p3dSimObjectsDirFromRegistryImpl());
413 QString p3dSimObjectsDirImpl()
415 QString dir(CFsDirectories::p3dDir());
416 if (dir.isEmpty()) {
return {}; }
417 return CFsDirectories::p3dSimObjectsDirFromSimDir(dir);
420 const QString &CFsDirectories::p3dSimObjectsDir()
422 static const QString dir(p3dSimObjectsDirImpl());
426 QStringList CFsDirectories::fsxSimObjectsDirPlusAddOnXmlSimObjectsPaths(
const QString &simObjectsDir)
429 QStringList allPaths = CFsDirectories::allFsxSimObjectPaths().values();
430 const QString sod = CFileUtils::normalizeFilePathToQtStandard(
431 simObjectsDir.isEmpty() ? CFsDirectories::fsxSimObjectsDir() : simObjectsDir);
432 if (!sod.isEmpty() && !allPaths.contains(sod, Qt::CaseInsensitive))
435 allPaths.push_front(sod);
438 allPaths.removeAll({});
439 allPaths.removeDuplicates();
440 allPaths.sort(Qt::CaseInsensitive);
444 QStringList CFsDirectories::msfsSimObjectsDirPath(
const QString &simObjectsDir)
446 Q_UNUSED(simObjectsDir);
447 static const QStringList Path { CFsDirectories::msfsSimObjectsDir() };
451 QStringList CFsDirectories::msfs2024SimObjectsDirPath(
const QString &simObjectsDir)
453 Q_UNUSED(simObjectsDir);
454 static const QStringList Path { CFsDirectories::msfs2024SimObjectsDir() };
457 QStringList CFsDirectories::p3dSimObjectsDirPlusAddOnXmlSimObjectsPaths(
const QString &simObjectsDir,
458 const QString &versionHint)
461 QStringList allPaths = CFsDirectories::allP3dAddOnXmlSimObjectPaths(versionHint).values();
462 const QString sod = CFileUtils::normalizeFilePathToQtStandard(
463 simObjectsDir.isEmpty() ? CFsDirectories::p3dSimObjectsDir() : simObjectsDir);
464 if (!sod.isEmpty() && !allPaths.contains(sod, Qt::CaseInsensitive))
467 allPaths.push_front(sod);
470 allPaths.removeAll({});
471 allPaths.removeDuplicates();
472 allPaths.sort(Qt::CaseInsensitive);
476 QString CFsDirectories::guessP3DVersion(
const QString &candidate)
478 if (candidate.isEmpty()) {
return "v5"; }
479 if (candidate.contains(
"v5", Qt::CaseInsensitive)) {
return QStringLiteral(
"v5"); }
480 if (candidate.contains(
"v4", Qt::CaseInsensitive)) {
return QStringLiteral(
"v4"); }
482 if (candidate.contains(
"5", Qt::CaseInsensitive)) {
return QStringLiteral(
"v5"); }
483 if (candidate.contains(
"4", Qt::CaseInsensitive)) {
return QStringLiteral(
"v4"); }
488 QString CFsDirectories::p3dSimObjectsDirFromSimDir(
const QString &simDir)
490 if (simDir.isEmpty()) {
return {}; }
491 return CFileUtils::normalizeFilePathToQtStandard(CFileUtils::appendFilePaths(simDir,
"SimObjects"));
494 const QStringList &CFsDirectories::p3dSimObjectsExcludeDirectoryPatterns()
496 static const QStringList exclude {
498 "SimObjects/Animals",
500 "SimObjects/GroundVehicles",
504 "SimObjects/Avatars",
505 "SimObjects/Countermeasures",
506 "SimObjects/Submersible",
507 "SimObjects/Weapons",
512 QString fs9DirFromRegistryImpl()
515 FsRegistryPathPair fs9RegistryPathPairs = {
517 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\DirectPlay\\Applications\\Microsoft Flight Simulator 2004"),
518 QStringLiteral(
"AppPath") },
520 "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\DirectPlay\\Applications\\Microsoft Flight "
522 QStringLiteral(
"AppPath") }
525 for (
const auto ®istryPair : fs9RegistryPathPairs)
527 QSettings fs9Registry(registryPair.first, QSettings::NativeFormat);
528 fs9Path = fs9Registry.value(registryPair.second).toString().trimmed();
530 if (fs9Path.isEmpty()) {
continue; }
531 fs9Path = CFileUtils::normalizeFilePathToQtStandard(fs9Path);
534 const QDir dir(fs9Path);
535 if (dir.exists()) {
break; }
541 const QString &CFsDirectories::fs9DirFromRegistry()
543 static const QString fs9Path(fs9DirFromRegistryImpl());
549 QString dir(CFsDirectories::fs9DirFromRegistry());
550 if (!dir.isEmpty()) {
return dir; }
551 const QStringList someDefaultDirs({
"C:/Flight Simulator 9",
"C:/FS9" });
552 return CFileUtils::findFirstExisting(someDefaultDirs);
555 const QString &CFsDirectories::fs9Dir()
557 static const QString v(fs9DirImpl());
561 QString fs9AircraftDirFromRegistryImpl()
563 QString fs9Path = CFsDirectories::fs9DirFromRegistry();
564 if (fs9Path.isEmpty()) {
return {}; }
565 return CFsDirectories::fs9AircraftDirFromSimDir(fs9Path);
568 const QString &CFsDirectories::fs9AircraftDirFromRegistry()
570 static const QString dir(fs9AircraftDirFromRegistryImpl());
574 QString fs9AircraftDirImpl()
576 const QString dir(CFsDirectories::fs9Dir());
577 if (dir.isEmpty()) {
return {}; }
578 return CFsDirectories::fs9AircraftDirFromSimDir(dir);
581 const QString &CFsDirectories::fs9AircraftDir()
583 static const QString dir(fs9AircraftDirImpl());
587 QString CFsDirectories::fs9AircraftDirFromSimDir(
const QString &simDir)
589 if (simDir.isEmpty()) {
return {}; }
590 return CFileUtils::appendFilePaths(simDir,
"Aircraft");
593 const QStringList &CFsDirectories::fs9AircraftObjectsExcludeDirectoryPatterns()
595 static const QStringList exclude;
599 QSet<QString> CFsDirectories::findP3dAddOnConfigFiles(
const QString &versionHint)
601 static const QString cfgFile(
"add-ons.cfg");
602 return CFsDirectories::findP3dConfigFiles(cfgFile, versionHint);
605 QSet<QString> CFsDirectories::findP3dSimObjectsConfigFiles(
const QString &versionHint)
607 static const QString cfgFile(
"simobjects.cfg");
608 return CFsDirectories::findP3dConfigFiles(cfgFile, versionHint);
611 QSet<QString> CFsDirectories::findP3dConfigFiles(
const QString &configFile,
const QString &versionHint)
614 const QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
616 for (
const QString &path : locations)
618 const QString pathUp = CFileUtils::appendFilePaths(CFileUtils::pathUp(path),
"Lockheed Martin");
619 const QDir d(pathUp);
620 if (!d.exists()) {
continue; }
621 if (logConfigPathReading())
623 CLogMessage(
static_cast<CFsDirectories *
>(
nullptr)).
info(u
"P3D config dir: '%1'") << d.absolutePath();
628 const QStringList entries = d.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
629 for (
const QString &entry : entries)
632 if (entry.contains(versionHint, Qt::CaseInsensitive))
634 const QString f = CFileUtils::appendFilePaths(d.absolutePath(), entry, configFile);
635 const QFileInfo fi(f);
639 if (logConfigPathReading())
641 CLogMessage(
static_cast<CFsDirectories *
>(
nullptr)).
info(u
"P3D config file: '%1'") << f;
650 QSet<QString> CFsDirectories::allConfigFilesPathValues(
const QStringList &configFiles,
bool checked,
651 const QString &pathPrefix)
653 if (configFiles.isEmpty()) {
return QSet<QString>(); }
655 for (
const QString &configFile : configFiles)
658 const QString fileContent = CFileUtils::readFileToString(configFile);
659 if (fileContent.isEmpty()) {
continue; }
661 static const QString p(
"Path=");
662 for (
const QStringRef &line : lines)
664 const int i = line.lastIndexOf(p, -1, Qt::CaseInsensitive);
665 if (i < 0 || line.endsWith(
'=')) {
continue; }
666 const QStringRef path = line.mid(i + p.length());
667 const QDir dir(QDir::fromNativeSeparators(
668 pathPrefix.isEmpty() ? path.toString() :
669 CFileUtils::appendFilePathsAndFixUnc(pathPrefix, path.toString())));
670 if (!checked || dir.exists()) { paths.insert(dir.absolutePath()); }
676 QSet<QString> CFsDirectories::allP3dAddOnXmlSimObjectPaths(
const QStringList &addOnPaths,
bool checked)
678 if (addOnPaths.isEmpty()) {
return QSet<QString>(); }
679 QSet<QString> simObjectPaths;
680 for (
const QString &addOnPath : addOnPaths)
682 const QString filename = CFileUtils::appendFilePaths(addOnPath,
"add-on.xml");
684 QFile file(filename);
685 if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file)) {
continue; }
686 if (CFsDirectories::logConfigPathReading())
689 << file.fileName() << addOnPath;
692 const QDomNodeList components = doc.elementsByTagName(
"AddOn.Component");
693 for (
int i = 0; i < components.size(); i++)
695 const QDomNode component = components.item(i);
696 const QDomElement category = component.firstChildElement(
"Category");
697 const QString categoryValue = category.text();
699 const QDomElement path = component.firstChildElement(
"Path");
700 const QString pathValue = CFileUtils::normalizeFilePathToQtStandard(path.text());
701 const bool correctPath = pathValue.contains(
"Airplanes", Qt::CaseInsensitive) ||
702 pathValue.contains(
"Rotorcraft", Qt::CaseInsensitive);
703 if (!correctPath) {
continue; }
706 const QString fp = QStringView { pathValue }.left(3).contains(
':') ?
708 CFileUtils::appendFilePaths(addOnPath, pathValue);
709 if (CFsDirectories::logConfigPathReading())
714 if (!checked || QDir(fp).exists())
716 simObjectPaths.insert(CFileUtils::normalizeFilePathToQtStandard(fp));
717 if (logConfigPathReading())
725 return simObjectPaths;
728 QSet<QString> CFsDirectories::allP3dAddOnXmlSimObjectPaths(
const QString &versionHint)
731 const QStringList addOnConfigFiles = CFsDirectories::findP3dAddOnConfigFiles(versionHint).values();
734 const QStringList addOnPaths = CFsDirectories::allConfigFilesPathValues(addOnConfigFiles,
true, {}).values();
737 const QSet<QString> all = CFsDirectories::allP3dAddOnXmlSimObjectPaths(addOnPaths,
true);
741 QSet<QString> CFsDirectories::allFsxSimObjectPaths()
743 return CFsDirectories::fsxSimObjectsPaths(CFsDirectories::findFsxConfigFiles(),
true);
746 QStringList CFsDirectories::findFsxConfigFiles()
748 const QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation);
750 for (
const QString &path : locations)
752 const QString file = CFileUtils::appendFilePaths(CFileUtils::pathUp(path),
"Microsoft/FSX/fsx.cfg");
753 const QFileInfo fi(file);
756 files.push_back(fi.absoluteFilePath());
757 if (logConfigPathReading())
760 << fi.absoluteFilePath();
767 QSet<QString> CFsDirectories::fsxSimObjectsPaths(
const QStringList &fsxFiles,
bool checked)
770 for (
const QString &fsxFile : fsxFiles) { paths.unite(CFsDirectories::fsxSimObjectsPaths(fsxFile, checked)); }
774 QSet<QString> CFsDirectories::msfsSimObjectsPaths(
const QStringList &msfsFiles,
bool checked)
777 for (
const QString &msfsFile : msfsFiles)
779 paths.unite(CFsDirectories::msfsSimObjectsPaths(msfsFile, checked));
784 QSet<QString> CFsDirectories::fsxSimObjectsPaths(
const QString &fsxFile,
bool checked)
786 const QString fileContent = CFileUtils::readFileToString(fsxFile);
787 if (fileContent.isEmpty()) {
return QSet<QString>(); }
789 static const QString p(
"SimObjectPaths.");
791 const QFileInfo fsxFileInfo(fsxFile);
792 const QString relPath = fsxFileInfo.absolutePath();
795 for (
const QStringRef &line : lines)
797 const int i1 = line.lastIndexOf(p, -1, Qt::CaseInsensitive);
798 if (i1 < 0) {
continue; }
799 const int i2 = line.lastIndexOf(
'=');
800 if (i2 < 0 || i1 >= i2 || line.endsWith(
'=')) {
continue; }
801 const QStringRef path = line.mid(i2 + 1);
802 QString soPath = QDir::fromNativeSeparators(path.toString());
803 if (logConfigPathReading())
810 if (
containsAny(soPath, CFsDirectories::fsxSimObjectsExcludeDirectoryPatterns(), Qt::CaseInsensitive))
816 if (!QStringView { soPath }.left(3).contains(
':'))
818 soPath = CFileUtils::appendFilePaths(relPath, soPath);
821 const QDir dir(soPath);
822 if (checked && !dir.exists())
825 if (logConfigPathReading())
828 .
info(u
"FSX SimObjects path skipped, not existing: '%1' in '%2'")
829 << dir.absolutePath() << fsxFile;
834 const QString afp = dir.absolutePath().toLower();
835 if (!CDirectoryUtils::containsFileInDir(afp, airFileFilter(),
true))
837 if (logConfigPathReading())
840 .
info(u
"FSX SimObjects path: Skipping '%1' from '%2', no '%3' file")
841 << afp << fsxFile << airFileFilter();
847 if (logConfigPathReading())
856 QSet<QString> CFsDirectories::msfsSimObjectsPaths(
const QString &msfsFile,
bool checked)
858 const QString fileContent = CFileUtils::readFileToString(msfsFile);
859 if (fileContent.isEmpty()) {
return QSet<QString>(); }
861 static const QString p(
"SimObjectPaths.");
863 const QFileInfo fsxFileInfo(msfsFile);
864 const QString relPath = fsxFileInfo.absolutePath();
867 for (
const QStringRef &line : lines)
869 const int i1 = line.lastIndexOf(p, -1, Qt::CaseInsensitive);
870 if (i1 < 0) {
continue; }
871 const int i2 = line.lastIndexOf(
'=');
872 if (i2 < 0 || i1 >= i2 || line.endsWith(
'=')) {
continue; }
873 const QStringRef path = line.mid(i2 + 1);
874 QString soPath = QDir::fromNativeSeparators(path.toString());
875 if (logConfigPathReading())
882 if (
containsAny(soPath, CFsDirectories::fsxSimObjectsExcludeDirectoryPatterns(), Qt::CaseInsensitive))
888 if (!QStringView(soPath).left(3).contains(
':')) { soPath = CFileUtils::appendFilePaths(relPath, soPath); }
890 const QDir dir(soPath);
891 if (checked && !dir.exists())
894 if (logConfigPathReading())
897 .
info(u
"FSX SimObjects path skipped, not existing: '%1' in '%2'")
898 << dir.absolutePath() << msfsFile;
903 const QString afp = dir.absolutePath().toLower();
904 if (!CDirectoryUtils::containsFileInDir(afp, airFileFilter(),
true))
906 if (logConfigPathReading())
909 .
info(u
"FSX SimObjects path: Skipping '%1' from '%2', no '%3' file")
910 << afp << msfsFile << airFileFilter();
916 if (logConfigPathReading())
925 const QString &CFsDirectories::airFileFilter()
927 static const QString a(
"*.air");
931 bool CFsDirectories::logConfigPathReading() {
return true; }
static bool isLocalDeveloperDebugBuild()
Local build for developers.
Class for emitting a log message.
Derived & info(const char16_t(&format)[N])
Set the severity to info, providing a format string.
SWIFT_MISC_EXPORT bool caseInsensitiveStringCompare(const QString &c1, const QString &c2)
Case insensitive string compare.
SWIFT_MISC_EXPORT bool containsAny(const QString &testString, const QStringList &any, Qt::CaseSensitivity cs)
Contains any string of the list?
SWIFT_MISC_EXPORT QList< QStringRef > splitLinesRefs(const QString &s)
Split a string into multiple lines. Blank lines are skipped.
std::vector< std::string > split(const std::string &str, size_t maxSplitCount=0, const std::string &delimiter=" ")
Split string by delimiter and maxSplitCount times.