From a19ccabf35ad0dfebf99b904da5ee147648143f9 Mon Sep 17 00:00:00 2001 From: Roland Winklmeier Date: Tue, 21 Aug 2018 15:04:05 +0200 Subject: [PATCH] Refactor shared X-Plane model parser in common header only functions ref T290 --- .../xplane/aircraftmodelloaderxplane.cpp | 90 ++------- .../xplane/aircraftmodelloaderxplane.h | 3 - src/blackmisc/simulation/xplane/qtfreeutils.h | 182 ++++++++++++++++++ src/xswiftbus/aircraftmodel.h | 89 --------- src/xswiftbus/service.cpp | 131 +------------ src/xswiftbus/service.h | 3 - src/xswiftbus/utils.cpp | 60 ------ src/xswiftbus/utils.h | 13 -- 8 files changed, 204 insertions(+), 367 deletions(-) create mode 100644 src/blackmisc/simulation/xplane/qtfreeutils.h delete mode 100644 src/xswiftbus/aircraftmodel.h diff --git a/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.cpp b/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.cpp index b09135cc0..50619802e 100644 --- a/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.cpp +++ b/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.cpp @@ -18,6 +18,7 @@ #include "blackmisc/simulation/distributor.h" #include "blackmisc/simulation/xplane/aircraftmodelloaderxplane.h" #include "blackmisc/simulation/xplane/xplaneutil.h" +#include "blackmisc/simulation/xplane/qtfreeutils.h" #include "blackmisc/statusmessage.h" #include "blackmisc/stringutils.h" #include "blackmisc/worker.h" @@ -62,30 +63,6 @@ namespace BlackMisc } } - //! Create a unique string to identify a model - static QString stringForFlyableModel(const CAircraftModel &model, const QFileInfo &acfFile) - { - if (model.getDistributor().hasDescription()) - { - if (!model.getName().isEmpty()) - { - if (model.getName().contains(model.getDistributor().getDescription())) - { - return model.getName(); - } - else - { - return model.getDistributor().getDescription() % ' ' % model.getName(); - } - } - else if (model.hasAircraftDesignator()) - { - return model.getDistributor().getDescription() % ' ' % model.getAircraftIcaoCodeDesignator(); - } - } - return acfFile.dir().dirName() % ' ' % acfFile.baseName(); - } - //! Create a description string for a model that doesn't already have one static QString descriptionForFlyableModel(const CAircraftModel &model) { @@ -217,7 +194,17 @@ namespace BlackMisc aircraftIt.next(); if (CFileUtils::isExcludedDirectory(aircraftIt.fileInfo(), excludeDirectories, Qt::CaseInsensitive)) { continue; } - CAircraftModel model = this->extractAcfProperties(aircraftIt.filePath(), aircraftIt.fileInfo()); + using namespace BlackMisc::Simulation::XPlane::QtFreeUtils; + AcfProperties acfProperties = extractAcfProperties(aircraftIt.filePath().toStdString()); + + const CDistributor dist({}, QString::fromStdString(acfProperties.author), {}, {}, CSimulatorInfo::XPLANE); + CAircraftModel model; + model.setAircraftIcaoCode(QString::fromStdString(acfProperties.aircraftIcaoCode)); + model.setDescription(QString::fromStdString(acfProperties.modelDescription)); + model.setName(QString::fromStdString(acfProperties.modelName)); + model.setDistributor(dist); + model.setModelString(QString::fromStdString(acfProperties.modelString)); + if (!model.hasDescription()) { model.setDescription(descriptionForFlyableModel(model)); } model.setModelType(CAircraftModel::TypeOwnSimulatorModel); model.setSimulator(CSimulatorInfo::xplane()); model.setFileDetailsAndTimestamp(aircraftIt.fileInfo()); @@ -236,59 +223,6 @@ namespace BlackMisc return installedModels; } - CAircraftModel CAircraftModelLoaderXPlane::extractAcfProperties(const QString &filePath, const QFileInfo &fileInfo) - { - BlackMisc::Simulation::CAircraftModel model; - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return model; } - - QTextStream ts(&file); - if (ts.readLine() == "I" && ts.readLine().contains("version") && ts.readLine() == "ACF") - { - while (!ts.atEnd()) - { - const QString line = ts.readLine(); - QVector tokens = line.splitRef(' ', QString::SkipEmptyParts); - if (tokens.size() < 3 || tokens.at(0) != QLatin1String("P")) { continue; } - if (tokens.at(1) == QLatin1String("acf/_ICAO")) - { - const CAircraftIcaoCode icao(tokens.at(2).toString()); - model.setAircraftIcaoCode(icao); - } - else if (tokens.at(1) == QLatin1String("acf/_descrip")) - { - const QString desc(line.mid(tokens.at(2).position())); - model.setDescription("[ACF] " % desc); - } - else if (tokens.at(1) == QLatin1String("acf/_name")) - { - const QString name(line.mid(tokens.at(2).position())); - model.setName(name); - } - else if (tokens.at(1) == QLatin1String("acf/_studio")) - { - const CDistributor dist({}, line.mid(tokens.at(2).position()), {}, {}, CSimulatorInfo::XPLANE); - model.setDistributor(dist); - } - else if (tokens.at(1) == QLatin1String("acf/_author")) - { - if (model.getDistributor().hasDescription()) { continue; } - thread_local const QRegularExpression end("\\W\\s", QRegularExpression::UseUnicodePropertiesOption); - QString author = line.mid(tokens.at(2).position()); - author = author.left(author.indexOf(end)).trimmed(); - if (author.isEmpty()) { continue; } - const CDistributor dist({}, author, {}, {}, CSimulatorInfo::XPLANE); - model.setDistributor(dist); - } - } - } - file.close(); - - model.setModelString(stringForFlyableModel(model, fileInfo)); - if (!model.hasDescription()) { model.setDescription(descriptionForFlyableModel(model)); } - return model; - } - CAircraftModelList CAircraftModelLoaderXPlane::parseCslPackages(const QString &rootDirectory, const QStringList &excludeDirectories) { Q_UNUSED(excludeDirectories); diff --git a/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.h b/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.h index 54490d21e..da82d0eea 100644 --- a/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.h +++ b/src/blackmisc/simulation/xplane/aircraftmodelloaderxplane.h @@ -54,9 +54,6 @@ namespace BlackMisc //! Parsed or injected models void updateInstalledModels(const CAircraftModelList &models); - //! Extract from an acf file (flyable plane) the properties needed to generate model string. - static CAircraftModel extractAcfProperties(const QString &filePath, const QFileInfo &fileInfo); - protected: //! \name Interface functions //! @{ diff --git a/src/blackmisc/simulation/xplane/qtfreeutils.h b/src/blackmisc/simulation/xplane/qtfreeutils.h new file mode 100644 index 000000000..e751afff5 --- /dev/null +++ b/src/blackmisc/simulation/xplane/qtfreeutils.h @@ -0,0 +1,182 @@ +/* Copyright (C) 2018 + * 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. + */ + +//! \file + +#ifndef BLACKMISC_SIMULATION_XPLANE_XPLANQTFREEUTILS_H +#define BLACKMISC_SIMULATION_XPLANE_XPLANQTFREEUTILS_H + +#include +#include +#include + +// Strict header only X-Plane model parser utils shared between BlackMisc and XSwiftBus. +// Header only is necessary to no require XSwiftBus to link against BlackMisc. + +namespace BlackMisc +{ + namespace Simulation + { + namespace XPlane + { + namespace QtFreeUtils + { + //! Get filename (including all extensions) from a filePath + std::string getFileName(const std::string &filePath) + { + const std::string seperator = "/\\"; + const std::size_t sepPos = filePath.find_last_of(seperator); + if (sepPos != std::string::npos) + { + return filePath.substr(sepPos + 1, filePath.size() - 1); + } + else + { + return filePath; + } + } + + //! Get the name of the parent directory + std::string getDirName(const std::string &filePath) + { + const std::string seperator = "/\\"; + const std::size_t sepPos = filePath.find_last_of(seperator); + if (sepPos != std::string::npos) + { + std::string dirPath = filePath.substr(0, sepPos); + return getFileName(dirPath); + } + else + { + return {}; + } + } + + //! Get the base name of the file + std::string getBaseName(const std::string &filePath) + { + const std::string seperator = "."; + const std::string fileName = getFileName(filePath); + std::size_t sepPos = fileName.find(seperator); + if (sepPos != std::string::npos) + { + return fileName.substr(0, sepPos); + } + else + { + return fileName; + } + } + + //! Split string by delimiter and maxSplitCount times + std::vector split(const std::string &str, size_t maxSplitCount = 0, const std::string &delimiter = " ") + { + std::string s(str); + size_t pos = 0; + std::vector tokens; + while ((pos = s.find(delimiter)) != std::string::npos) + { + tokens.push_back(s.substr(0, pos)); + s.erase(0, pos + delimiter.length()); + if (maxSplitCount > 0 && tokens.size() == maxSplitCount) { break; } + } + tokens.push_back(s); + return tokens; + } + + //! ACF properties + struct AcfProperties + { + std::string aircraftIcaoCode; //!< Aircraft ICAO code + std::string modelDescription; //!< Model description + std::string modelName; //!< Model name + std::string author; //!< Model author + std::string modelString; //!< Generated model string + }; + + //! Get the model string for a flyable aircraft + std::string stringForFlyableModel(const AcfProperties &acfProperties, const std::string &acfFile) + { + if (! acfProperties.author.empty()) + { + if (! acfProperties.modelName.empty()) + { + if (acfProperties.modelName.find(acfProperties.author) != std::string::npos) { return acfProperties.modelName; } + else { return acfProperties.author + ' ' + acfProperties.modelName; } + } + else if (! acfProperties.aircraftIcaoCode.empty()) + { + return acfProperties.author + ' ' + acfProperties.aircraftIcaoCode; + } + } + return getDirName(acfFile) + ' ' + getBaseName(acfFile); + } + + //! Extract ACF properties from an aircraft file + AcfProperties extractAcfProperties(const std::string &filePath) + { + std::ifstream fs(filePath, std::ios::in); + if (!fs.is_open()) { return {}; } + + std::string i; + std::string version; + std::string acf; + std::getline(fs, i); + std::getline(fs, version); + std::getline(fs, acf); + + AcfProperties acfProperties; + + if (i == "I" && version.find("version") != std::string::npos && acf == "ACF") + { + std::string line; + while (std::getline(fs, line)) + { + auto tokens = split(line, 2); + if (tokens.size() < 3 || tokens.at(0) != "P") { continue; } + + if (tokens.at(1) == "acf/_ICAO") + { + acfProperties.aircraftIcaoCode = tokens.at(2); + } + else if (tokens.at(1) == "acf/_descrip") + { + acfProperties.modelDescription = "[ACF] " + tokens.at(2); + } + else if (tokens.at(1) == "acf/_name") + { + acfProperties.modelName = tokens.at(2); + } + else if (tokens.at(1) == "acf/_studio") + { + acfProperties.author = tokens.at(2); + } + else if (tokens.at(1) == "acf/_author") + { + if (!acfProperties.author.empty()) { continue; } + std::string author = tokens.at(2); + size_t pos = author.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"); + author = author.substr(0, pos); + if (author.empty()) { continue; } + acfProperties.author = author; + } + } + } + + fs.close(); + acfProperties.modelString = stringForFlyableModel(acfProperties, filePath); + return acfProperties; + } + } + } // namespace + } // namespace +} // namespace + +#endif // guard + diff --git a/src/xswiftbus/aircraftmodel.h b/src/xswiftbus/aircraftmodel.h deleted file mode 100644 index a9a2bbe5f..000000000 --- a/src/xswiftbus/aircraftmodel.h +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (C) 2018 - * 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. - */ - -//! \file - -#ifndef BLACKSIM_XSWIFTBUS_AIRCRAFTMODEL_H -#define BLACKSIM_XSWIFTBUS_AIRCRAFTMODEL_H - -#include - -namespace XSwiftBus -{ - - //! Simplified implementation of \sa BlackMisc::Simulation::CDistributor - class CDistributor - { - public: - //! Default constructor - CDistributor() = default; - - //! Constructor - CDistributor(const std::string &description) : m_description(description) {} - - //! \copydoc BlackMisc::Simulation::CDistributor::hasDescription - bool hasDescription() const { return !m_description.empty(); } - - //! \copydoc BlackMisc::Simulation::CDistributor::getDescription - std::string getDescription() const { return m_description; } - - private: - std::string m_description; - }; - - //! Simplified implementation of \sa BlackMisc::Simulation::CAircraftModel - class CAircraftModel - { - public: - CAircraftModel() = default; - - //! \copydoc BlackMisc::Simulation::CAircraftModel::hasDescription - bool hasDescription() const { return !m_description.empty(); } - - //! \copydoc BlackMisc::Simulation::CAircraftModel::hasAircraftDesignator - bool hasAircraftDesignator() const { return !m_icao.empty(); } - - //! \copydoc BlackMisc::Simulation::CAircraftModel::getName - std::string getName() const { return m_name; } - - //! \copydoc BlackMisc::Simulation::CAircraftModel::getDistributor - CDistributor getDistributor() const { return m_distributor; } - - //! \copydoc BlackMisc::Simulation::CAircraftModel::getAircraftIcaoCodeDesignator - std::string getAircraftIcaoCodeDesignator() const { return m_icao; } - - //! \copydoc BlackMisc::Simulation::CAircraftModel::getModelString - std::string getModelString() const { return m_modelString; } - - //! \copydoc BlackMisc::Simulation::CAircraftModel::setAircraftIcaoCode - void setAircraftIcaoCode(const std::string &icao) { m_icao = icao; } - - //! \copydoc BlackMisc::Simulation::CAircraftModel::setDescription - void setDescription(const std::string &description) { m_description = description; } - - //! \copydoc BlackMisc::Simulation::CAircraftModel::setName - void setName(const std::string &name) { m_name = name; } - - //! \copydoc BlackMisc::Simulation::CAircraftModel::setDistributor - void setDistributor(const CDistributor &distributor) { m_distributor = distributor; } - - //! \copydoc BlackMisc::Simulation::CAircraftModel::setModelString - void setModelString(const std::string &modelString) { m_modelString = modelString; } - - private: - std::string m_name; - std::string m_icao; - std::string m_description; - CDistributor m_distributor; - std::string m_modelString; - }; - -} - -#endif // guard diff --git a/src/xswiftbus/service.cpp b/src/xswiftbus/service.cpp index 8bad7b89e..3f9467423 100644 --- a/src/xswiftbus/service.cpp +++ b/src/xswiftbus/service.cpp @@ -8,13 +8,15 @@ */ #include "service.h" +#include "utils.h" #include #include -#include -#include "utils.h" +#include "blackmisc/simulation/xplane/qtfreeutils.h" // clazy:excludeall=reserve-candidates +using namespace BlackMisc::Simulation::XPlane::QtFreeUtils; + namespace XSwiftBus { @@ -29,8 +31,8 @@ namespace XSwiftBus char filename[256]; char path[512]; XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path); - const auto model = extractAcfProperties(path); - emitAircraftModelChanged(path, filename, getAircraftLivery(), getAircraftIcaoCode(), model.getModelString(), model.getName(), getAircraftDescription()); + AcfProperties acfProperties = extractAcfProperties(path); + emitAircraftModelChanged(path, filename, getAircraftLivery(), getAircraftIcaoCode(), acfProperties.modelString, acfProperties.modelName, getAircraftDescription()); } void CService::addTextMessage(const std::string &text, double red, double green, double blue) @@ -81,8 +83,8 @@ namespace XSwiftBus char filename[256]; char path[512]; XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path); - const auto model = extractAcfProperties(path); - return model.getModelString(); + const AcfProperties acfProperties = extractAcfProperties(path); + return acfProperties.modelString; } std::string CService::getAircraftName() const @@ -90,8 +92,8 @@ namespace XSwiftBus char filename[256]; char path[512]; XPLMGetNthAircraftModel(XPLM_USER_AIRCRAFT, filename, path); - const auto model = extractAcfProperties(path); - return model.getName(); + const AcfProperties acfProperties = extractAcfProperties(path); + return acfProperties.modelName; } int CService::getXPlaneVersionMajor() const @@ -672,117 +674,4 @@ namespace XSwiftBus return closestAirports; } - //! Qt free version of BlackMisc::Simulation::XPlane::descriptionForFlyableModel() - std::string descriptionForFlyableModel(const CAircraftModel &model) - { - if (!model.getName().empty()) - { - if (model.getDistributor().hasDescription() && model.getName().find(model.getDistributor().getDescription()) == std::string::npos) - { - return std::string("[ACF] ") + model.getName() + " by " + model.getDistributor().getDescription(); - } - else - { - return std::string("[ACF] ") + model.getName(); - } - } - else if (model.hasAircraftDesignator()) - { - if (model.getDistributor().hasDescription()) - { - return std::string("[ACF] ") + model.getAircraftIcaoCodeDesignator() + " by " + model.getDistributor().getDescription(); - } - else - { - return std::string("[ACF] ") + model.getAircraftIcaoCodeDesignator(); - } - } - return std::string("[ACF]"); - } - - //! Qt free version of BlackMisc::Simulation::XPlane::stringForFlyableModel() - std::string stringForFlyableModel(const CAircraftModel &model, const std::string &acfFile) - { - if (model.getDistributor().hasDescription()) - { - if (!model.getName().empty()) - { - if (model.getName().find(model.getDistributor().getDescription()) != std::string::npos) - { - return model.getName(); - } - else - { - return model.getDistributor().getDescription() + ' ' + model.getName(); - } - } - else if (model.hasAircraftDesignator()) - { - return model.getDistributor().getDescription() + ' ' + model.getAircraftIcaoCodeDesignator(); - } - } - return getDirName(acfFile) + ' ' + getBaseName(acfFile); - } - - CAircraftModel CService::extractAcfProperties(const std::string &filePath) - { - CAircraftModel model; - - std::ifstream fs(filePath, std::ios::in | std::ios::binary); - if (!fs.is_open()) { return model; } - - std::string i; - std::string version; - std::string acf; - std::getline(fs, i); - std::getline(fs, version); - std::getline(fs, acf); - - if (i == "I" && version.find("version") != std::string::npos && acf == "ACF") - { - std::string line; - while (std::getline(fs, line)) - { - auto tokens = split(line, 2); - if (tokens.size() < 3 || tokens.at(0) != "P") { continue; } - if (tokens.at(1) == "acf/_ICAO") - { - const std::string icao(tokens.at(2)); - model.setAircraftIcaoCode(icao); - } - else if (tokens.at(1) == "acf/_descrip") - { - const std::string desc(tokens.at(2)); - model.setDescription("[ACF] " + desc); - } - else if (tokens.at(1) == "acf/_name") - { - const std::string name(tokens.at(2)); - model.setName(name); - } - else if (tokens.at(1) == "acf/_studio") - { - const CDistributor dist(tokens.at(2)); - model.setDistributor(dist); - } - else if (tokens.at(1) == "acf/_author") - { - if (model.getDistributor().hasDescription()) { continue; } - std::string author = tokens.at(2); - size_t pos = author.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"); - author = author.substr(0, pos); - if (author.empty()) { continue; } - const CDistributor dist(author); - model.setDistributor(dist); - } - } - } - - fs.close(); - - model.setModelString(stringForFlyableModel(model, filePath)); - if (!model.hasDescription()) { model.setDescription(descriptionForFlyableModel(model)); } - return model; - } - } diff --git a/src/xswiftbus/service.h b/src/xswiftbus/service.h index 53ac89f0f..63b0e07ac 100644 --- a/src/xswiftbus/service.h +++ b/src/xswiftbus/service.h @@ -20,7 +20,6 @@ #include "datarefs.h" #include "messages.h" #include "navdatareference.h" -#include "aircraftmodel.h" #include #include @@ -246,8 +245,6 @@ namespace XSwiftBus std::vector findClosestAirports(int number, double latitude, double longitude); - static CAircraftModel extractAcfProperties(const std::string &filePath); - StringDataRef m_liveryPath; StringDataRef m_icao; StringDataRef m_descrip; diff --git a/src/xswiftbus/utils.cpp b/src/xswiftbus/utils.cpp index bcec731c4..8b9185c19 100644 --- a/src/xswiftbus/utils.cpp +++ b/src/xswiftbus/utils.cpp @@ -43,66 +43,6 @@ namespace XSwiftBus g_xplanePath = xplanePath; } - std::string getDirName(const std::string &filePath) - { - std::string seperator = "/\\"; - std::size_t sepPos = filePath.find_last_of(seperator); - if (sepPos != std::string::npos) - { - std::string dirPath = filePath.substr(0, sepPos); - return getFileName(dirPath); - } - else - { - return {}; - } - } - - std::string getFileName(const std::string &filePath) - { - std::string seperator = "/\\"; - std::size_t sepPos = filePath.find_last_of(seperator); - if (sepPos != std::string::npos) - { - return filePath.substr(sepPos + 1, filePath.size() - 1); - } - else - { - return filePath; - } - } - - std::string getBaseName(const std::string &filePath) - { - std::string seperator = "."; - std::string fileName = getFileName(filePath); - std::size_t sepPos = fileName.find(seperator); - if (sepPos != std::string::npos) - { - return fileName.substr(0, sepPos); - } - else - { - return fileName; - } - } - - std::vector split(const std::string &str, size_t maxSplitCount) - { - std::string s(str); - std::string delimiter = " "; - size_t pos = 0; - std::vector tokens; - while ((pos = s.find(delimiter)) != std::string::npos) - { - tokens.push_back(s.substr(0, pos)); - s.erase(0, pos + delimiter.length()); - if (tokens.size() == maxSplitCount) { break; } - } - tokens.push_back(s); - return tokens; - } - void Logger::print(const std::string &filePath, int line, MsgType type, const std::string &message) { (void) line; diff --git a/src/xswiftbus/utils.h b/src/xswiftbus/utils.h index 9ccf1c426..642a115d6 100644 --- a/src/xswiftbus/utils.h +++ b/src/xswiftbus/utils.h @@ -26,19 +26,6 @@ namespace XSwiftBus //! Init global xplane path void initXPlanePath(); - //! Returns the directory name of a given file path - std::string getDirName(const std::string &filePath); - - //! Returns the filename (including extension) of a given file path - std::string getFileName(const std::string &filePath); - - //! Returns the filename without extension of a given file path - std::string getBaseName(const std::string &filePath); - - //! Splits the given string maximal maxSplitCount times and returns the tokens - //! The size of the returned vector is up to maxSplitCount + 1 or less - std::vector split(const std::string &str, size_t maxSplitCount = 0); - //! Simple logger class. //! Don't use it directly, but the _LOG macros instead class Logger