/* Copyright (C) 2015 * swift Project Community / Contributors * * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, * including this file, may be copied, modified, propagated, or distributed except according to the terms * contained in the LICENSE file. */ #include "blackmisc/simulation/xplane/xplaneutil.h" #include "blackmisc/fileutils.h" #include "blackmisc/directoryutils.h" #include "qsystemdetection.h" #include #include #include #include #include #if defined(Q_OS_WIN) #include #endif using namespace BlackMisc; namespace BlackMisc { namespace Simulation { namespace XPlane { // Returns the last path from filePath, which does exist on the file system QString getLastExistingPathFromFile(const QString &filePath) { const QFileInfo fileInfo(filePath); if (!fileInfo.exists()) { return {}; } QFile file(fileInfo.absoluteFilePath()); if (!file.open(QIODevice::ReadOnly)) { return {}; } QString lastLine; QTextStream ts(&file); while (!ts.atEnd()) { QString pathToCheck = ts.readLine(); if (QFileInfo::exists(pathToCheck)) { lastLine = pathToCheck; } } return lastLine; } #if defined(Q_OS_WIN) QString getWindowsLocalAppDataPath() { QString result; TCHAR szLocalAppDataPath[MAX_PATH]; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, szLocalAppDataPath))) { result = QString::fromWCharArray(szLocalAppDataPath); } return result; } #endif QString CXPlaneUtil::xplane9Dir() { static const QString xplaneInstallFile("x-plane_install.txt"); const QString xplaneInstallFilePath = xplaneDir(xplaneInstallFile); return getLastExistingPathFromFile(xplaneInstallFilePath); } QString CXPlaneUtil::xplane10Dir() { static const QString xplaneInstallFile("x-plane_install_10.txt"); const QString xplaneInstallFilePath = xplaneDir(xplaneInstallFile); return getLastExistingPathFromFile(xplaneInstallFilePath); } QString CXPlaneUtil::xplane11Dir() { static const QString xplaneInstallFile("x-plane_install_11.txt"); const QString xplaneInstallFilePath = xplaneDir(xplaneInstallFile); return getLastExistingPathFromFile(xplaneInstallFilePath); } QString CXPlaneUtil::xplaneDir(const QString &xplaneInstallFile) { //! \fixme KB 8/17 we could also use the runtime CBuildConfig decision here, which looks nicer (I personally always try to avoid ifdef) #if defined(Q_OS_WIN) return CFileUtils::appendFilePathsAndFixUnc(getWindowsLocalAppDataPath(), xplaneInstallFile); #elif defined (Q_OS_LINUX) static const QString xp(".x-plane"); return CFileUtils::appendFilePaths(QDir::homePath(), xp, xplaneInstallFile); #elif defined (Q_OS_OSX) static const QString lib("Library/Preferences"); return CFileUtils::appendFilePaths(QDir::homePath(), lib, xplaneInstallFile); #endif } const QString &CXPlaneUtil::xplaneRootDir() { static const QString dir = [] { if (!xplane11Dir().isEmpty()) { return xplane11Dir(); } else if (!xplane10Dir().isEmpty()) { return xplane10Dir(); } else if (!xplane9Dir().isEmpty()) { return xplane9Dir(); } else { return QString(); } }(); return dir; } bool CXPlaneUtil::isXplaneRootDirExisting() { static const bool exists = QDir(xplaneRootDir()).exists(); return exists; } const QString &CXPlaneUtil::xplanePluginDir() { static const QString pd(xplaneRootDir().isEmpty() ? "" : CFileUtils::appendFilePaths(xplaneRootDir(), xplanePluginPathName())); return pd; } QString CXPlaneUtil::pluginDirFromRootDir(const QString &rootDir) { return CFileUtils::appendFilePathsAndFixUnc(rootDir, xplanePluginPathName()); } QStringList CXPlaneUtil::modelDirectoriesFromSimDir(const QString &simulatorDir) { if (simulatorDir.isEmpty()) { return QStringList(); } return QStringList({ simulatorDir }); } const QString &CXPlaneUtil::xplanePluginPathName() { static const QString p("Resources/plugins"); return p; } const QString &CXPlaneUtil::xswiftbusPathName() { static const QString p("xswiftbus"); return p; } bool CXPlaneUtil::isXplanePluginDirDirExisting() { static const bool exists = QDir(xplanePluginDir()).exists(); return exists; } QStringList CXPlaneUtil::pluginSubdirectories(const QString &pluginDir) { const QString dirName = pluginDir.isEmpty() ? xplaneRootDir() : pluginDir; if (!CDirectoryUtils::isDirExisting(dirName)) { return QStringList(); } const QDir dir(dirName); return dir.entryList(QDir::Dirs, QDir::Name | QDir::IgnoreCase); } const QStringList &CXPlaneUtil::xplaneModelDirectories() { static const QStringList dirs = xplaneRootDir().isEmpty() ? QStringList() : QStringList({ xplaneRootDir() }); return dirs; } const QStringList &CXPlaneUtil::xplaneModelExcludeDirectoryPatterns() { static const QStringList empty; return empty; } QString CXPlaneUtil::xswiftbusPluginDir(const QString &xplaneRootDir) { const QString rootDir = xplaneRootDir.isEmpty() ? CXPlaneUtil::xplaneRootDir() : xplaneRootDir; if (!rootDir.isEmpty()) { const QString xswiftbusDir = CFileUtils::appendFilePathsAndFixUnc(CXPlaneUtil::pluginDirFromRootDir(xplaneRootDir), CXPlaneUtil::xswiftbusPathName()); if (CDirectoryUtils::isDirExisting(xswiftbusDir)) { return xswiftbusDir; } } return {}; } QString CXPlaneUtil::xswiftbusLegacyDir(const QString &xplaneRootDir) { static const QString legacyPath("/Resources/plugins/xswiftbus/LegacyData"); // Return the first non empty path, we can find. const QString rootDir = xplaneRootDir.isEmpty() ? CXPlaneUtil::xplaneRootDir() : xplaneRootDir; if (!rootDir.isEmpty()) { const QString xswiftbusLegacy = CFileUtils::appendFilePathsAndFixUnc(xplaneRootDir, legacyPath); if (CDirectoryUtils::isDirExisting(xswiftbusLegacy)) { return xswiftbusLegacy; } } return {}; } bool CXPlaneUtil::hasXSwiftBusBuildAndPluginDir(const QString &xplaneRootDir) { if (CDirectoryUtils::getXSwiftBusBuildDirectory().isEmpty()) { return false; } const QString xswiftBusPluginDir = CXPlaneUtil::xswiftbusPluginDir(xplaneRootDir); return (!xswiftBusPluginDir.isEmpty()); } QStringList CXPlaneUtil::findConflictingPlugins(const QString &pluginDir) { const QStringList files = findAllXplFiles(pluginDir); QStringList conflicts; for (const QString &file : files) { if (file.contains("swift", Qt::CaseInsensitive)) { continue; } if (file.contains("ivap", Qt::CaseInsensitive)) { conflicts.push_back(file); continue; } if (file.contains("XSquawkBox", Qt::CaseInsensitive)) { conflicts.push_back(file); continue; } } return conflicts; } QStringList CXPlaneUtil::findAllXplFiles(const QString &pluginDir) { const QString dirName = CFileUtils::fixWindowsUncPath(pluginDir.isEmpty() ? xplaneRootDir() : pluginDir); const QDir directory(dirName); if (!directory.exists()) { return QStringList(); } // this finds the current levels XPLs QStringList files = directory.entryList(xplFileFilter(), QDir::Files, QDir::Name | QDir::IgnoreCase); const QStringList dirs = directory.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase); for (const QString &dir : dirs) { const QString subDir = CFileUtils::appendFilePaths(dirName, dir); const QStringList subDirFiles = CXPlaneUtil::findAllXplFiles(subDir); if (subDirFiles.isEmpty()) { continue; } for (const QString &file : subDirFiles) { files.push_back(CFileUtils::appendFilePaths(dir, file)); } } return files; } bool CXPlaneUtil::hasNewerXSwiftBusBuild(const QString &xplaneRootDir) { if (CDirectoryUtils::getXSwiftBusBuildDirectory().isEmpty()) { return false; } const QString xswiftBusPluginDir = CXPlaneUtil::xswiftbusPluginDir(xplaneRootDir); if (xswiftBusPluginDir.isEmpty()) { return false; } const QFileInfo fiLatestBuild = CFileUtils::findLastModified(CDirectoryUtils::getXSwiftBusBuildDirectory(), true, xplFileFilter()); if (!fiLatestBuild.lastModified().isValid()) { return false; } const QFileInfo fiLatestDeployed = CFileUtils::findLastModified(xswiftBusPluginDir, true, xplFileFilter()); if (!fiLatestDeployed.lastModified().isValid()) { return true; } // not yet existing // newer? return fiLatestBuild.lastModified() > fiLatestDeployed.lastModified(); } int CXPlaneUtil::copyXSwiftBusBuildFiles(const QString &xplaneRootDir) { if (CDirectoryUtils::getXSwiftBusBuildDirectory().isEmpty()) { return -1; } const QString xswiftBusPluginDir = CXPlaneUtil::xswiftbusPluginDir(xplaneRootDir); if (xswiftBusPluginDir.isEmpty()) { return -1; } return CDirectoryUtils::copyDirectoryRecursively(CDirectoryUtils::getXSwiftBusBuildDirectory(), xswiftBusPluginDir, true); } const QStringList &CXPlaneUtil::xplFileFilter() { static const QStringList filter({"*.xpl"}); return filter; } } // namespace } // namespace } // namespace