From 51494ed6dfe32edbcdc29bc2095b6260baed180a Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Fri, 30 Jun 2023 00:24:42 -0400 Subject: [PATCH 01/29] Remove culled database tables/columns --- CMakeLists.txt | 2 +- lib/include/fp/fp-db.h | 83 +++------------ lib/src/fp-db.cpp | 231 +---------------------------------------- 3 files changed, 20 insertions(+), 296 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5c811ec..c5a08ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ set(LIBFP_QX_COMPONENTS include(OB/FetchQx) ob_fetch_qx( - REF "v0.5.0.1" + REF "84585805c3d085eb469a04558cc2a76c4de91849" COMPONENTS ${LIBFP_QX_COMPONENTS} ) diff --git a/lib/include/fp/fp-db.h b/lib/include/fp/fp-db.h index 5e4e008..30708d0 100644 --- a/lib/include/fp/fp-db.h +++ b/lib/include/fp/fp-db.h @@ -35,7 +35,6 @@ class FP_FP_EXPORT Db : public QObject static inline const QString COL_PUBLISHER = "publisher"; static inline const QString COL_DATE_ADDED = "dateAdded"; static inline const QString COL_DATE_MODIFIED = "dateModified"; - static inline const QString COL_PLATFORM = "platform"; static inline const QString COL_BROKEN = "broken"; static inline const QString COL_EXTREME = "extreme"; static inline const QString COL_PLAY_MODE = "playMode"; @@ -50,10 +49,11 @@ class FP_FP_EXPORT Db : public QObject static inline const QString COL_LANGUAGE = "language"; static inline const QString COL_LIBRARY = "library"; static inline const QString COL_ORDER_TITLE = "orderTitle"; + static inline const QString COL_PLATFORM_NAME = "platformName"; - static inline const QStringList COLUMN_LIST = {COL_ID, COL_TITLE, COL_SERIES, COL_DEVELOPER, COL_PUBLISHER, COL_DATE_ADDED, COL_DATE_MODIFIED, COL_PLATFORM, + static inline const QStringList COLUMN_LIST = {COL_ID, COL_PARENT_ID, COL_TITLE, COL_SERIES, COL_DEVELOPER, COL_PUBLISHER, COL_DATE_ADDED, COL_DATE_MODIFIED, COL_BROKEN, COL_EXTREME, COL_PLAY_MODE, COL_STATUS, COL_NOTES, COL_SOURCE, COL_APP_PATH, COL_LAUNCH_COMMAND, COL_RELEASE_DATE, - COL_VERSION, COL_ORIGINAL_DESC, COL_LANGUAGE, COL_LIBRARY, COL_ORDER_TITLE}; + COL_VERSION, COL_ORIGINAL_DESC, COL_LANGUAGE, COL_LIBRARY, COL_ORDER_TITLE, COL_PLATFORM_NAME}; static inline const QString ENTRY_GAME_LIBRARY = "arcade"; static inline const QString ENTRY_ANIM_LIBRARY = "theatre"; @@ -98,62 +98,6 @@ class FP_FP_EXPORT Db : public QObject static inline const QString ENTRY_MESSAGE = ":message:"; }; - class Table_Playlist - { - public: - static inline const QString NAME = "playlist"; - static inline const QString COL_ID = "id"; - static inline const QString COL_TITLE = "title"; - static inline const QString COL_DESCRIPTION = "description"; - static inline const QString COL_AUTHOR = "author"; - static inline const QString COL_LIBRARY = "library"; - - static inline const QString ENTRY_GAME_LIBRARY = "arcade"; - - static inline const QStringList COLUMN_LIST = {COL_ID, COL_TITLE, COL_DESCRIPTION, COL_AUTHOR, COL_LIBRARY}; - }; - - class Table_Playlist_Game - { - public: - static inline const QString NAME = "playlist_game"; - - static inline const QString COL_ID = "id"; - static inline const QString COL_PLAYLIST_ID = "playlistId"; - static inline const QString COL_ORDER = "order"; - static inline const QString COL_GAME_ID = "gameId"; - - static inline const QStringList COLUMN_LIST = {COL_ID, COL_PLAYLIST_ID, COL_ORDER, COL_GAME_ID}; - }; - - class Table_Source - { - public: - static inline const QString NAME = "source"; - - static inline const QString COL_ID = "id"; - static inline const QString COL_NAME = "name"; - static inline const QString COL_DATE_ADDED = "dateAdded"; - static inline const QString COL_LAST_UPDATED = "lastUpdated"; - static inline const QString COL_SRC_FILE_URL = "sourceFileUrl"; - static inline const QString COL_BASE_URL = "baseUrl"; - static inline const QString COL_COUNT = "count"; - - static inline const QStringList COLUMN_LIST = {COL_ID, COL_NAME, COL_DATE_ADDED, COL_LAST_UPDATED, COL_SRC_FILE_URL, COL_BASE_URL, COL_COUNT}; - }; - - class Table_Source_Data - { - public: - static inline const QString NAME = "source_data"; - - static inline const QString COL_ID = "id"; - static inline const QString COL_SOURCE_ID = "sourceId"; - static inline const QString COL_SHA256 = "sha256"; - static inline const QString COL_URL_PATH = "urlPath"; - - static inline const QStringList COLUMN_LIST = {COL_ID, COL_SOURCE_ID, COL_SHA256, COL_URL_PATH}; - }; class Table_Game_Tags_Tag { @@ -271,10 +215,17 @@ class FP_FP_EXPORT Db : public QObject private: static inline const QString DATABASE_CONNECTION_NAME = "flashpoint_database"; - static inline const QList DATABASE_SPECS_LIST = {{Db::Table_Game::NAME, Db::Table_Game::COLUMN_LIST}, - {Db::Table_Add_App::NAME, Db::Table_Add_App::COLUMN_LIST}, - {Db::Table_Playlist::NAME, Db::Table_Playlist::COLUMN_LIST}, - {Db::Table_Playlist_Game::NAME, Db::Table_Playlist_Game::COLUMN_LIST}}; + // TODO: Self register this somehow so that it doesnt need to be modified when tables are added or removed. + // Might require wrapping tables in actual classes + static inline const QList DATABASE_SPECS_LIST = { + {Db::Table_Game::NAME, Db::Table_Game::COLUMN_LIST}, + {Db::Table_Add_App::NAME, Db::Table_Add_App::COLUMN_LIST}, + {Db::Table_Game_Data::NAME, Db::Table_Game_Data::COLUMN_LIST}, + {Db::Table_Game_Tags_Tag::NAME, Db::Table_Game_Tags_Tag::COLUMN_LIST}, + {Db::Table_Tag::NAME, Db::Table_Tag::COLUMN_LIST}, + {Db::Table_Tag_Alias::NAME, Db::Table_Tag_Alias::COLUMN_LIST}, + {Db::Table_Tag_Category::NAME, Db::Table_Tag_Category::COLUMN_LIST}, + }; static inline const QString GENERAL_QUERY_SIZE_COMMAND = "COUNT(1)"; static inline const QString GAME_ONLY_FILTER = Db::Table_Game::COL_LIBRARY + " = '" + Db::Table_Game::ENTRY_GAME_LIBRARY + "'"; @@ -339,21 +290,15 @@ class FP_FP_EXPORT Db : public QObject QSqlError queryGamesByPlatform(QList& resultBuffer, QStringList platforms, InclusionOptions inclusionOptions, std::optional*> idInclusionFilter = std::nullopt); QSqlError queryAllAddApps(QueryBuffer& resultBuffer); - QSqlError queryPlaylistsByName(QueryBuffer& resultBuffer, QStringList playlists, InclusionOptions inclusionOptions); - QSqlError queryPlaylistGamesByPlaylist(QList& resultBuffer, const QList& playlistIds); - QSqlError queryPlaylistGameIds(QueryBuffer& resultBuffer, const QList& playlistIds); QSqlError queryAllEntryTags(QueryBuffer& resultBuffer); // Queries - CLIFp QSqlError queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter); QSqlError queryEntryDataById(QueryBuffer& resultBuffer, QUuid appId); - QSqlError queryDataPackSource(QueryBuffer& resultBuffer); - QSqlError queryEntrySourceData(QueryBuffer& resultBuffer, QString appSha256Hex); QSqlError queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter filter); // Info QStringList platformList() const; - QStringList playlistList() const; QMap tags() const; // Checks diff --git a/lib/src/fp-db.cpp b/lib/src/fp-db.cpp index 6034eb8..354df6a 100644 --- a/lib/src/fp-db.cpp +++ b/lib/src/fp-db.cpp @@ -292,7 +292,7 @@ QSqlError Db::populateAvailableItems() mPlaylistList.clear(); // Make platform query - QSqlQuery platformQuery("SELECT DISTINCT " + Table_Game::COL_PLATFORM + " FROM " + Table_Game::NAME, fpDb); + QSqlQuery platformQuery("SELECT DISTINCT " + Table_Game::COL_PLATFORM_NAME + " FROM " + Table_Game::NAME, fpDb); // Return if error occurs if(platformQuery.lastError().isValid()) @@ -300,25 +300,11 @@ QSqlError Db::populateAvailableItems() // Parse query while(platformQuery.next()) - mPlatformList.append(platformQuery.value(Table_Game::COL_PLATFORM).toString()); + mPlatformList.append(platformQuery.value(Table_Game::COL_PLATFORM_NAME).toString()); // Sort list mPlatformList.sort(); - // Make playlist query - QSqlQuery playlistQuery("SELECT DISTINCT " + Table_Playlist::COL_TITLE + " FROM " + Table_Playlist::NAME, fpDb); - - // Return if error occurs - if(playlistQuery.lastError().isValid()) - return playlistQuery.lastError(); - - // Parse query - while(playlistQuery.next()) - mPlaylistList.append(playlistQuery.value(Db::Table_Playlist::COL_TITLE).toString()); - - // Sort list - mPlaylistList.sort(); - // Return invalid SqlError return QSqlError(); } @@ -425,7 +411,7 @@ QSqlError Db::queryGamesByPlatform(QList& resultBuffer, QStringList // Create platform query string QString placeholder = ":platform"; QString baseQueryCommand = "SELECT %1 FROM " + Table_Game::NAME + " WHERE " + - Table_Game::COL_PLATFORM + " = " + placeholder + " AND "; + Table_Game::COL_PLATFORM_NAME + " = " + placeholder + " AND "; // Handle filtering QString filteredQueryCommand = baseQueryCommand.append(inclusionOptions.includeAnimations ? GAME_AND_ANIM_FILTER : GAME_ONLY_FILTER); @@ -498,165 +484,6 @@ QSqlError Db::queryAllAddApps(QueryBuffer& resultBuffer) return makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand); } -QSqlError Db::queryPlaylistsByName(QueryBuffer& resultBuffer, QStringList playlists, InclusionOptions inclusionOptions) -{ - // Return blank result if no playlists are selected - if(playlists.isEmpty()) - { - resultBuffer.source = QString(); - resultBuffer.result = QSqlQuery(); - resultBuffer.size = 0; - - return QSqlError(); - } - else - { - // Ensure return buffer is effectively null - resultBuffer = QueryBuffer(); - - // Get database - QSqlDatabase fpDb; - QSqlError dbError = getThreadConnection(fpDb); - if(dbError.isValid()) - return dbError; - - // Create selected playlists query string - QString placeHolders = QString("?,").repeated(playlists.size()); - placeHolders.chop(1); // Remove trailing ? - QString baseQueryCommand = "SELECT %1 FROM " + Table_Playlist::NAME + " WHERE " + - Table_Playlist::COL_TITLE + " IN (" + placeHolders + ") AND " + - (inclusionOptions.includeAnimations ? GAME_AND_ANIM_FILTER : GAME_ONLY_FILTER); - QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Playlist::COLUMN_LIST.join("`,`") + "`"); - QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); - - // Create main query and bind selected playlists - QSqlQuery mainQuery(fpDb); - mainQuery.setForwardOnly(true); - mainQuery.prepare(mainQueryCommand); - for(const QString& playlist : playlists) - mainQuery.addBindValue(playlist); - - // Execute query and return if error occurs - if(!mainQuery.exec()) - return mainQuery.lastError(); - - // Create size query and bind selected playlists - QSqlQuery sizeQuery(fpDb); - sizeQuery.setForwardOnly(true); - sizeQuery.prepare(sizeQueryCommand); - for(const QString& playlist : playlists) - sizeQuery.addBindValue(playlist); - - // Execute query and return if error occurs - if(!sizeQuery.exec()) - return sizeQuery.lastError(); - - // Get query size - sizeQuery.next(); - int querySize = sizeQuery.value(0).toInt(); - - // Set buffer instance to result - resultBuffer.source = Table_Playlist::NAME; - resultBuffer.result = mainQuery; - resultBuffer.size = querySize; - - // Return invalid SqlError - return QSqlError(); - } -} - -QSqlError Db::queryPlaylistGamesByPlaylist(QList& resultBuffer, const QList& playlistIds) -{ - // Ensure return buffer is empty - resultBuffer.clear(); - - // Get database - QSqlDatabase fpDb; - QSqlError dbError = getThreadConnection(fpDb); - if(dbError.isValid()) - return dbError; - - for(QUuid playlistId : playlistIds) // Naturally returns empty list if no playlists are selected - { - // Query all games for the current playlist - QString baseQueryCommand = "SELECT %1 FROM " + Table_Playlist_Game::NAME + " WHERE " + - Table_Playlist_Game::COL_PLAYLIST_ID + " = '" + playlistId.toString(QUuid::WithoutBraces) + "'"; - QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Playlist_Game::COLUMN_LIST.join("`,`") + "`"); - QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); - - // Make query - QSqlError queryError; - QueryBuffer queryResult; - queryResult.source = playlistId.toString(); - - if((queryError = makeNonBindQuery(queryResult, &fpDb, mainQueryCommand, sizeQueryCommand)).isValid()) - return queryError; - - // Add result to buffer if there were any hits - if(queryResult.size > 0) - resultBuffer.append(queryResult); - } - - // Return invalid SqlError - return QSqlError(); -} - -QSqlError Db::queryPlaylistGameIds(QueryBuffer& resultBuffer, const QList& playlistIds) -{ - // Ensure return buffer is empty - resultBuffer = QueryBuffer(); - - // Get database - QSqlDatabase fpDb; - QSqlError dbError = getThreadConnection(fpDb); - if(dbError.isValid()) - return dbError; - - // Create playlist ID query string - QString idCSV = Qx::String::join(playlistIds, [](QUuid id){return id.toString(QUuid::WithoutBraces);}, "','"); - - // Query all game IDs that fall under given the playlists - QString baseQueryCommand = "SELECT %1 FROM " + Table_Playlist_Game::NAME + " WHERE " + - Table_Playlist_Game::COL_PLAYLIST_ID + " IN('" + idCSV + "')"; - QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Playlist_Game::COL_GAME_ID + "`"); - QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); - - // Make query - QSqlError queryError; - resultBuffer.source = Table_Playlist_Game::NAME; - - if((queryError = makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand)).isValid()) - return queryError; - - // Return invalid SqlError - return QSqlError(); - -} - -QSqlError Db::queryAllEntryTags(QueryBuffer& resultBuffer) -{ - // Ensure return buffer is empty - resultBuffer = QueryBuffer(); - - // Get database - QSqlDatabase fpDb; - QSqlError dbError = getThreadConnection(fpDb); - if(dbError.isValid()) - return dbError; - - // Query all tags tied to game IDs - QString baseQueryCommand = "SELECT %1 FROM " + Table_Game_Tags_Tag::NAME; - QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Game_Tags_Tag::COL_GAME_ID + "`"); - QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); - - // Make query - QSqlError queryError; - resultBuffer.source = Table_Playlist_Game::NAME; - - // Return invalid SqlError - return makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand); -} - QSqlError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) { // Ensure return buffer is effectively null @@ -805,53 +632,6 @@ QSqlError Db::queryEntryDataById(QueryBuffer& resultBuffer, QUuid appId) return makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand); } -QSqlError Db::queryDataPackSource(QueryBuffer& resultBuffer) -{ - // Ensure return buffer is effectively null - resultBuffer = QueryBuffer(); - - // Get database - QSqlDatabase fpDb; - QSqlError dbError = getThreadConnection(fpDb); - if(dbError.isValid()) - return dbError; - - // Setup ID query - QString baseQueryCommand = "SELECT %1 FROM " + Table_Source::NAME; - QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Source::COLUMN_LIST.join("`,`") + "`"); - QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); - - // Make query - QSqlError queryError; - resultBuffer.source = Table_Source::NAME; - - return makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand); -} - -QSqlError Db::queryEntrySourceData(QueryBuffer& resultBuffer, QString appSha256Hex) -{ - // Ensure return buffer is effectively null - resultBuffer = QueryBuffer(); - - // Get database - QSqlDatabase fpDb; - QSqlError dbError = getThreadConnection(fpDb); - if(dbError.isValid()) - return dbError; - - // Setup ID query - QString baseQueryCommand = "SELECT %1 FROM " + Table_Source_Data::NAME + " WHERE " + - Table_Source_Data::COL_SHA256 + " == '" + appSha256Hex + "'"; - QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Source_Data::COLUMN_LIST.join("`,`") + "`"); - QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); - - // Make query - QSqlError queryError; - resultBuffer.source = Table_Source_Data::NAME; - - return makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand); -} - QSqlError Db::queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter includeFilter) { // Ensure return buffer is effectively null @@ -874,14 +654,13 @@ QSqlError Db::queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter includeFi return makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand); } -QStringList Db::platformList() const { return mPlatformList; } -QStringList Db::playlistList() const { return mPlaylistList; } +QStringList Db::platformList() const { return mPlatformList; } //TODO: Probably should use RAII for this. QMap Db::tags() const { return mTagMap; } QSqlError Db::entryUsesDataPack(bool& resultBuffer, QUuid gameId) { /* NOTE: The launcher performs this check and other data pack tasks by checking if the `activeDataId` column - * of the `game` table has a value, and if it does that matching that to the `id` column in the `game_data` + * of the `game` table has a value, and if it does, then matching that to the `id` column in the `game_data` * table to get the game's data pack info. This requires slightly less processing, but the way it's done here * is ultimately fine and technically handles typos/errors in the database slightly better since it's a more * direct check. Ultimately this should be switched over to the official method though. From 36c0e42e12847d3d5dec8e46ed55a7e82b5474ba Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Mon, 3 Jul 2023 16:14:42 -0400 Subject: [PATCH 02/29] Reorganize settings related files, account for JSON changes --- CMakeLists.txt | 2 +- lib/CMakeLists.txt | 14 +- lib/include/fp/fp-install.h | 21 +- lib/include/fp/fp-items.h | 6 +- lib/include/fp/fp-json.h | 262 ------------- lib/include/fp/settings/fp-config.h | 30 ++ lib/include/fp/settings/fp-execs.h | 41 ++ lib/include/fp/settings/fp-preferences.h | 76 ++++ lib/include/fp/settings/fp-services.h | 71 ++++ lib/include/fp/settings/fp-settings.h | 60 +++ lib/src/fp-install.cpp | 20 +- lib/src/fp-items.cpp | 4 +- lib/src/fp-json.cpp | 479 ----------------------- lib/src/settings/fp-config.cpp | 49 +++ lib/src/settings/fp-execs.cpp | 91 +++++ lib/src/settings/fp-preferences.cpp | 275 +++++++++++++ lib/src/settings/fp-services.cpp | 253 ++++++++++++ lib/src/settings/fp-settings.cpp | 72 ++++ 18 files changed, 1057 insertions(+), 769 deletions(-) delete mode 100644 lib/include/fp/fp-json.h create mode 100644 lib/include/fp/settings/fp-config.h create mode 100644 lib/include/fp/settings/fp-execs.h create mode 100644 lib/include/fp/settings/fp-preferences.h create mode 100644 lib/include/fp/settings/fp-services.h create mode 100644 lib/include/fp/settings/fp-settings.h delete mode 100644 lib/src/fp-json.cpp create mode 100644 lib/src/settings/fp-config.cpp create mode 100644 lib/src/settings/fp-execs.cpp create mode 100644 lib/src/settings/fp-preferences.cpp create mode 100644 lib/src/settings/fp-services.cpp create mode 100644 lib/src/settings/fp-settings.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c5a08ad..29359a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ set(LIBFP_QX_COMPONENTS include(OB/FetchQx) ob_fetch_qx( - REF "84585805c3d085eb469a04558cc2a76c4de91849" + REF "90098afc6b84ce0c833fa0121235b9eafd2211e6" COMPONENTS ${LIBFP_QX_COMPONENTS} ) diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 2ba5d8f..3de6d3e 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -11,14 +11,22 @@ ob_add_standard_library(${LIB_TARGET_NAME} fp-db.h fp-install.h fp-items.h - fp-json.h fp-macro.h + settings/fp-config.h + settings/fp-execs.h + settings/fp-preferences.h + settings/fp-services.h + settings/fp-settings.h IMPLEMENTATION fp-db.cpp fp-install.cpp - fp-items.cpp - fp-json.cpp fp-macro.cpp + fp-items.cpp + settings/fp-config.cpp + settings/fp-execs.cpp + settings/fp-preferences.cpp + settings/fp-services.cpp + settings/fp-settings.cpp LINKS PUBLIC Qt6::Core diff --git a/lib/include/fp/fp-install.h b/lib/include/fp/fp-install.h index 4ac4ba1..b327c49 100644 --- a/lib/include/fp/fp-install.h +++ b/lib/include/fp/fp-install.h @@ -14,7 +14,10 @@ #include // Project Includes -#include "fp/fp-json.h" +#include "fp/settings/fp-config.h" +#include "fp/settings/fp-execs.h" +#include "fp/settings/fp-preferences.h" +#include "fp/settings/fp-services.h" #include "fp/fp-macro.h" #include "fp/fp-db.h" #include "fp/fp-items.h" @@ -96,10 +99,10 @@ enum class Edition {Ultimate, Infinity, Core}; std::unique_ptr mVersionFile; // Settings - Json::Config mConfig; - Json::Preferences mPreferences; - Json::Services mServices; - Json::Execs mExecs; + Config mConfig; + Preferences mPreferences; + Services mServices; + Execs mExecs; // Database Db* mDatabase = nullptr; @@ -142,10 +145,10 @@ enum class Edition {Ultimate, Infinity, Core}; // Support Application Checks // TODO: At some point create a "Settings" object that wraps all of these, would need to rename existing Fp::Settings - const Json::Config& config() const; - const Json::Preferences& preferences() const; - const Json::Services& services() const; - const Json::Execs& execs() const; + const Config& config() const; + const Preferences& preferences() const; + const Services& services() const; + const Execs& execs() const; // Data access QString fullPath() const; diff --git a/lib/include/fp/fp-items.h b/lib/include/fp/fp-items.h index aa41f26..ce0f748 100644 --- a/lib/include/fp/fp-items.h +++ b/lib/include/fp/fp-items.h @@ -30,7 +30,6 @@ class FP_FP_EXPORT Game QString mPublisher; QDateTime mDateAdded; QDateTime mDateModified; - QString mPlatform; bool mBroken; QString mPlayMode; QString mStatus; @@ -44,6 +43,7 @@ class FP_FP_EXPORT Game QString mLanguage; QString mOrderTitle; QString mLibrary; + QString mPlatformName; //-Constructor------------------------------------------------------------------------------------------------- public: @@ -58,7 +58,6 @@ class FP_FP_EXPORT Game QString publisher() const; QDateTime dateAdded() const; QDateTime dateModified() const; - QString platform() const; bool isBroken() const; QString playMode() const; QString status() const; @@ -72,6 +71,7 @@ class FP_FP_EXPORT Game QString language() const; QString orderTitle() const; QString library() const; + QString platformName() const; }; class FP_FP_EXPORT Game::Builder @@ -97,7 +97,6 @@ class FP_FP_EXPORT Game::Builder Builder& wPublisher(QString publisher); Builder& wDateAdded(QString rawDateAdded); Builder& wDateModified(QString rawDateModified); - Builder& wPlatform(QString platform); Builder& wBroken(QString rawBroken); Builder& wPlayMode(QString playMode); Builder& wStatus(QString status); @@ -111,6 +110,7 @@ class FP_FP_EXPORT Game::Builder Builder& wLanguage(QString language); Builder& wOrderTitle(QString orderTitle); Builder& wLibrary(QString library); + Builder& wPlatformName(QString platformName); Game build(); }; diff --git a/lib/include/fp/fp-json.h b/lib/include/fp/fp-json.h deleted file mode 100644 index 2260d3b..0000000 --- a/lib/include/fp/fp-json.h +++ /dev/null @@ -1,262 +0,0 @@ -#ifndef FLASHPOINT_JSON_H -#define FLASHPOINT_JSON_H - -// Shared Lib Support -#include "fp/fp_export.h" - -// Qt Includes -#include -#include -#include - -// Qx Includes -#include - -// Project Includes -#include "fp/fp-macro.h" - -/* Remove the ancient built-in 'linux' define to avoid clash with exec.linux. - * No one should still be using it anyway and instead using __linux__. - */ -#undef linux - -namespace Fp -{ - -enum KnownDaemon{ - None = 0x0, - Docker = 0x1, - Qemu = 0x2 -}; -Q_DECLARE_FLAGS(KnownDaemons, KnownDaemon); -Q_DECLARE_OPERATORS_FOR_FLAGS(KnownDaemons); - -class FP_FP_EXPORT Json -{ -//-Inner Classes------------------------------------------------------------------------------------------------- -private: - class Object_Config - { - public: - static inline const QString KEY_FLASHPOINT_PATH = "flashpointPath"; // Reading this value is current redundant and unused, but this may change in the future - static inline const QString KEY_START_SERVER = "startServer"; - static inline const QString KEY_SERVER = "server"; - }; - - class Object_AppPathOverrides - { - public: - static inline const QString KEY_PATH = "path"; - static inline const QString KEY_OVERRIDE = "override"; - static inline const QString KEY_ENABLED = "enabled"; - }; - - class Object_Preferences - { - public: - static inline const QString KEY_IMAGE_FOLDER_PATH = "imageFolderPath"; - static inline const QString KEY_JSON_FOLDER_PATH = "jsonFolderPath"; - static inline const QString KEY_HTDOCS_FOLDER_PATH = "htdocsFolderPath"; - static inline const QString KEY_DATA_PACKS_FOLDER_PATH = "dataPacksFolderPath"; - static inline const QString KEY_ON_DEMAND_IMAGES = "onDemandImages"; - static inline const QString KEY_ON_DEMAND_BASE_URL = "onDemandBaseUrl"; - static inline const QString KEY_APP_PATH_OVERRIDES = "appPathOverrides"; - static inline const QString KEY_NATIVE_PLATFORMS = "nativePlatforms"; - static inline const QString KEY_BROWSER_MODE_PROXY = "browserModeProxy"; - }; - - class Object_ServerDaemon - { - public: - static inline const QString KEY_NAME = "name"; - static inline const QString KEY_PATH = "path"; - static inline const QString KEY_FILENAME = "filename"; - static inline const QString KEY_ARGUMENTS = "arguments"; - static inline const QString KEY_KILL = "kill"; - }; - - class Object_StartStop - { - public: - static inline const QString KEY_PATH = "path"; - static inline const QString KEY_FILENAME = "filename"; - static inline const QString KEY_ARGUMENTS = "arguments"; - }; - - class Object_Services - { - public: - static inline const QString KEY_WATCH = "watch"; - static inline const QString KEY_SERVER = "server"; - static inline const QString KEY_DAEMON = "daemon"; - static inline const QString KEY_START = "start"; - static inline const QString KEY_STOP = "stop"; - }; - - class Object_Execs - { - public: - static inline const QString KEY_EXECS = "execs"; - }; - - class Object_Exec - { - public: - static inline const QString KEY_WIN32 = "win32"; - static inline const QString KEY_LINUX = "linux"; - static inline const QString KEY_WINE = "wine"; - }; - - struct Settings {}; - -public: - struct ServerDaemon - { - QString name; - QString path; - QString filename; - QStringList arguments; - bool kill; - }; - - struct StartStop - { - QString path; - QString filename; - QStringList arguments; - - friend bool operator== (const StartStop& lhs, const StartStop& rhs) noexcept; - friend size_t qHash(const StartStop& key, size_t seed) noexcept; - }; - - struct Config : public Settings - { - QString flashpointPath; - bool startServer; - QString server; - }; - - struct AppPathOverride - { - QString path; - QString override; - bool enabled; - }; - - struct Preferences : public Settings - { - QString imageFolderPath; - QString jsonFolderPath; - QString htdocsFolderPath; - QString dataPacksFolderPath; - bool onDemandImages; - QString onDemandBaseUrl; - QList appPathOverrides; - QSet nativePlatforms; - QString browserModeProxy; - }; - - struct Services : public Settings - { - //QSet watches; - QHash servers; - QHash daemons; - QSet starts; - QSet stops; - KnownDaemons recognizedDaemons; // Non-standard - // TODO: If Settings container obj is made (see other todo), move this there - }; - - struct Exec - { - QString linux; - QString win32; - QString wine; - }; - - struct Execs : public Settings - { - QList list; - }; - - class SettingsReader - { - //-Class variables----------------------------------------------------------------------------------------------------- - public: - static inline const QString ERR_PARSING_JSON_DOC = "Error parsing JSON Document: %1"; - static inline const QString ERR_JSON_UNEXP_FORMAT = "Unexpected document format"; - - //-Instance Variables-------------------------------------------------------------------------------------------------- - protected: - Settings* mTargetSettings; - std::shared_ptr mSourceJsonFile; - - //-Constructor-------------------------------------------------------------------------------------------------------- - public: - SettingsReader(Settings* targetSettings, std::shared_ptr sourceJsonFile); - - //-Instance Functions------------------------------------------------------------------------------------------------- - private: - virtual Qx::GenericError parseDocument(const QJsonDocument& jsonDoc) = 0; - - public: - Qx::GenericError readInto(); - - }; - - class ConfigReader : public SettingsReader - { - //-Constructor-------------------------------------------------------------------------------------------------------- - public: - ConfigReader(Config* targetConfig, std::shared_ptr sourceJsonFile); - - //-Instance Functions------------------------------------------------------------------------------------------------- - private: - Qx::GenericError parseDocument(const QJsonDocument& configDoc); - }; - - class PreferencesReader : public SettingsReader - { - //-Constructor-------------------------------------------------------------------------------------------------------- - public: - PreferencesReader(Preferences* targetPreferences, std::shared_ptr sourceJsonFile); - - //-Instance Functions------------------------------------------------------------------------------------------------- - private: - Qx::GenericError parseDocument(const QJsonDocument& prefDoc); - Qx::GenericError parseAppPathOverride(AppPathOverride& apoBuffer, const QJsonValue& jvApo); - Qx::GenericError parseNativePlatform(QString& nativePlatformBuffer, const QJsonValue& jvNativePlatform); - }; - - class ServicesReader : public SettingsReader - { - //-Instance Variables-------------------------------------------------------------------------------------------------- - private: - const MacroResolver* mHostMacroResolver; - - //-Constructor-------------------------------------------------------------------------------------------------------- - public: - ServicesReader(Services* targetServices, std::shared_ptr sourceJsonFile, const MacroResolver* macroResolver); - - //-Instance Functions------------------------------------------------------------------------------------------------- - private: - Qx::GenericError parseDocument(const QJsonDocument& servicesDoc); - Qx::GenericError parseServerDaemon(ServerDaemon& serverBuffer, const QJsonValue& jvServer); - Qx::GenericError parseStartStop(StartStop& startStopBuffer, const QJsonValue& jvStartStop); - }; - - class ExecsReader : public SettingsReader - { - //-Constructor-------------------------------------------------------------------------------------------------------- - public: - ExecsReader(Execs* targetExecs, std::shared_ptr sourceJsonFile); - - //-Instance Functions------------------------------------------------------------------------------------------------- - private: - Qx::GenericError parseDocument(const QJsonDocument& execsDoc); - Qx::GenericError parseExec(Exec& execBuffer, const QJsonValue& jvExec); - }; -}; -} - -#endif // FLASHPOINT_JSON_H diff --git a/lib/include/fp/settings/fp-config.h b/lib/include/fp/settings/fp-config.h new file mode 100644 index 0000000..4410e20 --- /dev/null +++ b/lib/include/fp/settings/fp-config.h @@ -0,0 +1,30 @@ +#ifndef FLASHPOINT_CONFIG_H +#define FLASHPOINT_CONFIG_H + +// Project Includes +#include "fp/settings/fp-settings.h" + +namespace Fp +{ + +struct FP_FP_EXPORT Config : public Settings +{ + QString flashpointPath; + bool startServer; + QString server; +}; + +class FP_FP_EXPORT ConfigReader : public SettingsReader +{ +//-Constructor-------------------------------------------------------------------------------------------------------- +public: + ConfigReader(Config* targetConfig, std::shared_ptr sourceJsonFile); + +//-Instance Functions------------------------------------------------------------------------------------------------- +private: + Qx::GenericError parseDocument(const QJsonDocument& configDoc); +}; + +} + +#endif // FLASHPOINT_CONFIG_H diff --git a/lib/include/fp/settings/fp-execs.h b/lib/include/fp/settings/fp-execs.h new file mode 100644 index 0000000..90e7b08 --- /dev/null +++ b/lib/include/fp/settings/fp-execs.h @@ -0,0 +1,41 @@ +#ifndef FLASHPOINT_EXECS_H +#define FLASHPOINT_EXECS_H + +// Project Includes +#include "fp/settings/fp-settings.h" + +/* Remove the ancient built-in 'linux' define to avoid clash with Exec.linux. + * No one should still be using it anyway and instead using __linux__. + */ +#undef linux + +namespace Fp +{ + +struct FP_FP_EXPORT Exec +{ + QString linux; + QString win32; + QString wine; +}; + +struct FP_FP_EXPORT Execs : public Settings +{ + QList list; +}; + +class FP_FP_EXPORT ExecsReader : public SettingsReader +{ +//-Constructor-------------------------------------------------------------------------------------------------------- +public: + ExecsReader(Execs* targetExecs, std::shared_ptr sourceJsonFile); + +//-Instance Functions------------------------------------------------------------------------------------------------- +private: + Qx::GenericError parseDocument(const QJsonDocument& execsDoc); + Qx::GenericError parseExec(Exec& execBuffer, const QJsonValue& jvExec); +}; + +} + +#endif // FLASHPOINT_EXECS_H diff --git a/lib/include/fp/settings/fp-preferences.h b/lib/include/fp/settings/fp-preferences.h new file mode 100644 index 0000000..c87c155 --- /dev/null +++ b/lib/include/fp/settings/fp-preferences.h @@ -0,0 +1,76 @@ +#ifndef FLASHPOINT_PREFERENCES_H +#define FLASHPOINT_PREFERENCES_H + +// Qt Includes +#include + +// Project Includes +#include "fp/settings/fp-settings.h" + +namespace Fp +{ + +struct FP_FP_EXPORT AppPathOverride +{ + QString path; + QString override; + bool enabled; +}; + +struct FP_FP_EXPORT GameDataSource +{ + QList arguments; + QString name; + QString type; +}; + +//struct FP_FP_EXPORT GameMetadataSource_GamesTags +//{ +// QDateTime actualUpdateTime; +// QDateTime latestDeleteTime; +// QDateTime latestUpdateTime; +//}; + +struct FP_FP_EXPORT GameMetadataSource +{ + QString baseUrl; + //GameMetadataSource_GamesTags games; + QString name; + //GameMetadataSource_GamesTags tags; +}; + +struct FP_FP_EXPORT Preferences : public Settings +{ + QString fpfssBaseUrl; + QHash gameDataSources; + QHash gameMetadataSources; + QString imageFolderPath; + QString jsonFolderPath; + QString htdocsFolderPath; + QString dataPacksFolderPath; + bool onDemandImages; + QString onDemandBaseUrl; + QList appPathOverrides; + QSet nativePlatforms; + QString browserModeProxy; + QString server; +}; + +class FP_FP_EXPORT PreferencesReader : public SettingsReader +{ +//-Constructor-------------------------------------------------------------------------------------------------------- +public: + PreferencesReader(Preferences* targetPreferences, std::shared_ptr sourceJsonFile); + +//-Instance Functions------------------------------------------------------------------------------------------------- +private: + Qx::GenericError parseDocument(const QJsonDocument& prefDoc); + Qx::GenericError parseAppPathOverride(AppPathOverride& apoBuffer, const QJsonValue& jvApo); + Qx::GenericError parseNativePlatform(QString& nativePlatformBuffer, const QJsonValue& jvNativePlatform); + Qx::GenericError parseGameDataSource(GameDataSource& gdsBuffer, const QJsonValue& jvGds); + Qx::GenericError parseGameMetadataSource(GameMetadataSource& gmsBuffer, const QJsonValue& jvGms); +}; + +} + +#endif // FLASHPOINT_PREFERENCES_H diff --git a/lib/include/fp/settings/fp-services.h b/lib/include/fp/settings/fp-services.h new file mode 100644 index 0000000..967b807 --- /dev/null +++ b/lib/include/fp/settings/fp-services.h @@ -0,0 +1,71 @@ +#ifndef FLASHPOINT_SERVICES_H +#define FLASHPOINT_SERVICES_H + +// Qt Includes +#include + +// Project Includes +#include "fp/settings/fp-settings.h" +#include "fp/fp-macro.h" + +namespace Fp +{ + +enum KnownDaemon{ + None = 0x0, + Docker = 0x1, + Qemu = 0x2 +}; +Q_DECLARE_FLAGS(KnownDaemons, KnownDaemon); +Q_DECLARE_OPERATORS_FOR_FLAGS(KnownDaemons); + +struct FP_FP_EXPORT ServerDaemon +{ + QString name; + QString path; + QString filename; + QStringList arguments; + bool kill; +}; + +struct FP_FP_EXPORT StartStop +{ + QString path; + QString filename; + QStringList arguments; + + friend bool operator== (const StartStop& lhs, const StartStop& rhs) noexcept; + friend size_t qHash(const StartStop& key, size_t seed) noexcept; +}; + +struct FP_FP_EXPORT Services : public Settings +{ + //QSet watches; + QHash servers; + QHash daemons; + QSet starts; + QSet stops; + KnownDaemons recognizedDaemons; // Non-standard + // TODO: If Settings container obj is made (see other todo), move this there +}; + +class FP_FP_EXPORT ServicesReader : public SettingsReader +{ +//-Instance Variables-------------------------------------------------------------------------------------------------- +private: + const MacroResolver* mHostMacroResolver; + +//-Constructor-------------------------------------------------------------------------------------------------------- +public: + ServicesReader(Services* targetServices, std::shared_ptr sourceJsonFile, const MacroResolver* macroResolver); + +//-Instance Functions------------------------------------------------------------------------------------------------- +private: + Qx::GenericError parseDocument(const QJsonDocument& servicesDoc); + Qx::GenericError parseServerDaemon(ServerDaemon& serverBuffer, const QJsonValue& jvServer); + Qx::GenericError parseStartStop(StartStop& startStopBuffer, const QJsonValue& jvStartStop); +}; + +} + +#endif // FLASHPOINT_SERVICES_H diff --git a/lib/include/fp/settings/fp-settings.h b/lib/include/fp/settings/fp-settings.h new file mode 100644 index 0000000..595a332 --- /dev/null +++ b/lib/include/fp/settings/fp-settings.h @@ -0,0 +1,60 @@ +#ifndef FLASHPOINT_JSON_H +#define FLASHPOINT_JSON_H + +// Shared Lib Support +#include "fp/fp_export.h" + +// Qt Includes +#include +#include +#include +#include + +// Qx Includes +#include +#include + +namespace Fp +{ + +struct FP_FP_EXPORT Settings {}; + +using BasicJsonTypePtr = std::variant; + +struct FP_FP_EXPORT KeyValuePtr +{ + QStringView key; + BasicJsonTypePtr val; +}; + +class FP_FP_EXPORT SettingsReader +{ +//-Class variables----------------------------------------------------------------------------------------------------- +public: + static inline const QString ERR_PARSING_JSON_DOC = "Error parsing JSON Document: %1"; + static inline const QString ERR_JSON_UNEXP_FORMAT = "Unexpected document format"; + +//-Instance Variables-------------------------------------------------------------------------------------------------- +protected: + Settings* mTargetSettings; + std::shared_ptr mSourceJsonFile; + +//-Constructor-------------------------------------------------------------------------------------------------------- +public: + SettingsReader(Settings* targetSettings, std::shared_ptr sourceJsonFile); + +//-Class Functions------------------------------------------------------------------------------------------------- +protected: + static Qx::GenericError retrieveBasicKeys(QList keyValuePairs, const QJsonObject& obj); //TODO: Use this more, unless switching to improved Qx::Json + +//-Instance Functions------------------------------------------------------------------------------------------------- +private: + virtual Qx::GenericError parseDocument(const QJsonDocument& jsonDoc) = 0; + +public: + Qx::GenericError readInto(); +}; + +} + +#endif // FLASHPOINT_JSON_H diff --git a/lib/src/fp-install.cpp b/lib/src/fp-install.cpp index 2452e6d..0be6259 100644 --- a/lib/src/fp-install.cpp +++ b/lib/src/fp-install.cpp @@ -54,14 +54,14 @@ Install::Install(QString installPath) : // Get settings Qx::GenericError readReport; - Json::ConfigReader configReader(&mConfig, mConfigJsonFile); + ConfigReader configReader(&mConfig, mConfigJsonFile); if((readReport = configReader.readInto()).isValid()) { mError = Qx::GenericError(Qx::GenericError::Critical, ERR_INVALID, readReport.primaryInfo() + " [" + readReport.secondaryInfo() + "]"); return; } - Json::PreferencesReader prefReader(&mPreferences, mPreferencesJsonFile); + PreferencesReader prefReader(&mPreferences, mPreferencesJsonFile); if((readReport = prefReader.readInto()).isValid()) { mError = Qx::GenericError(Qx::GenericError::Critical, ERR_INVALID, readReport.primaryInfo() + " [" + readReport.secondaryInfo() + "]"); @@ -72,7 +72,7 @@ Install::Install(QString installPath) : mLogosDirectory = QDir(installPath + "/" + mPreferences.imageFolderPath + '/' + LOGOS_FOLDER_NAME); mScreenshotsDirectory = QDir(installPath + "/" + mPreferences.imageFolderPath + '/' + SCREENSHOTS_FOLDER_NAME); - Json::ServicesReader servicesReader(&mServices, mServicesJsonFile, mMacroResolver); + ServicesReader servicesReader(&mServices, mServicesJsonFile, mMacroResolver); if((readReport = servicesReader.readInto()).isValid()) { mError = Qx::GenericError(Qx::GenericError::Critical, ERR_INVALID, readReport.primaryInfo() + " [" + readReport.secondaryInfo() + "]"); @@ -81,7 +81,7 @@ Install::Install(QString installPath) : if(mExecsJsonFile->exists()) // Optional { - Json::ExecsReader execsReader(&mExecs, mExecsJsonFile); + ExecsReader execsReader(&mExecs, mExecsJsonFile); if((readReport = execsReader.readInto()).isValid()) { mError = Qx::GenericError(Qx::GenericError::Critical, ERR_INVALID, readReport.primaryInfo() + " [" + readReport.secondaryInfo() + "]"); @@ -223,10 +223,10 @@ QString Install::launcherChecksum() const Db* Install::database() { return mDatabase; } -const Json::Config& Install::config() const { return mConfig; } -const Json::Preferences& Install::preferences() const { return mPreferences; } -const Json::Services& Install::services() const { return mServices; } -const Json::Execs& Install::execs() const { return mExecs; } +const Config& Install::config() const { return mConfig; } +const Preferences& Install::preferences() const { return mPreferences; } +const Services& Install::services() const { return mServices; } +const Execs& Install::execs() const { return mExecs; } QString Install::fullPath() const { return mRootDirectory.absolutePath(); } QDir Install::logosDirectory() const { return mLogosDirectory; } @@ -250,7 +250,7 @@ const MacroResolver* Install::macroResolver() const { return mMacroResolver; } QString Install::resolveAppPathOverrides(const QString& appPath) const { // Check if path has an associated override - for(const Json::AppPathOverride& override : qAsConst(mPreferences.appPathOverrides)) + for(const AppPathOverride& override : qAsConst(mPreferences.appPathOverrides)) { if(override.path == appPath && override.enabled) return override.override; @@ -265,7 +265,7 @@ QString Install::resolveExecSwaps(const QString& appPath, const QString& platfor bool preferNative = mPreferences.nativePlatforms.contains(platform); // Check if path has an associated swap - for(const Json::Exec& swap : qAsConst(mExecs.list)) + for(const Exec& swap : qAsConst(mExecs.list)) { if(swap.win32 == appPath) { diff --git a/lib/src/fp-items.cpp b/lib/src/fp-items.cpp index 3a822b1..c920cfb 100644 --- a/lib/src/fp-items.cpp +++ b/lib/src/fp-items.cpp @@ -24,7 +24,6 @@ QString Game::developer() const { return mDeveloper; } QString Game::publisher() const { return mPublisher; } QDateTime Game::dateAdded() const { return mDateAdded; } QDateTime Game::dateModified() const { return mDateModified; } -QString Game::platform() const { return mPlatform; } QString Game::playMode() const { return mPlayMode; } bool Game::isBroken() const { return mBroken; } QString Game::status() const { return mStatus; } @@ -38,6 +37,7 @@ QString Game::originalDescription() const { return mOriginalDescription; } QString Game::language() const { return mLanguage; } QString Game::orderTitle() const { return mOrderTitle; } QString Game::library() const { return mLibrary; } +QString Game::platformName() const { return mPlatformName; } //=============================================================================================================== // Game::Builder @@ -78,7 +78,6 @@ Game::Builder& Game::Builder::wDeveloper(QString developer) { mGameBlueprint.mDe Game::Builder& Game::Builder::wPublisher(QString publisher) { mGameBlueprint.mPublisher = publisher; return *this; } Game::Builder& Game::Builder::wDateAdded(QString rawDateAdded) { mGameBlueprint.mDateAdded = QDateTime::fromString(rawDateAdded, Qt::ISODateWithMs); return *this; } Game::Builder& Game::Builder::wDateModified(QString rawDateModified) { mGameBlueprint.mDateModified = QDateTime::fromString(rawDateModified, Qt::ISODateWithMs); return *this; } -Game::Builder& Game::Builder::wPlatform(QString platform) { mGameBlueprint.mPlatform = platform; return *this; } Game::Builder& Game::Builder::wBroken(QString rawBroken) { mGameBlueprint.mBroken = rawBroken.toInt() != 0; return *this; } Game::Builder& Game::Builder::wPlayMode(QString playMode) { mGameBlueprint.mPlayMode = playMode; return *this; } Game::Builder& Game::Builder::wStatus(QString status) { mGameBlueprint.mStatus = status; return *this; } @@ -92,6 +91,7 @@ Game::Builder& Game::Builder::wOriginalDescription(QString originalDescription) Game::Builder& Game::Builder::wLanguage(QString language) { mGameBlueprint.mLanguage = language; return *this; } Game::Builder& Game::Builder::wOrderTitle(QString orderTitle) { mGameBlueprint.mOrderTitle = orderTitle; return *this; } Game::Builder& Game::Builder::wLibrary(QString library) { mGameBlueprint.mLibrary = library; return *this; } +Game::Builder& Game::Builder::wPlatformName(QString platformName) { mGameBlueprint.mPlatformName = platformName; return *this; } Game Game::Builder::build() { return mGameBlueprint; } diff --git a/lib/src/fp-json.cpp b/lib/src/fp-json.cpp deleted file mode 100644 index 424c2db..0000000 --- a/lib/src/fp-json.cpp +++ /dev/null @@ -1,479 +0,0 @@ -// Unit Includes -#include "fp/fp-json.h" - -// Qt Includes -#include -#include -#include - -// Qx Includes -#include -#include - -namespace Fp -{ - -//=============================================================================================================== -// JSON::START_STOP -//=============================================================================================================== - -//-Operators---------------------------------------------------------------------------------------------------- -//Public: -bool operator== (const Json::StartStop& lhs, const Json::StartStop& rhs) noexcept -{ - return lhs.path == rhs.path && lhs.filename == rhs.filename && lhs.arguments == rhs.arguments; -} - -//-Hashing------------------------------------------------------------------------------------------------------ -size_t qHash(const Json::StartStop& key, size_t seed) noexcept -{ - QtPrivate::QHashCombine hash; - seed = hash(seed, key.path); - seed = hash(seed, key.filename); - seed = hash(seed, key.arguments); - - return seed; -} - -//=============================================================================================================== -// JSON::SETTINGS_READER -//=============================================================================================================== - -//-Constructor-------------------------------------------------------------------------------------------------------- -//Public: -Json::SettingsReader::SettingsReader(Settings* targetSettings, std::shared_ptr sourceJsonFile) : - mTargetSettings(targetSettings), - mSourceJsonFile(sourceJsonFile) -{} - -//-Instance Functions------------------------------------------------------------------------------------------------- -//Public: -Qx::GenericError Json::SettingsReader::readInto() -{ - // Load original JSON file - QByteArray settingsData; - Qx::IoOpReport settingsLoadReport = Qx::readBytesFromFile(settingsData, *mSourceJsonFile); - - if(settingsLoadReport.isFailure()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), settingsLoadReport.outcomeInfo()); - - // Parse original JSON data - QJsonParseError parseError; - QJsonDocument settingsDocument = QJsonDocument::fromJson(settingsData, &parseError); - - if(settingsDocument.isNull()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), parseError.errorString()); - else - { - // Ensure top level container is object - if(!settingsDocument.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - return parseDocument(settingsDocument); - } -} - -//=============================================================================================================== -// JSON::CONFIG_READER -//=============================================================================================================== - -//-Constructor-------------------------------------------------------------------------------------------------------- -//Public: -Json::ConfigReader::ConfigReader(Config* targetConfig, std::shared_ptr sourceJsonFile) : - SettingsReader(targetConfig, sourceJsonFile) -{} - -//-Instance Functions------------------------------------------------------------------------------------------------- -//Private: -Qx::GenericError Json::ConfigReader::parseDocument(const QJsonDocument& configDoc) -{ - // Get derivation specific target - Config* targetConfig = static_cast(mTargetSettings); - - // Get values - Qx::GenericError valueError; - - if((valueError = Qx::Json::checkedKeyRetrieval(targetConfig->flashpointPath, configDoc.object(), Object_Config::KEY_FLASHPOINT_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetConfig->startServer, configDoc.object(), Object_Config::KEY_START_SERVER)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetConfig->server, configDoc.object(), Object_Config::KEY_SERVER)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Return invalid error on success - return Qx::GenericError(); - -} - -//=============================================================================================================== -// JSON::PREFERENCES_READER -//=============================================================================================================== - -//-Constructor-------------------------------------------------------------------------------------------------------- -//Public: -Json::PreferencesReader::PreferencesReader(Preferences* targetPreferences, std::shared_ptr sourceJsonFile) : - SettingsReader(targetPreferences, sourceJsonFile) -{} - -//-Instance Functions------------------------------------------------------------------------------------------------- -//Private: -Qx::GenericError Json::PreferencesReader::parseDocument(const QJsonDocument& prefDoc) -{ - // Get derivation specific target - Preferences* targetPreferences = static_cast(mTargetSettings); - - // Get values - Qx::GenericError valueError; - - // Single value - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->imageFolderPath, prefDoc.object(), Object_Preferences::KEY_IMAGE_FOLDER_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->jsonFolderPath, prefDoc.object(), Object_Preferences::KEY_JSON_FOLDER_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->htdocsFolderPath, prefDoc.object(), Object_Preferences::KEY_HTDOCS_FOLDER_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->dataPacksFolderPath, prefDoc.object(), Object_Preferences::KEY_DATA_PACKS_FOLDER_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->onDemandImages, prefDoc.object(), Object_Preferences::KEY_ON_DEMAND_IMAGES)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->onDemandBaseUrl, prefDoc.object(), Object_Preferences::KEY_ON_DEMAND_BASE_URL)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->browserModeProxy, prefDoc.object(), Object_Preferences::KEY_BROWSER_MODE_PROXY)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Get app path overrides - QJsonArray appPathOverrides; - if((valueError = Qx::Json::checkedKeyRetrieval(appPathOverrides, prefDoc.object(), Object_Preferences::KEY_APP_PATH_OVERRIDES)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse app path overrides - for(const QJsonValue& jvApo : qAsConst(appPathOverrides)) - { - AppPathOverride apoBuffer; - if((valueError = parseAppPathOverride(apoBuffer, jvApo)).isValid()) - return valueError; - - targetPreferences->appPathOverrides.append(apoBuffer); - } - - // Get native platforms - QJsonArray nativePlatforms; - if((valueError = Qx::Json::checkedKeyRetrieval(nativePlatforms, prefDoc.object(), Object_Preferences::KEY_NATIVE_PLATFORMS)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse native platforms - for(const QJsonValue& jvNativePlatform : qAsConst(nativePlatforms)) - { - QString nativePlatformBuffer; - if((valueError = parseNativePlatform(nativePlatformBuffer, jvNativePlatform)).isValid()) - return valueError; - - targetPreferences->nativePlatforms.insert(nativePlatformBuffer); - } - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError Json::PreferencesReader::parseAppPathOverride(AppPathOverride& apoBuffer, const QJsonValue& jvApo) -{ - // Ensure array element is Object - if(!jvApo.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get app path override Object - QJsonObject joApo = jvApo.toObject(); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get direct values - if((valueError = Qx::Json::checkedKeyRetrieval(apoBuffer.path, joApo, Object_AppPathOverrides::KEY_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(apoBuffer.override, joApo, Object_AppPathOverrides::KEY_OVERRIDE)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(apoBuffer.enabled, joApo, Object_AppPathOverrides::KEY_ENABLED)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError Json::PreferencesReader::parseNativePlatform(QString& nativePlatformBuffer, const QJsonValue& jvNativePlatform) -{ - // Ensure array element is String - if(!jvNativePlatform.isString()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get native platform string - nativePlatformBuffer = jvNativePlatform.toString(); - - // Return invalid error on success - return Qx::GenericError(); -} - -//=============================================================================================================== -// JSON::SERVICES_READER -//=============================================================================================================== - -//-Constructor-------------------------------------------------------------------------------------------------------- -//Public: -Json::ServicesReader::ServicesReader(Services* targetServices, std::shared_ptr sourceJsonFile, const MacroResolver* macroResolver) : - SettingsReader(targetServices, sourceJsonFile), - mHostMacroResolver(macroResolver) -{} - -//-Instance Functions------------------------------------------------------------------------------------------------- -//Private: -Qx::GenericError Json::ServicesReader::parseDocument(const QJsonDocument& servicesDoc) -{ - // Get derivation specific target - Services* targetServices = static_cast(mTargetSettings); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get watches - // TODO: include logs - - // Get servers - QJsonArray jaServers; - if((valueError = Qx::Json::checkedKeyRetrieval(jaServers, servicesDoc.object(), Object_Services::KEY_SERVER)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse servers - for(const QJsonValue& jvServer : qAsConst(jaServers)) - { - ServerDaemon serverBuffer; - if((valueError = parseServerDaemon(serverBuffer, jvServer)).isValid()) - return valueError; - - targetServices->servers.insert(serverBuffer.name, serverBuffer); - } - - // Get daemons - QJsonArray jaDaemons; - if((valueError = Qx::Json::checkedKeyRetrieval(jaDaemons, servicesDoc.object(), Object_Services::KEY_DAEMON)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse daemons - for(const QJsonValue& jvDaemon : qAsConst(jaDaemons)) - { - ServerDaemon daemonBuffer; - if((valueError = parseServerDaemon(daemonBuffer, jvDaemon)).isValid()) - return valueError; - - targetServices->daemons.insert(daemonBuffer.name, daemonBuffer); - - /* NOTE: If for some reason this list becomes large, use a hash instead - * (e.g. if(hash.contains("NAME")){ recognizedDaemons.setFlag(hash["NAME]); } ) - */ - if(daemonBuffer.name.contains("qemu", Qt::CaseInsensitive) || - daemonBuffer.filename.contains("qemu", Qt::CaseInsensitive)) - targetServices->recognizedDaemons.setFlag(KnownDaemon::Qemu); - else if(daemonBuffer.name.contains("docker", Qt::CaseInsensitive) || - daemonBuffer.filename.contains("docker", Qt::CaseInsensitive)) - targetServices->recognizedDaemons.setFlag(KnownDaemon::Docker); - } - - // Get starts - QJsonArray jaStarts; - if((valueError = Qx::Json::checkedKeyRetrieval(jaStarts, servicesDoc.object(), Object_Services::KEY_START)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse starts - for(const QJsonValue& jvStart : qAsConst(jaStarts)) - { - StartStop startStopBuffer; - if((valueError = parseStartStop(startStopBuffer, jvStart)).isValid()) - return valueError; - - targetServices->starts.insert(startStopBuffer); - } - - // Get stops - QJsonArray jaStops; - if((valueError = Qx::Json::checkedKeyRetrieval(jaStops, servicesDoc.object(), Object_Services::KEY_STOP)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse starts - for(const QJsonValue& jvStop : qAsConst(jaStops)) - { - StartStop startStopBuffer; - if((valueError = parseStartStop(startStopBuffer, jvStop)).isValid()) - return valueError; - - targetServices->stops.insert(startStopBuffer); - } - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError Json::ServicesReader::parseServerDaemon(ServerDaemon& serverBuffer, const QJsonValue& jvServer) -{ - // Ensure array element is Object - if(!jvServer.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get server Object - QJsonObject joServer = jvServer.toObject(); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get direct values - if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.name, joServer, Object_ServerDaemon::KEY_NAME)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.path, joServer, Object_ServerDaemon::KEY_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.filename, joServer, Object_ServerDaemon::KEY_FILENAME)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.kill, joServer, Object_ServerDaemon::KEY_KILL)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Get arguments - QJsonArray jaArgs; - if((valueError = Qx::Json::checkedKeyRetrieval(jaArgs, joServer, Object_ServerDaemon::KEY_ARGUMENTS)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - for(const QJsonValue& jvArg : qAsConst(jaArgs)) - { - // Ensure array element is String - if(!jvArg.isString()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - serverBuffer.arguments.append(jvArg.toString()); - } - - // Resolve macros for relevant variables - serverBuffer.path = mHostMacroResolver->resolve(serverBuffer.path); - for(QString& arg : serverBuffer.arguments) - arg = mHostMacroResolver->resolve(arg); - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError Json::ServicesReader::parseStartStop(StartStop& startStopBuffer, const QJsonValue& jvStartStop) -{ - // Ensure return buffer is null - startStopBuffer = StartStop(); - - // Ensure array element is Object - if(!jvStartStop.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get server Object - QJsonObject joStartStop = jvStartStop.toObject(); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get direct values - if((valueError = Qx::Json::checkedKeyRetrieval(startStopBuffer.path, joStartStop , Object_StartStop::KEY_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(startStopBuffer.filename, joStartStop, Object_StartStop::KEY_FILENAME)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Get arguments - QJsonArray jaArgs; - if((valueError = Qx::Json::checkedKeyRetrieval(jaArgs, joStartStop, Object_StartStop::KEY_ARGUMENTS)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - for(const QJsonValue& jvArg : qAsConst(jaArgs)) - { - // Ensure array element is String - if(!jvArg.isString()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - startStopBuffer.arguments.append(jvArg.toString()); - } - - // Resolve macros for relevant variables - startStopBuffer.path = mHostMacroResolver->resolve(startStopBuffer.path); - for(QString& arg : startStopBuffer.arguments) - arg = mHostMacroResolver->resolve(arg); - - // Return invalid error on success - return Qx::GenericError(); -} - -//=============================================================================================================== -// JSON::EXECS_READER -//=============================================================================================================== - -//-Constructor-------------------------------------------------------------------------------------------------------- -//Public: -Json::ExecsReader::ExecsReader(Execs* targetExecs, std::shared_ptr sourceJsonFile) : - SettingsReader(targetExecs, sourceJsonFile) -{} - -//-Instance Functions------------------------------------------------------------------------------------------------- -//Private: -Qx::GenericError Json::ExecsReader::parseDocument(const QJsonDocument& execsDoc) -{ - // Get derivation specific target - Execs* targetExecs = static_cast(mTargetSettings); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get exec entries - QJsonArray jaExecs; - if((valueError = Qx::Json::checkedKeyRetrieval(jaExecs, execsDoc.object(), Object_Execs::KEY_EXECS)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse starts - for(const QJsonValue& jvExec : qAsConst(jaExecs)) - { - Exec execBuffer; - if((valueError = parseExec(execBuffer, jvExec)).isValid()) - return valueError; - - targetExecs->list.append(execBuffer); - } - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError Json::ExecsReader::parseExec(Exec& execBuffer, const QJsonValue& jvExec) -{ - // Ensure array element is Object - if(!jvExec.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get exec Object - QJsonObject joExec = jvExec.toObject(); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get direct values (ignore errors for optional values) - if((valueError = Qx::Json::checkedKeyRetrieval(execBuffer.win32, joExec , Object_Exec::KEY_WIN32)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - Qx::Json::checkedKeyRetrieval(execBuffer.linux, joExec , Object_Exec::KEY_LINUX); - Qx::Json::checkedKeyRetrieval(execBuffer.wine, joExec , Object_Exec::KEY_WINE); - - - // Return invalid error on success - return Qx::GenericError(); -} - -} diff --git a/lib/src/settings/fp-config.cpp b/lib/src/settings/fp-config.cpp new file mode 100644 index 0000000..e1d2398 --- /dev/null +++ b/lib/src/settings/fp-config.cpp @@ -0,0 +1,49 @@ +// Unit Includes +#include "fp/settings/fp-config.h" + +// Qx Includes +#include + +using namespace Qt::Literals::StringLiterals; + +namespace Fp +{ + +namespace Json +{ + namespace Object_Config + { + const QString KEY_FLASHPOINT_PATH = u"flashpointPath"_s; // Reading this value is current redundant and unused, but this may change in the future + const QString KEY_START_SERVER = u"startServer"_s; + const QString KEY_SERVER = u"server"_s; + }; +} + +//=============================================================================================================== +// ConfigReader +//=============================================================================================================== + +//-Constructor-------------------------------------------------------------------------------------------------------- +//Public: +ConfigReader::ConfigReader(Config* targetConfig, std::shared_ptr sourceJsonFile) : + SettingsReader(targetConfig, sourceJsonFile) +{} + +//-Instance Functions------------------------------------------------------------------------------------------------- +//Private: +Qx::GenericError ConfigReader::parseDocument(const QJsonDocument& configDoc) +{ + // Get derivation specific target + Config* targetConfig = static_cast(mTargetSettings); + + // Get values + const QList kvps{ + {Json::Object_Config::KEY_FLASHPOINT_PATH, &targetConfig->flashpointPath}, + {Json::Object_Config::KEY_START_SERVER, &targetConfig->startServer}, + {Json::Object_Config::KEY_SERVER, &targetConfig->server}, + }; + + return retrieveBasicKeys(kvps, configDoc.object()); +} + +} diff --git a/lib/src/settings/fp-execs.cpp b/lib/src/settings/fp-execs.cpp new file mode 100644 index 0000000..e8862fd --- /dev/null +++ b/lib/src/settings/fp-execs.cpp @@ -0,0 +1,91 @@ +// Unit Includes +#include "fp/settings/fp-execs.h" + +// Qx Includes +#include + +using namespace Qt::Literals::StringLiterals; + +namespace Fp +{ + +namespace Json +{ + namespace Object_Execs + { + const QString KEY_EXECS = u"execs"_s; + }; + + namespace Object_Exec + { + const QString KEY_WIN32 = u"win32"_s; + const QString KEY_LINUX = u"linux"_s; + const QString KEY_WINE = u"wine"_s; + }; +} + +//=============================================================================================================== +// ExecsReader +//=============================================================================================================== + +//-Constructor-------------------------------------------------------------------------------------------------------- +//Public: +ExecsReader::ExecsReader(Execs* targetExecs, std::shared_ptr sourceJsonFile) : + SettingsReader(targetExecs, sourceJsonFile) +{} + +//-Instance Functions------------------------------------------------------------------------------------------------- +//Private: +Qx::GenericError ExecsReader::parseDocument(const QJsonDocument& execsDoc) +{ + // Get derivation specific target + Execs* targetExecs = static_cast(mTargetSettings); + + // Value error checking buffer + QJsonObject rootObj = execsDoc.object(); + Qx::GenericError valueError; + + // Get exec entries + QJsonArray jaExecs; + if((valueError = Qx::Json::checkedKeyRetrieval(jaExecs, rootObj, Json::Object_Execs::KEY_EXECS)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Parse execs + for(const QJsonValue& jvExec : qAsConst(jaExecs)) + { + Exec execBuffer; + if((valueError = parseExec(execBuffer, jvExec)).isValid()) + return valueError; + + targetExecs->list.append(execBuffer); + } + + // Return invalid error on success + return Qx::GenericError(); +} + +Qx::GenericError ExecsReader::parseExec(Exec& execBuffer, const QJsonValue& jvExec) +{ + // Ensure array element is Object + if(!jvExec.isObject()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); + + // Get exec Object + QJsonObject joExec = jvExec.toObject(); + + // Value error checking buffer + Qx::GenericError valueError; + + // Get direct values (ignore errors for optional values) + if((valueError = Qx::Json::checkedKeyRetrieval(execBuffer.win32, joExec , Json::Object_Exec::KEY_WIN32)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + Qx::Json::checkedKeyRetrieval(execBuffer.linux, joExec, Json::Object_Exec::KEY_LINUX); + Qx::Json::checkedKeyRetrieval(execBuffer.wine, joExec, Json::Object_Exec::KEY_WINE); + + + // Return invalid error on success + return Qx::GenericError(); +} + +} diff --git a/lib/src/settings/fp-preferences.cpp b/lib/src/settings/fp-preferences.cpp new file mode 100644 index 0000000..e32f854 --- /dev/null +++ b/lib/src/settings/fp-preferences.cpp @@ -0,0 +1,275 @@ +// Unit Includes +#include "fp/settings/fp-preferences.h" + +// Qx Includes +#include + +using namespace Qt::Literals::StringLiterals; + +namespace Fp +{ + +namespace Json +{ + namespace Object_AppPathOverride + { + const QString KEY_PATH = u"path"_s; + const QString KEY_OVERRIDE = u"override"_s; + const QString KEY_ENABLED = u"enabled"_s; + }; + + namespace Object_GameDataSource + { + const QString KEY_ARGUMENTS = u"arguments"_s; + const QString KEY_NAME = u"name"_s; + const QString KEY_TYPE = u"type"_s; + } + + namespace Object_GameMetadataSource_GamesTags + { + const QString KEY_ACTUAL_UPDATE_TIME = u"actualUpdateTime"_s; + const QString KEY_LAST_DELETE_TIME = u"lastDeleteTime"_s; + const QString KEY_LAST_UPDATE_TIME = u"latestUpdateTime"_s; + } + + namespace Object_GameMetadataSource + { + const QString KEY_BASE_URL = u"baseUrl"_s; + const QString KEY_GAMES = u"games"_s; + const QString KEY_NAME = u"name"_s; + const QString KET_TAGS = u"tags"_s; + } + + namespace Object_Preferences + { + const QString KEY_APP_PATH_OVERRIDES = u"appPathOverrides"_s; + const QString KEY_BROWSER_MODE_PROXY = u"browserModeProxy"_s; + const QString KEY_DATA_PACKS_FOLDER_PATH = u"dataPacksFolderPath"_s; + const QString KEY_FPFSS_BASE_URL = u"fpfssBaseUrl"_s; + const QString KEY_GAME_DATA_SOURCES = u"gameDataSources"_s; + const QString KEY_GAME_METADATA_SOURCES = u"gameMetadataSources"_s; + const QString KEY_HTDOCS_FOLDER_PATH = u"htdocsFolderPath"_s; + const QString KEY_IMAGE_FOLDER_PATH = u"imageFolderPath"_s; + const QString KEY_JSON_FOLDER_PATH = u"jsonFolderPath"_s; + const QString KEY_NATIVE_PLATFORMS = u"nativePlatforms"_s; + const QString KEY_ON_DEMAND_BASE_URL = u"onDemandBaseUrl"_s; + const QString KEY_ON_DEMAND_IMAGES = u"onDemandImages"_s; + const QString KEY_SERVER = u"server"_s; + }; +} + +//=============================================================================================================== +// PreferencesReader +//=============================================================================================================== + +//-Constructor-------------------------------------------------------------------------------------------------------- +//Public: +PreferencesReader::PreferencesReader(Preferences* targetPreferences, std::shared_ptr sourceJsonFile) : + SettingsReader(targetPreferences, sourceJsonFile) +{} + +//-Instance Functions------------------------------------------------------------------------------------------------- +//Private: +Qx::GenericError PreferencesReader::parseDocument(const QJsonDocument& prefDoc) +{ + // Get derivation specific target + Preferences* targetPreferences = static_cast(mTargetSettings); + + // Get values + QJsonObject rootObj = prefDoc.object(); + Qx::GenericError valueError; + + // Single value + if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->fpfssBaseUrl, rootObj, Json::Object_Preferences::KEY_FPFSS_BASE_URL)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->imageFolderPath, rootObj, Json::Object_Preferences::KEY_IMAGE_FOLDER_PATH)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->jsonFolderPath, rootObj, Json::Object_Preferences::KEY_JSON_FOLDER_PATH)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->htdocsFolderPath, rootObj, Json::Object_Preferences::KEY_HTDOCS_FOLDER_PATH)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->dataPacksFolderPath, rootObj, Json::Object_Preferences::KEY_DATA_PACKS_FOLDER_PATH)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->onDemandImages, rootObj, Json::Object_Preferences::KEY_ON_DEMAND_IMAGES)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->onDemandBaseUrl, rootObj, Json::Object_Preferences::KEY_ON_DEMAND_BASE_URL)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->browserModeProxy, rootObj, Json::Object_Preferences::KEY_BROWSER_MODE_PROXY)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->server, rootObj, Json::Object_Preferences::KEY_SERVER)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Get app path overrides + QJsonArray appPathOverrides; + if((valueError = Qx::Json::checkedKeyRetrieval(appPathOverrides, rootObj, Json::Object_Preferences::KEY_APP_PATH_OVERRIDES)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Parse app path overrides + for(const QJsonValue& jvApo : qAsConst(appPathOverrides)) + { + AppPathOverride apoBuffer; + if((valueError = parseAppPathOverride(apoBuffer, jvApo)).isValid()) + return valueError; + + targetPreferences->appPathOverrides.append(apoBuffer); + } + + // Get native platforms + QJsonArray nativePlatforms; + if((valueError = Qx::Json::checkedKeyRetrieval(nativePlatforms, rootObj, Json::Object_Preferences::KEY_NATIVE_PLATFORMS)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Parse native platforms + for(const QJsonValue& jvNativePlatform : qAsConst(nativePlatforms)) + { + QString nativePlatformBuffer; + if((valueError = parseNativePlatform(nativePlatformBuffer, jvNativePlatform)).isValid()) + return valueError; + + targetPreferences->nativePlatforms.insert(nativePlatformBuffer); + } + + //TODO: PARSE NEW STRUCTUTRES + + // Get game data sources + QJsonArray gameDataSources; + if((valueError = Qx::Json::checkedKeyRetrieval(gameDataSources, rootObj, Json::Object_Preferences::KEY_GAME_DATA_SOURCES)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Parse game data sources + for(const QJsonValue& jvGameDataSource : qAsConst(gameDataSources)) + { + GameDataSource gameDataSourceBuffer; + if((valueError = parseGameDataSource(gameDataSourceBuffer, jvGameDataSource)).isValid()) + return valueError; + + targetPreferences->gameDataSources.insert(gameDataSourceBuffer.name, gameDataSourceBuffer); + } + + // Get game data sources + QJsonArray gameMetadataSources; + if((valueError = Qx::Json::checkedKeyRetrieval(gameMetadataSources, rootObj, Json::Object_Preferences::KEY_GAME_METADATA_SOURCES)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Parse game data sources + for(const QJsonValue& jvGameMetadataSource : qAsConst(gameMetadataSources)) + { + GameMetadataSource gameMetadataSourceBuffer; + if((valueError = parseGameMetadataSource(gameMetadataSourceBuffer, jvGameMetadataSource)).isValid()) + return valueError; + + targetPreferences->gameMetadataSources.insert(gameMetadataSourceBuffer.name, gameMetadataSourceBuffer); + } + + // Return invalid error on success + return Qx::GenericError(); +} + +Qx::GenericError PreferencesReader::parseAppPathOverride(AppPathOverride& apoBuffer, const QJsonValue& jvApo) +{ + // Ensure array element is Object + if(!jvApo.isObject()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); + + // Get app path override Object + QJsonObject joApo = jvApo.toObject(); + + // Value error checking buffer + Qx::GenericError valueError; + + // Get direct values + if((valueError = Qx::Json::checkedKeyRetrieval(apoBuffer.path, joApo, Json::Object_AppPathOverride::KEY_PATH)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(apoBuffer.override, joApo, Json::Object_AppPathOverride::KEY_OVERRIDE)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(apoBuffer.enabled, joApo, Json::Object_AppPathOverride::KEY_ENABLED)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Return invalid error on success + return Qx::GenericError(); +} + +Qx::GenericError PreferencesReader::parseNativePlatform(QString& nativePlatformBuffer, const QJsonValue& jvNativePlatform) +{ + // Ensure array element is String + if(!jvNativePlatform.isString()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); + + // Get native platform string + nativePlatformBuffer = jvNativePlatform.toString(); + + // Return invalid error on success + return Qx::GenericError(); +} + +Qx::GenericError PreferencesReader::parseGameDataSource(GameDataSource& gdsBuffer, const QJsonValue& jvGds) +{ + // Ensure array element is Object + if(!jvGds.isObject()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); + + // Get game data source Object + QJsonObject joGds = jvGds.toObject(); + + // Value error checking buffer + Qx::GenericError valueError; + + // Get direct values + if((valueError = Qx::Json::checkedKeyRetrieval(gdsBuffer.name, joGds, Json::Object_GameDataSource::KEY_NAME)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(gdsBuffer.type, joGds, Json::Object_GameDataSource::KEY_TYPE)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Get arguments + QJsonArray arguments; + if((valueError = Qx::Json::checkedKeyRetrieval(arguments, joGds, Json::Object_GameDataSource::KEY_ARGUMENTS)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Parse arguments + for(const QJsonValue& jvArgument : qAsConst(arguments)) + { + if(!jvArgument.isString()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); + + gdsBuffer.arguments.append(jvArgument.toString()); + } + + // Return invalid error on success + return Qx::GenericError(); +} + +Qx::GenericError PreferencesReader::parseGameMetadataSource(GameMetadataSource& gmsBuffer, const QJsonValue& jvGms) +{ + // Ensure array element is Object + if(!jvGms.isObject()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); + + // Get game data source Object + QJsonObject joGms = jvGms.toObject(); + + // Value error checking buffer + Qx::GenericError valueError; + + // Get direct values + if((valueError = Qx::Json::checkedKeyRetrieval(gmsBuffer.baseUrl, joGms, Json::Object_GameMetadataSource::KEY_BASE_URL)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(gmsBuffer.name, joGms, Json::Object_GameMetadataSource::KEY_NAME)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Return invalid error on success + return Qx::GenericError(); +} + +} diff --git a/lib/src/settings/fp-services.cpp b/lib/src/settings/fp-services.cpp new file mode 100644 index 0000000..238165f --- /dev/null +++ b/lib/src/settings/fp-services.cpp @@ -0,0 +1,253 @@ +// Unit Includes +#include "fp/settings/fp-services.h" + +// Qx Includes +#include + +using namespace Qt::Literals::StringLiterals; + +namespace Fp +{ + +namespace Json +{ + namespace Object_ServerDaemon + { + const QString KEY_NAME = u"name"_s; + const QString KEY_PATH = u"path"_s; + const QString KEY_FILENAME = u"filename"_s; + const QString KEY_ARGUMENTS = u"arguments"_s; + const QString KEY_KILL = u"kill"_s; + }; + namespace Object_StartStop + { + const QString KEY_PATH = u"path"_s; + const QString KEY_FILENAME = u"filename"_s; + const QString KEY_ARGUMENTS = u"arguments"_s; + }; + + namespace Object_Services + { + const QString KEY_WATCH = u"watch"_s; + const QString KEY_SERVER = u"server"_s; + const QString KEY_DAEMON = u"daemon"_s; + const QString KEY_START = u"start"_s; + const QString KEY_STOP = u"stop"_s; + }; +} + +//=============================================================================================================== +// StartStop +//=============================================================================================================== + +//-Operators---------------------------------------------------------------------------------------------------- +//Public: +bool operator== (const StartStop& lhs, const StartStop& rhs) noexcept +{ + return lhs.path == rhs.path && lhs.filename == rhs.filename && lhs.arguments == rhs.arguments; +} + +//-Hashing------------------------------------------------------------------------------------------------------ +size_t qHash(const StartStop& key, size_t seed) noexcept +{ + QtPrivate::QHashCombine hash; + seed = hash(seed, key.path); + seed = hash(seed, key.filename); + seed = hash(seed, key.arguments); + + return seed; +} + +//=============================================================================================================== +// ServicesReader +//=============================================================================================================== + +//-Constructor-------------------------------------------------------------------------------------------------------- +//Public: +ServicesReader::ServicesReader(Services* targetServices, std::shared_ptr sourceJsonFile, const MacroResolver* macroResolver) : + SettingsReader(targetServices, sourceJsonFile), + mHostMacroResolver(macroResolver) +{} + +//-Instance Functions------------------------------------------------------------------------------------------------- +//Private: +Qx::GenericError ServicesReader::parseDocument(const QJsonDocument& servicesDoc) +{ + // Get derivation specific target + Services* targetServices = static_cast(mTargetSettings); + + // Value error checking buffer + QJsonObject rootObj = servicesDoc.object(); + Qx::GenericError valueError; + + // Get watches + // TODO: include logs + + // Get servers + QJsonArray jaServers; + if((valueError = Qx::Json::checkedKeyRetrieval(jaServers, rootObj, Json::Object_Services::KEY_SERVER)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Parse servers + for(const QJsonValue& jvServer : qAsConst(jaServers)) + { + ServerDaemon serverBuffer; + if((valueError = parseServerDaemon(serverBuffer, jvServer)).isValid()) + return valueError; + + targetServices->servers.insert(serverBuffer.name, serverBuffer); + } + + // Get daemons + QJsonArray jaDaemons; + if((valueError = Qx::Json::checkedKeyRetrieval(jaDaemons, rootObj, Json::Object_Services::KEY_DAEMON)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Parse daemons + for(const QJsonValue& jvDaemon : qAsConst(jaDaemons)) + { + ServerDaemon daemonBuffer; + if((valueError = parseServerDaemon(daemonBuffer, jvDaemon)).isValid()) + return valueError; + + targetServices->daemons.insert(daemonBuffer.name, daemonBuffer); + + /* NOTE: If for some reason this list becomes large, use a hash instead + * (e.g. if(hash.contains("NAME")){ recognizedDaemons.setFlag(hash["NAME]); } ) + */ + if(daemonBuffer.name.contains("qemu", Qt::CaseInsensitive) || + daemonBuffer.filename.contains("qemu", Qt::CaseInsensitive)) + targetServices->recognizedDaemons.setFlag(KnownDaemon::Qemu); + else if(daemonBuffer.name.contains("docker", Qt::CaseInsensitive) || + daemonBuffer.filename.contains("docker", Qt::CaseInsensitive)) + targetServices->recognizedDaemons.setFlag(KnownDaemon::Docker); + } + + // Get starts + QJsonArray jaStarts; + if((valueError = Qx::Json::checkedKeyRetrieval(jaStarts, rootObj, Json::Object_Services::KEY_START)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Parse starts + for(const QJsonValue& jvStart : qAsConst(jaStarts)) + { + StartStop startStopBuffer; + if((valueError = parseStartStop(startStopBuffer, jvStart)).isValid()) + return valueError; + + targetServices->starts.insert(startStopBuffer); + } + + // Get stops + QJsonArray jaStops; + if((valueError = Qx::Json::checkedKeyRetrieval(jaStops, rootObj, Json::Object_Services::KEY_STOP)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Parse starts + for(const QJsonValue& jvStop : qAsConst(jaStops)) + { + StartStop startStopBuffer; + if((valueError = parseStartStop(startStopBuffer, jvStop)).isValid()) + return valueError; + + targetServices->stops.insert(startStopBuffer); + } + + // Return invalid error on success + return Qx::GenericError(); +} + +Qx::GenericError ServicesReader::parseServerDaemon(ServerDaemon& serverBuffer, const QJsonValue& jvServer) +{ + // Ensure array element is Object + if(!jvServer.isObject()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); + + // Get server Object + QJsonObject joServer = jvServer.toObject(); + + // Value error checking buffer + Qx::GenericError valueError; + + // Get direct values + if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.name, joServer, Json::Object_ServerDaemon::KEY_NAME)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.path, joServer, Json::Object_ServerDaemon::KEY_PATH)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.filename, joServer, Json::Object_ServerDaemon::KEY_FILENAME)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.kill, joServer, Json::Object_ServerDaemon::KEY_KILL)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Get arguments + QJsonArray jaArgs; + if((valueError = Qx::Json::checkedKeyRetrieval(jaArgs, joServer, Json::Object_ServerDaemon::KEY_ARGUMENTS)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + for(const QJsonValue& jvArg : qAsConst(jaArgs)) + { + // Ensure array element is String + if(!jvArg.isString()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); + + serverBuffer.arguments.append(jvArg.toString()); + } + + // Resolve macros for relevant variables + serverBuffer.path = mHostMacroResolver->resolve(serverBuffer.path); + for(QString& arg : serverBuffer.arguments) + arg = mHostMacroResolver->resolve(arg); + + // Return invalid error on success + return Qx::GenericError(); +} + +Qx::GenericError ServicesReader::parseStartStop(StartStop& startStopBuffer, const QJsonValue& jvStartStop) +{ + // Ensure return buffer is null + startStopBuffer = StartStop(); + + // Ensure array element is Object + if(!jvStartStop.isObject()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); + + // Get server Object + QJsonObject joStartStop = jvStartStop.toObject(); + + // Value error checking buffer + Qx::GenericError valueError; + + // Get direct values + if((valueError = Qx::Json::checkedKeyRetrieval(startStopBuffer.path, joStartStop, Json::Object_StartStop::KEY_PATH)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + if((valueError = Qx::Json::checkedKeyRetrieval(startStopBuffer.filename, joStartStop, Json::Object_StartStop::KEY_FILENAME)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + // Get arguments + QJsonArray jaArgs; + if((valueError = Qx::Json::checkedKeyRetrieval(jaArgs, joStartStop, Json::Object_StartStop::KEY_ARGUMENTS)).isValid()) + return valueError.setErrorLevel(Qx::GenericError::Critical); + + for(const QJsonValue& jvArg : qAsConst(jaArgs)) + { + // Ensure array element is String + if(!jvArg.isString()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); + + startStopBuffer.arguments.append(jvArg.toString()); + } + + // Resolve macros for relevant variables + startStopBuffer.path = mHostMacroResolver->resolve(startStopBuffer.path); + for(QString& arg : startStopBuffer.arguments) + arg = mHostMacroResolver->resolve(arg); + + // Return invalid error on success + return Qx::GenericError(); +} + +} diff --git a/lib/src/settings/fp-settings.cpp b/lib/src/settings/fp-settings.cpp new file mode 100644 index 0000000..c610dee --- /dev/null +++ b/lib/src/settings/fp-settings.cpp @@ -0,0 +1,72 @@ +// Unit Includes +#include "fp/settings/fp-settings.h" + +// Qt Includes +#include +#include +#include + +// Qx Includes +#include +#include + +namespace Fp +{ + +//=============================================================================================================== +// SettingsReader +//=============================================================================================================== + +//-Constructor-------------------------------------------------------------------------------------------------------- +//Public: +SettingsReader::SettingsReader(Settings* targetSettings, std::shared_ptr sourceJsonFile) : + mTargetSettings(targetSettings), + mSourceJsonFile(sourceJsonFile) +{} + +//-Class Functions------------------------------------------------------------------------------------------------- +//Protected: +Qx::GenericError SettingsReader::retrieveBasicKeys(QList keyValuePairs, const QJsonObject& obj) +{ + for(const KeyValuePtr& kvp : keyValuePairs) + { + QStringView key = kvp.key; + auto fn = [&obj, &key](const auto& vPtr)->Qx::GenericError{ + Q_ASSERT(vPtr); + return Qx::Json::checkedKeyRetrieval(*vPtr, obj, key); + }; + if(auto e = std::visit(fn, kvp.val); e.isValid()) + return e; + } + + return Qx::GenericError(); +} + +//-Instance Functions------------------------------------------------------------------------------------------------- +//Public: +Qx::GenericError SettingsReader::readInto() +{ + // Load original JSON file + QByteArray settingsData; + Qx::IoOpReport settingsLoadReport = Qx::readBytesFromFile(settingsData, *mSourceJsonFile); + + if(settingsLoadReport.isFailure()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), settingsLoadReport.outcomeInfo()); + + // Parse original JSON data + QJsonParseError parseError; + QJsonDocument settingsDocument = QJsonDocument::fromJson(settingsData, &parseError); + + if(settingsDocument.isNull()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), parseError.errorString()); + else + { + // Ensure top level container is object + if(!settingsDocument.isObject()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); + + return parseDocument(settingsDocument); + } +} + +} From 539ebe4bbebebe0cb9401aece4676f86bc6cdeee Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Mon, 3 Jul 2023 19:00:54 -0400 Subject: [PATCH 03/29] Add GameData item --- lib/include/fp/fp-db.h | 5 ++- lib/include/fp/fp-items.h | 69 +++++++++++++++++++++++++++++++++++++++ lib/src/fp-items.cpp | 48 +++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) diff --git a/lib/include/fp/fp-db.h b/lib/include/fp/fp-db.h index 30708d0..f0a746b 100644 --- a/lib/include/fp/fp-db.h +++ b/lib/include/fp/fp-db.h @@ -75,8 +75,11 @@ class FP_FP_EXPORT Db : public QObject static inline const QString COL_PATH = "path"; static inline const QString COL_SIZE = "size"; static inline const QString COL_PARAM = "parameters"; + static inline const QString COL_APP_PATH = "applicationPath"; + static inline const QString COL_LAUNCH_COMMAND = "launchCommand"; - static inline const QStringList COLUMN_LIST = {COL_ID, COL_GAME_ID, COL_TITLE, COL_DATE_ADDED, COL_SHA256, COL_CRC32, COL_PRES_ON_DISK, COL_PATH, COL_SIZE, COL_PARAM}; + static inline const QStringList COLUMN_LIST = {COL_ID, COL_GAME_ID, COL_TITLE, COL_DATE_ADDED, COL_SHA256, COL_CRC32, COL_PRES_ON_DISK, COL_PATH, COL_SIZE, COL_PARAM, + COL_APP_PATH, COL_LAUNCH_COMMAND}; }; class Table_Add_App diff --git a/lib/include/fp/fp-items.h b/lib/include/fp/fp-items.h index ce0f748..8b7b305 100644 --- a/lib/include/fp/fp-items.h +++ b/lib/include/fp/fp-items.h @@ -115,6 +115,75 @@ class FP_FP_EXPORT Game::Builder Game build(); }; +class FP_FP_EXPORT GameData +{ +//-Inner Classes---------------------------------------------------------------------------------------------------- +public: + class Builder; + +//-Instance Variables----------------------------------------------------------------------------------------------- +private: + quint32 mId; + QUuid mGameId; + QString mTitle; + QDateTime mDateAdded; + QString mSha256; + quint32 mCrc32; + bool mPresentOnDisk; + QString mPath; + quint32 mSize; + QString mParameters; + QString mAppPath; + QString mLaunchCommand; + +//-Constructor------------------------------------------------------------------------------------------------- +public: + GameData(); + +//-Instance Functions------------------------------------------------------------------------------------------ +public: + quint32 id() const; + QUuid gameId() const; + QString title() const; + QDateTime dateAdded() const; + QString sha256() const; + quint32 crc32() const; + bool presentOnDisk() const; + QString path() const; + quint32 size() const; + QString parameters() const; + QString appPath() const; + QString launchCommand() const; +}; + +class FP_FP_EXPORT GameData::Builder +{ +//-Instance Variables------------------------------------------------------------------------------------------ +private: + GameData mGameDataBlueprint; + +//-Constructor------------------------------------------------------------------------------------------------- +public: + Builder(); + +//-Instance Functions------------------------------------------------------------------------------------------ +public: + Builder& wId(QStringView rawId); + Builder& wGameId(QStringView rawId); + Builder& wTitle(const QString& title); + Builder& wDateAdded(QStringView rawDateAdded); + Builder& wSha256(const QString& sha256); + Builder& wCrc32(QStringView rawCrc32); + Builder& wPresentOnDisk(QStringView rawBroken); + Builder& wPath(const QString& path); + Builder& wSize(QStringView rawSize); + Builder& wParameters(const QString& parameters); + Builder& wAppPath(const QString& appPath); + Builder& wLaunchCommand(const QString& launchCommand); + + GameData build(); +}; + class FP_FP_EXPORT AddApp { //-Inner Classes---------------------------------------------------------------------------------------------------- diff --git a/lib/src/fp-items.cpp b/lib/src/fp-items.cpp index c920cfb..386b860 100644 --- a/lib/src/fp-items.cpp +++ b/lib/src/fp-items.cpp @@ -95,6 +95,54 @@ Game::Builder& Game::Builder::wPlatformName(QString platformName) { mGameBluepri Game Game::Builder::build() { return mGameBlueprint; } +//=============================================================================================================== +// GameData +//=============================================================================================================== + +//-Constructor------------------------------------------------------------------------------------------------ +//Public: +GameData::GameData() {} + +//-Instance Functions------------------------------------------------------------------------------------------------ +//Public: +quint32 GameData::id() const { return mId; } +QUuid GameData::gameId() const { return mGameId; } +QString GameData::title() const { return mTitle; } +QDateTime GameData::dateAdded() const { return mDateAdded; } +QString GameData::sha256() const { return mSha256; } +quint32 GameData::crc32() const { return mCrc32; } +bool GameData::presentOnDisk() const { return mPresentOnDisk; } +QString GameData::path() const { return mPath; } +quint32 GameData::size() const { return mSize; } +QString GameData::parameters() const { return mParameters; } +QString GameData::appPath() const { return mAppPath; } +QString GameData::launchCommand() const { return mLaunchCommand; } + +//=============================================================================================================== +// GameData::Builder +//=============================================================================================================== + +//-Constructor------------------------------------------------------------------------------------------------- +//Public: +GameData::Builder::Builder() {} + +//-Instance Functions------------------------------------------------------------------------------------------ +//Public: +GameData::Builder& GameData::Builder::wId(QStringView rawId) { mGameDataBlueprint.mId = rawId.toInt(); return *this; } +GameData::Builder& GameData::Builder::wGameId(QStringView rawId) { mGameDataBlueprint.mGameId = QUuid(rawId); return *this; } +GameData::Builder& GameData::Builder::wTitle(const QString& title) { mGameDataBlueprint.mTitle = title; return *this; } +GameData::Builder& GameData::Builder::wDateAdded(QStringView rawDateAdded) { mGameDataBlueprint.mDateAdded = QDateTime::fromString(rawDateAdded, Qt::ISODateWithMs); return *this; } +GameData::Builder& GameData::Builder::wSha256(const QString& sha256) { mGameDataBlueprint.mSha256 = sha256; return *this; } +GameData::Builder& GameData::Builder::wCrc32(QStringView rawCrc32) { mGameDataBlueprint.mCrc32 = rawCrc32.toInt(); return *this; } +GameData::Builder& GameData::Builder::wPresentOnDisk(QStringView rawBroken) { mGameDataBlueprint.mPresentOnDisk = rawBroken.toInt() != 0; return *this; } +GameData::Builder& GameData::Builder::wPath(const QString& path) { mGameDataBlueprint.mPath = path; return *this; } +GameData::Builder& GameData::Builder::wSize(QStringView rawSize) { mGameDataBlueprint.mSize = rawSize.toInt(); return *this; } +GameData::Builder& GameData::Builder::wParameters(const QString& parameters) { mGameDataBlueprint.mParameters = parameters; return *this; } +GameData::Builder& GameData::Builder::wAppPath(const QString& appPath) { mGameDataBlueprint.mAppPath = appPath; return *this; } +GameData::Builder& GameData::Builder::wLaunchCommand(const QString& launchCommand) { mGameDataBlueprint.mLaunchCommand = launchCommand; return *this; } + +GameData GameData::Builder::build() { return mGameDataBlueprint; } + //=============================================================================================================== // AddApp //=============================================================================================================== From 7f04fdd28819859ea00002b9dc2e3f492febbc2f Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Mon, 3 Jul 2023 23:58:17 -0400 Subject: [PATCH 04/29] Add convenience database getters for Game/AddApp and GameData --- lib/include/fp/fp-db.h | 18 ++++++- lib/include/fp/fp-items.h | 4 ++ lib/src/fp-db.cpp | 110 +++++++++++++++++++++++++++++++++++++- lib/src/fp-items.cpp | 8 ++- 4 files changed, 136 insertions(+), 4 deletions(-) diff --git a/lib/include/fp/fp-db.h b/lib/include/fp/fp-db.h index f0a746b..81eff4f 100644 --- a/lib/include/fp/fp-db.h +++ b/lib/include/fp/fp-db.h @@ -12,6 +12,11 @@ // Qx Includes #include +// Project Includes +#include "fp/fp-items.h" + +using namespace Qt::Literals::StringLiterals; + namespace Fp { @@ -240,6 +245,13 @@ class FP_FP_EXPORT Db : public QObject static inline const QString ERR_MISSING_TABLE = "The Flashpoint database is missing expected tables."; static inline const QString ERR_TABLE_MISSING_COLUMN = "The Flashpoint database tables are missing expected columns."; + // Error - Helper + static inline const QString ERR_UNEXPECTED_SQL = u"Unexpected SQL error while querying the Flashpoint database:"_s; + static inline const QString ERR_ID_NOT_FOUND = u"An entry matching the specified ID could not be found in the Flashpoint database."_s; + static inline const QString ERR_TITLE_NOT_FOUND = u"The provided title was not found in the Flashpoint database."_s; + static inline const QString ERR_ID_DUPLICATE_ENTRY_P = u"Multiple entries with the specified ID were found."_s; + static inline const QString ERR_ID_DUPLICATE_ENTRY_S = u"This should not be possible and may indicate an error within the Flashpoint database"_s; + //-Instance Variables----------------------------------------------------------------------------------------------- private: @@ -297,7 +309,7 @@ class FP_FP_EXPORT Db : public QObject // Queries - CLIFp QSqlError queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter); - QSqlError queryEntryDataById(QueryBuffer& resultBuffer, QUuid appId); + QSqlError queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId); QSqlError queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter filter); // Info @@ -307,6 +319,10 @@ class FP_FP_EXPORT Db : public QObject // Checks QSqlError entryUsesDataPack(bool& resultBuffer, QUuid gameId); + // Helper + Qx::GenericError getEntry(std::variant& entry, const QUuid& entryId); + Qx::GenericError getGameData(GameData& data, const QUuid& gameId); + //-Slots ------------------------------------------------------------------------------------------------------ private: void connectedThreadDestroyed(QObject* thread); diff --git a/lib/include/fp/fp-items.h b/lib/include/fp/fp-items.h index 8b7b305..af7afdb 100644 --- a/lib/include/fp/fp-items.h +++ b/lib/include/fp/fp-items.h @@ -123,6 +123,8 @@ class FP_FP_EXPORT GameData //-Instance Variables----------------------------------------------------------------------------------------------- private: + bool mNull; + quint32 mId; QUuid mGameId; QString mTitle; @@ -142,6 +144,8 @@ class FP_FP_EXPORT GameData //-Instance Functions------------------------------------------------------------------------------------------ public: + bool isNull() const; + quint32 id() const; QUuid gameId() const; QString title() const; diff --git a/lib/src/fp-db.cpp b/lib/src/fp-db.cpp index 354df6a..af25075 100644 --- a/lib/src/fp-db.cpp +++ b/lib/src/fp-db.cpp @@ -3,6 +3,7 @@ // Qx Includes #include +#include namespace Fp { @@ -608,7 +609,7 @@ QSqlError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) return QSqlError(); } -QSqlError Db::queryEntryDataById(QueryBuffer& resultBuffer, QUuid appId) +QSqlError Db::queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId) { // Ensure return buffer is effectively null resultBuffer = QueryBuffer(); @@ -702,6 +703,113 @@ QSqlError Db::entryUsesDataPack(bool& resultBuffer, QUuid gameId) return QSqlError(); } +Qx::GenericError Db::getEntry(std::variant& entry, const QUuid& entryId) +{ + // Find title + Db::EntryFilter mainFilter{.type = Fp::Db::EntryType::PrimaryThenAddApp, .id = entryId}; + + Fp::Db::QueryBuffer searchResult; + QSqlError searchError = queryEntrys(searchResult, mainFilter); + if(searchError.isValid()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_UNEXPECTED_SQL, searchError.text()); + + // Check if ID was found and that only one instance was found + if(searchResult.size == 0) + return Qx::GenericError(Qx::GenericError::Critical, ERR_ID_NOT_FOUND); + else if(searchResult.size > 1) + return Qx::GenericError(Qx::GenericError::Critical, ERR_ID_DUPLICATE_ENTRY_P, ERR_ID_DUPLICATE_ENTRY_S); + + // Advance result to only record + searchResult.result.next(); + + // Fill variant + if(searchResult.source == Db::Table_Add_App::NAME) + { + AddApp::Builder fpAab; + fpAab.wId(searchResult.result.value(Fp::Db::Table_Add_App::COL_ID).toString()); + fpAab.wAppPath(searchResult.result.value(Fp::Db::Table_Add_App::COL_APP_PATH).toString()); + fpAab.wAutorunBefore(searchResult.result.value(Fp::Db::Table_Add_App::COL_AUTORUN).toString()); + fpAab.wLaunchCommand(searchResult.result.value(Fp::Db::Table_Add_App::COL_LAUNCH_COMMAND).toString()); + fpAab.wName(searchResult.result.value(Fp::Db::Table_Add_App::COL_NAME).toString().remove(Qx::RegularExpression::LINE_BREAKS)); + fpAab.wWaitExit(searchResult.result.value(Fp::Db::Table_Add_App::COL_WAIT_EXIT).toString()); + fpAab.wParentId(searchResult.result.value(Fp::Db::Table_Add_App::COL_PARENT_ID).toString()); + + entry = fpAab.build(); + } + else if(searchResult.source == Db::Table_Game::NAME) + { + Game::Builder fpGb; + fpGb.wId(searchResult.result.value(Fp::Db::Table_Game::COL_ID).toString()); + fpGb.wTitle(searchResult.result.value(Fp::Db::Table_Game::COL_TITLE).toString().remove(Qx::RegularExpression::LINE_BREAKS)); + fpGb.wSeries(searchResult.result.value(Fp::Db::Table_Game::COL_SERIES).toString().remove(Qx::RegularExpression::LINE_BREAKS)); + fpGb.wDeveloper(searchResult.result.value(Fp::Db::Table_Game::COL_DEVELOPER).toString().remove(Qx::RegularExpression::LINE_BREAKS)); + fpGb.wPublisher(searchResult.result.value(Fp::Db::Table_Game::COL_PUBLISHER).toString().remove(Qx::RegularExpression::LINE_BREAKS)); + fpGb.wDateAdded(searchResult.result.value(Fp::Db::Table_Game::COL_DATE_ADDED).toString()); + fpGb.wDateModified(searchResult.result.value(Fp::Db::Table_Game::COL_DATE_MODIFIED).toString()); + fpGb.wBroken(searchResult.result.value(Fp::Db::Table_Game::COL_BROKEN).toString()); + fpGb.wPlayMode(searchResult.result.value(Fp::Db::Table_Game::COL_PLAY_MODE).toString()); + fpGb.wStatus(searchResult.result.value(Fp::Db::Table_Game::COL_STATUS).toString()); + fpGb.wNotes(searchResult.result.value(Fp::Db::Table_Game::COL_NOTES).toString()); + fpGb.wSource(searchResult.result.value(Fp::Db::Table_Game::COL_SOURCE).toString().remove(Qx::RegularExpression::LINE_BREAKS)); + fpGb.wAppPath(searchResult.result.value(Fp::Db::Table_Game::COL_APP_PATH).toString()); + fpGb.wLaunchCommand(searchResult.result.value(Fp::Db::Table_Game::COL_LAUNCH_COMMAND).toString()); + fpGb.wReleaseDate(searchResult.result.value(Fp::Db::Table_Game::COL_RELEASE_DATE).toString()); + fpGb.wVersion(searchResult.result.value(Fp::Db::Table_Game::COL_VERSION).toString().remove(Qx::RegularExpression::LINE_BREAKS)); + fpGb.wOriginalDescription(searchResult.result.value(Fp::Db::Table_Game::COL_ORIGINAL_DESC).toString()); + fpGb.wLanguage(searchResult.result.value(Fp::Db::Table_Game::COL_LANGUAGE).toString().remove(Qx::RegularExpression::LINE_BREAKS)); + fpGb.wOrderTitle(searchResult.result.value(Fp::Db::Table_Game::COL_ORDER_TITLE).toString().remove(Qx::RegularExpression::LINE_BREAKS)); + fpGb.wLibrary(searchResult.result.value(Fp::Db::Table_Game::COL_LIBRARY).toString()); + fpGb.wPlatformName(searchResult.result.value(Fp::Db::Table_Game::COL_PLATFORM_NAME).toString()); + + entry = fpGb.build(); + } + else + qFatal("Entry search result source must be 'game' or 'additional_app'"); + + return Qx::GenericError(); +} + +Qx::GenericError Db::getGameData(GameData& data, const QUuid& gameId) +{ + // Clear buffer + data = GameData(); + + // Get entry data + QSqlError searchError; + Fp::Db::QueryBuffer searchResult; + + if((searchError = queryEntryDataById(searchResult, gameId)).isValid()) + return Qx::GenericError(Qx::GenericError::Critical, ERR_UNEXPECTED_SQL, searchError.text()); + + // Check if ID was found and if so that only one instance was found + if(searchResult.size == 0) + return Qx::GenericError(); // Game doesn't have data pack + else if(searchResult.size > 1) + return Qx::GenericError(Qx::GenericError::Critical, ERR_ID_DUPLICATE_ENTRY_P, ERR_ID_DUPLICATE_ENTRY_S); + + // Advance result to only record + searchResult.result.next(); + + // Fill buffer + GameData::Builder fpGdb; + fpGdb.wId(searchResult.result.value(Fp::Db::Table_Game_Data::COL_ID).toString()); + fpGdb.wGameId(searchResult.result.value(Fp::Db::Table_Game_Data::COL_GAME_ID).toString()); + fpGdb.wTitle(searchResult.result.value(Fp::Db::Table_Game_Data::COL_TITLE).toString()); + fpGdb.wDateAdded(searchResult.result.value(Fp::Db::Table_Game_Data::COL_DATE_ADDED).toString()); + fpGdb.wSha256(searchResult.result.value(Fp::Db::Table_Game_Data::COL_SHA256).toString()); + fpGdb.wCrc32(searchResult.result.value(Fp::Db::Table_Game_Data::COL_CRC32).toString()); + fpGdb.wPresentOnDisk(searchResult.result.value(Fp::Db::Table_Game_Data::COL_PRES_ON_DISK).toString()); + fpGdb.wPath(searchResult.result.value(Fp::Db::Table_Game_Data::COL_PATH).toString()); + fpGdb.wSize(searchResult.result.value(Fp::Db::Table_Game_Data::COL_SIZE).toString()); + fpGdb.wParameters(searchResult.result.value(Fp::Db::Table_Game_Data::COL_PARAM).toString()); + fpGdb.wAppPath(searchResult.result.value(Fp::Db::Table_Game_Data::COL_APP_PATH).toString()); + fpGdb.wLaunchCommand(searchResult.result.value(Fp::Db::Table_Game_Data::COL_LAUNCH_COMMAND).toString()); + + data = fpGdb.build(); + + return Qx::GenericError(); +} + //-Slots ------------------------------------------------------------------------------------------------------ //Private: void Db::connectedThreadDestroyed(QObject* thread) diff --git a/lib/src/fp-items.cpp b/lib/src/fp-items.cpp index 386b860..20d1e39 100644 --- a/lib/src/fp-items.cpp +++ b/lib/src/fp-items.cpp @@ -101,10 +101,14 @@ Game Game::Builder::build() { return mGameBlueprint; } //-Constructor------------------------------------------------------------------------------------------------ //Public: -GameData::GameData() {} +GameData::GameData() : + mNull(true) +{} //-Instance Functions------------------------------------------------------------------------------------------------ //Public: +bool GameData::isNull() const { return mNull; } + quint32 GameData::id() const { return mId; } QUuid GameData::gameId() const { return mGameId; } QString GameData::title() const { return mTitle; } @@ -141,7 +145,7 @@ GameData::Builder& GameData::Builder::wParameters(const QString& parameters) { m GameData::Builder& GameData::Builder::wAppPath(const QString& appPath) { mGameDataBlueprint.mAppPath = appPath; return *this; } GameData::Builder& GameData::Builder::wLaunchCommand(const QString& launchCommand) { mGameDataBlueprint.mLaunchCommand = launchCommand; return *this; } -GameData GameData::Builder::build() { return mGameDataBlueprint; } +GameData GameData::Builder::build() { mGameDataBlueprint.mNull = false; return mGameDataBlueprint; } //=============================================================================================================== // AddApp From 522ddb007fdbdc8a92c47e58940bcdb1bafe8f06 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Wed, 12 Jul 2023 05:08:51 -0400 Subject: [PATCH 05/29] Conform to newer Qx overhauls Namely: - Qx::Error interface - Qx JSON parsing --- CMakeLists.txt | 2 +- lib/include/fp/fp-db.h | 70 ++++-- lib/include/fp/fp-install.h | 19 +- lib/include/fp/settings/fp-config.h | 4 +- lib/include/fp/settings/fp-execs.h | 7 +- lib/include/fp/settings/fp-preferences.h | 28 ++- lib/include/fp/settings/fp-services.h | 29 ++- lib/include/fp/settings/fp-settings.h | 30 +-- lib/src/fp-db.cpp | 63 ++++-- lib/src/fp-install.cpp | 45 ++-- lib/src/settings/fp-config.cpp | 27 +-- lib/src/settings/fp-execs.cpp | 67 +----- lib/src/settings/fp-preferences.cpp | 260 ++--------------------- lib/src/settings/fp-services.cpp | 210 ++---------------- lib/src/settings/fp-settings.cpp | 30 +-- 15 files changed, 235 insertions(+), 656 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 29359a1..1a4e12b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ set(LIBFP_QX_COMPONENTS include(OB/FetchQx) ob_fetch_qx( - REF "90098afc6b84ce0c833fa0121235b9eafd2211e6" + REF "d32e81de4c7eca233de826944f2a4d60059da83a" COMPONENTS ${LIBFP_QX_COMPONENTS} ) diff --git a/lib/include/fp/fp-db.h b/lib/include/fp/fp-db.h index 81eff4f..736dffa 100644 --- a/lib/include/fp/fp-db.h +++ b/lib/include/fp/fp-db.h @@ -10,7 +10,7 @@ #include // Qx Includes -#include +#include // Project Includes #include "fp/fp-items.h" @@ -20,6 +20,55 @@ using namespace Qt::Literals::StringLiterals; namespace Fp { +class FP_FP_EXPORT QX_ERROR_TYPE(DbError, "Fp::DbError", 1101) +{ + friend class Db; +//-Class Enums------------------------------------------------------------- +public: + enum Type + { + NoError = 0, + SqlError = 1, + InvalidSchema = 2, + IdCollision = 3, + IncompleteSearch = 4 + }; + +//-Class Variables------------------------------------------------------------- +private: + static inline const QHash ERR_STRINGS{ + {NoError, QSL("No error occurred.")}, + {SqlError, QSL("An unexpected SQL error occurred.")}, + {InvalidSchema, QSL("The schema of the database was different than expected.")}, + {IdCollision, QSL("A duplicate of a unique ID was found.")}, + {IncompleteSearch, QSL("A data search could not be completed.")} + }; + +//-Instance Variables------------------------------------------------------------- +private: + Type mType; + QString mCause; + QString mDetails; + +//-Class Constructor------------------------------------------------------------- +private: + DbError(Type t = NoError, const QString& c = {}, const QString& d = {}); + +//-Instance Functions------------------------------------------------------------- +private: + Qx::Severity deriveSeverity() const override; + quint32 deriveValue() const override; + QString derivePrimary() const override; + QString deriveSecondary() const override; + QString deriveDetails() const override; + +public: + bool isValid() const; + Type type() const; + QString cause() const; + QString details() const; +}; + class FP_FP_EXPORT Db : public QObject { //-QObject Macro (Required for all QObject Derived Classes)----------------------------------------------------------- @@ -241,22 +290,15 @@ class FP_FP_EXPORT Db : public QObject static inline const QString GAME_AND_ANIM_FILTER = "(" + GAME_ONLY_FILTER + " OR " + ANIM_ONLY_FILTER + ")"; // Error - static inline const QString ERR_DATABASE = "Flashpoint Database Error:"; static inline const QString ERR_MISSING_TABLE = "The Flashpoint database is missing expected tables."; static inline const QString ERR_TABLE_MISSING_COLUMN = "The Flashpoint database tables are missing expected columns."; - - // Error - Helper - static inline const QString ERR_UNEXPECTED_SQL = u"Unexpected SQL error while querying the Flashpoint database:"_s; static inline const QString ERR_ID_NOT_FOUND = u"An entry matching the specified ID could not be found in the Flashpoint database."_s; - static inline const QString ERR_TITLE_NOT_FOUND = u"The provided title was not found in the Flashpoint database."_s; - static inline const QString ERR_ID_DUPLICATE_ENTRY_P = u"Multiple entries with the specified ID were found."_s; - static inline const QString ERR_ID_DUPLICATE_ENTRY_S = u"This should not be possible and may indicate an error within the Flashpoint database"_s; - + static inline const QString ERR_ID_DUPLICATE_ENTRY = u"This should not be possible and may indicate an error within the Flashpoint database"_s; //-Instance Variables----------------------------------------------------------------------------------------------- private: bool mValid; - Qx::GenericError mError; + DbError mError; // Database information QSet mConnectedThreads; @@ -267,7 +309,7 @@ class FP_FP_EXPORT Db : public QObject //-Constructor------------------------------------------------------------------------------------------------- public: - explicit Db(QString databaseName, const Key&); + explicit Db(const QString& databaseName, const Key&); //-Destructor------------------------------------------------------------------------------------------------- public: @@ -297,7 +339,7 @@ class FP_FP_EXPORT Db : public QObject public: // Validity bool isValid(); - Qx::GenericError error(); + DbError error(); // TODO: See if these query functions can be consolidated via by better filtration arguments @@ -320,8 +362,8 @@ class FP_FP_EXPORT Db : public QObject QSqlError entryUsesDataPack(bool& resultBuffer, QUuid gameId); // Helper - Qx::GenericError getEntry(std::variant& entry, const QUuid& entryId); - Qx::GenericError getGameData(GameData& data, const QUuid& gameId); + DbError getEntry(std::variant& entry, const QUuid& entryId); + DbError getGameData(GameData& data, const QUuid& gameId); //-Slots ------------------------------------------------------------------------------------------------------ private: diff --git a/lib/include/fp/fp-install.h b/lib/include/fp/fp-install.h index b327c49..750cf92 100644 --- a/lib/include/fp/fp-install.h +++ b/lib/include/fp/fp-install.h @@ -12,6 +12,7 @@ // Qx Includes #include +#include // Project Includes #include "fp/settings/fp-config.h" @@ -41,10 +42,6 @@ enum class Edition {Ultimate, Infinity, Core}; #endif private: - - // Validity check fail reasons - static inline const QString FILE_DNE = "A required file does not exist: %1"; - // Static paths static inline const QString LAUNCHER_PATH = "Launcher/" + LAUNCHER_NAME; static inline const QString DATABASE_PATH = "Data/flashpoint.sqlite"; @@ -67,12 +64,12 @@ enum class Edition {Ultimate, Infinity, Core}; static inline const QString LOGOS_FOLDER_NAME = "Logos"; static inline const QString SCREENSHOTS_FOLDER_NAME = "Screenshots"; + // Error + static inline const QString ERR_FILE_MISSING = QSL("A required flashpoint install file is missing."); + // Settings static inline const QString MACRO_FP_PATH = ""; - // Error - static inline const QString ERR_INVALID = "Invalid Flashpoint Install:"; - // Regex static inline const QRegularExpression VERSION_NUMBER_REGEX = QRegularExpression("[fF]lashpoint (?.*?) "); @@ -83,7 +80,7 @@ enum class Edition {Ultimate, Infinity, Core}; private: // Validity bool mValid; - Qx::GenericError mError; + Qx::Error mError; // Files and directories QDir mRootDirectory; @@ -120,10 +117,10 @@ enum class Edition {Ultimate, Infinity, Core}; //-Class Functions------------------------------------------------------------------------------------------------------ private: - static QString standardImageSubPath(ImageType imageType, QUuid gameId); + static QString standardImageSubPath(QUuid gameId); public: - static Qx::GenericError appInvolvesSecurePlayer(bool& involvesBuffer, QFileInfo appInfo); + static Qx::Error appInvolvesSecurePlayer(bool& involvesBuffer, QFileInfo appInfo); //-Instance Functions------------------------------------------------------------------------------------------------------ private: @@ -132,7 +129,7 @@ enum class Edition {Ultimate, Infinity, Core}; public: // Validity bool isValid() const; - Qx::GenericError error() const; + Qx::Error error() const; // General information Edition edition() const; diff --git a/lib/include/fp/settings/fp-config.h b/lib/include/fp/settings/fp-config.h index 4410e20..0896b80 100644 --- a/lib/include/fp/settings/fp-config.h +++ b/lib/include/fp/settings/fp-config.h @@ -12,6 +12,8 @@ struct FP_FP_EXPORT Config : public Settings QString flashpointPath; bool startServer; QString server; + + QX_JSON_STRUCT(flashpointPath, startServer, server); }; class FP_FP_EXPORT ConfigReader : public SettingsReader @@ -22,7 +24,7 @@ class FP_FP_EXPORT ConfigReader : public SettingsReader //-Instance Functions------------------------------------------------------------------------------------------------- private: - Qx::GenericError parseDocument(const QJsonDocument& configDoc); + Qx::JsonError parseDocument(const QJsonDocument& configDoc); }; } diff --git a/lib/include/fp/settings/fp-execs.h b/lib/include/fp/settings/fp-execs.h index 90e7b08..2c1ee1b 100644 --- a/lib/include/fp/settings/fp-execs.h +++ b/lib/include/fp/settings/fp-execs.h @@ -17,11 +17,15 @@ struct FP_FP_EXPORT Exec QString linux; QString win32; QString wine; + + QX_JSON_STRUCT(linux, win32, wine); }; struct FP_FP_EXPORT Execs : public Settings { QList list; + + QX_JSON_STRUCT(list); }; class FP_FP_EXPORT ExecsReader : public SettingsReader @@ -32,8 +36,7 @@ class FP_FP_EXPORT ExecsReader : public SettingsReader //-Instance Functions------------------------------------------------------------------------------------------------- private: - Qx::GenericError parseDocument(const QJsonDocument& execsDoc); - Qx::GenericError parseExec(Exec& execBuffer, const QJsonValue& jvExec); + Qx::JsonError parseDocument(const QJsonDocument& execsDoc); }; } diff --git a/lib/include/fp/settings/fp-preferences.h b/lib/include/fp/settings/fp-preferences.h index c87c155..8627dac 100644 --- a/lib/include/fp/settings/fp-preferences.h +++ b/lib/include/fp/settings/fp-preferences.h @@ -15,6 +15,8 @@ struct FP_FP_EXPORT AppPathOverride QString path; QString override; bool enabled; + + QX_JSON_STRUCT(path, override, enabled); }; struct FP_FP_EXPORT GameDataSource @@ -22,6 +24,8 @@ struct FP_FP_EXPORT GameDataSource QList arguments; QString name; QString type; + + QX_JSON_STRUCT(arguments, name, type); }; //struct FP_FP_EXPORT GameMetadataSource_GamesTags @@ -37,6 +41,8 @@ struct FP_FP_EXPORT GameMetadataSource //GameMetadataSource_GamesTags games; QString name; //GameMetadataSource_GamesTags tags; + + QX_JSON_STRUCT(baseUrl, name); }; struct FP_FP_EXPORT Preferences : public Settings @@ -54,6 +60,22 @@ struct FP_FP_EXPORT Preferences : public Settings QSet nativePlatforms; QString browserModeProxy; QString server; + + QX_JSON_STRUCT( + fpfssBaseUrl, + gameDataSources, + gameMetadataSources, + imageFolderPath, + jsonFolderPath, + htdocsFolderPath, + dataPacksFolderPath, + onDemandImages, + onDemandBaseUrl, + appPathOverrides, + nativePlatforms, + browserModeProxy, + server + ); }; class FP_FP_EXPORT PreferencesReader : public SettingsReader @@ -64,11 +86,7 @@ class FP_FP_EXPORT PreferencesReader : public SettingsReader //-Instance Functions------------------------------------------------------------------------------------------------- private: - Qx::GenericError parseDocument(const QJsonDocument& prefDoc); - Qx::GenericError parseAppPathOverride(AppPathOverride& apoBuffer, const QJsonValue& jvApo); - Qx::GenericError parseNativePlatform(QString& nativePlatformBuffer, const QJsonValue& jvNativePlatform); - Qx::GenericError parseGameDataSource(GameDataSource& gdsBuffer, const QJsonValue& jvGds); - Qx::GenericError parseGameMetadataSource(GameMetadataSource& gmsBuffer, const QJsonValue& jvGms); + Qx::JsonError parseDocument(const QJsonDocument& prefDoc); }; } diff --git a/lib/include/fp/settings/fp-services.h b/lib/include/fp/settings/fp-services.h index 967b807..2e0f98b 100644 --- a/lib/include/fp/settings/fp-services.h +++ b/lib/include/fp/settings/fp-services.h @@ -26,6 +26,14 @@ struct FP_FP_EXPORT ServerDaemon QString filename; QStringList arguments; bool kill; + + QX_JSON_STRUCT( + name, + path, + filename, + arguments, + kill + ); }; struct FP_FP_EXPORT StartStop @@ -36,6 +44,12 @@ struct FP_FP_EXPORT StartStop friend bool operator== (const StartStop& lhs, const StartStop& rhs) noexcept; friend size_t qHash(const StartStop& key, size_t seed) noexcept; + + QX_JSON_STRUCT( + path, + filename, + arguments + ); }; struct FP_FP_EXPORT Services : public Settings @@ -46,7 +60,14 @@ struct FP_FP_EXPORT Services : public Settings QSet starts; QSet stops; KnownDaemons recognizedDaemons; // Non-standard - // TODO: If Settings container obj is made (see other todo), move this there + // TODO: ^If Settings container obj is made (see other todo), move this there + + QX_JSON_STRUCT( + servers, + daemons, + starts, + stops, + ); }; class FP_FP_EXPORT ServicesReader : public SettingsReader @@ -61,9 +82,9 @@ class FP_FP_EXPORT ServicesReader : public SettingsReader //-Instance Functions------------------------------------------------------------------------------------------------- private: - Qx::GenericError parseDocument(const QJsonDocument& servicesDoc); - Qx::GenericError parseServerDaemon(ServerDaemon& serverBuffer, const QJsonValue& jvServer); - Qx::GenericError parseStartStop(StartStop& startStopBuffer, const QJsonValue& jvStartStop); + Qx::JsonError parseDocument(const QJsonDocument& servicesDoc); + Qx::JsonError parseServerDaemon(ServerDaemon& serverBuffer, const QJsonValue& jvServer); + Qx::JsonError parseStartStop(StartStop& startStopBuffer, const QJsonValue& jvStartStop); }; } diff --git a/lib/include/fp/settings/fp-settings.h b/lib/include/fp/settings/fp-settings.h index 595a332..52e9747 100644 --- a/lib/include/fp/settings/fp-settings.h +++ b/lib/include/fp/settings/fp-settings.h @@ -1,5 +1,5 @@ -#ifndef FLASHPOINT_JSON_H -#define FLASHPOINT_JSON_H +#ifndef FLASHPOINT_SETTINGS_H +#define FLASHPOINT_SETTINGS_H // Shared Lib Support #include "fp/fp_export.h" @@ -11,7 +11,8 @@ #include // Qx Includes -#include +#include +#include #include namespace Fp @@ -19,21 +20,8 @@ namespace Fp struct FP_FP_EXPORT Settings {}; -using BasicJsonTypePtr = std::variant; - -struct FP_FP_EXPORT KeyValuePtr -{ - QStringView key; - BasicJsonTypePtr val; -}; - class FP_FP_EXPORT SettingsReader { -//-Class variables----------------------------------------------------------------------------------------------------- -public: - static inline const QString ERR_PARSING_JSON_DOC = "Error parsing JSON Document: %1"; - static inline const QString ERR_JSON_UNEXP_FORMAT = "Unexpected document format"; - //-Instance Variables-------------------------------------------------------------------------------------------------- protected: Settings* mTargetSettings; @@ -43,18 +31,14 @@ class FP_FP_EXPORT SettingsReader public: SettingsReader(Settings* targetSettings, std::shared_ptr sourceJsonFile); -//-Class Functions------------------------------------------------------------------------------------------------- -protected: - static Qx::GenericError retrieveBasicKeys(QList keyValuePairs, const QJsonObject& obj); //TODO: Use this more, unless switching to improved Qx::Json - //-Instance Functions------------------------------------------------------------------------------------------------- private: - virtual Qx::GenericError parseDocument(const QJsonDocument& jsonDoc) = 0; + virtual Qx::JsonError parseDocument(const QJsonDocument& jsonDoc) = 0; public: - Qx::GenericError readInto(); + Qx::Error readInto(); }; } -#endif // FLASHPOINT_JSON_H +#endif // FLASHPOINT_SETTINGS_H diff --git a/lib/src/fp-db.cpp b/lib/src/fp-db.cpp index af25075..5f9dfbd 100644 --- a/lib/src/fp-db.cpp +++ b/lib/src/fp-db.cpp @@ -8,6 +8,33 @@ namespace Fp { +//=============================================================================================================== +// DbError +//=============================================================================================================== + +//-Constructor------------------------------------------------------------------------------------------------ +//Public: +DbError::DbError(Type t, const QString& c, const QString& d): + mType(t), + mCause(c), + mDetails(d) +{} + +//-Instance Functions------------------------------------------------------------------------------------------------ +//Private: +Qx::Severity DbError::deriveSeverity() const { return Qx::Critical; } +quint32 DbError::deriveValue() const { return mType; } +QString DbError::derivePrimary() const { return ERR_STRINGS.value(mType); } +QString DbError::deriveSecondary() const { return mCause; } +QString DbError::deriveDetails() const { return mDetails; } + +//Public: +bool DbError::isValid() const { return mType != NoError; } +DbError::Type DbError::type() const { return mType; } +QString DbError::cause() const { return mCause; } +QString DbError::details() const { return mDetails; } + + //=============================================================================================================== // DB::TAG_CATEGORY //=============================================================================================================== @@ -22,7 +49,7 @@ bool operator< (const Db::TagCategory& lhs, const Db::TagCategory& rhs) noexcept //-Constructor------------------------------------------------------------------------------------------------ //Public: -Db::Db(QString databaseName, const Key&) : +Db::Db(const QString& databaseName, const Key&) : QObject(), mValid(false), // Instance is invalid until proven otherwise mDatabaseName(databaseName) @@ -36,14 +63,14 @@ Db::Db(QString databaseName, const Key&) : QSet missingTables; if((databaseError = checkDatabaseForRequiredTables(missingTables)).isValid()) { - mError = Qx::GenericError(Qx::GenericError::Critical, ERR_DATABASE, databaseError.text()); + mError = DbError(DbError::SqlError, databaseError.text()); return; } // Check if tables are missing if(!missingTables.isEmpty()) { - mError = Qx::GenericError(Qx::GenericError::Critical, ERR_MISSING_TABLE, QString(), + mError = DbError(DbError::InvalidSchema, ERR_MISSING_TABLE, QStringList(missingTables.begin(), missingTables.end()).join("\n")); return; } @@ -52,14 +79,14 @@ Db::Db(QString databaseName, const Key&) : QSet missingColumns; if((databaseError = checkDatabaseForRequiredColumns(missingColumns)).isValid()) { - mError = Qx::GenericError(Qx::GenericError::Critical, ERR_DATABASE, databaseError.text()); + mError = DbError(DbError::SqlError, databaseError.text()); return; } // Check if columns are missing if(!missingColumns.isEmpty()) { - mError = Qx::GenericError(Qx::GenericError::Critical, ERR_MISSING_TABLE, QString(), + mError = DbError(DbError::InvalidSchema, ERR_MISSING_TABLE, QStringList(missingColumns.begin(), missingColumns.end()).join("\n")); return; } @@ -67,13 +94,13 @@ Db::Db(QString databaseName, const Key&) : // Populate item members if((databaseError = populateAvailableItems()).isValid()) { - mError = Qx::GenericError(Qx::GenericError::Critical, ERR_DATABASE, databaseError.text()); + mError = DbError(DbError::SqlError, databaseError.text()); return; } if((databaseError = populateTags()).isValid()) { - mError = Qx::GenericError(Qx::GenericError::Critical, ERR_DATABASE, databaseError.text()); + mError = DbError(DbError::SqlError, databaseError.text()); return; } @@ -209,7 +236,7 @@ QSqlError Db::makeNonBindQuery(QueryBuffer& resultBuffer, QSqlDatabase* database //Public: bool Db::isValid() { return mValid; } -Qx::GenericError Db::error() { return mError; } +DbError Db::error() { return mError; } QSqlError Db::checkDatabaseForRequiredTables(QSet& missingTablesReturnBuffer) { @@ -703,7 +730,7 @@ QSqlError Db::entryUsesDataPack(bool& resultBuffer, QUuid gameId) return QSqlError(); } -Qx::GenericError Db::getEntry(std::variant& entry, const QUuid& entryId) +DbError Db::getEntry(std::variant& entry, const QUuid& entryId) { // Find title Db::EntryFilter mainFilter{.type = Fp::Db::EntryType::PrimaryThenAddApp, .id = entryId}; @@ -711,13 +738,13 @@ Qx::GenericError Db::getEntry(std::variant& entry, const QUuid& en Fp::Db::QueryBuffer searchResult; QSqlError searchError = queryEntrys(searchResult, mainFilter); if(searchError.isValid()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_UNEXPECTED_SQL, searchError.text()); + return DbError(DbError::SqlError, searchError.text()); // Check if ID was found and that only one instance was found if(searchResult.size == 0) - return Qx::GenericError(Qx::GenericError::Critical, ERR_ID_NOT_FOUND); + return DbError(DbError::IncompleteSearch, ERR_ID_NOT_FOUND); else if(searchResult.size > 1) - return Qx::GenericError(Qx::GenericError::Critical, ERR_ID_DUPLICATE_ENTRY_P, ERR_ID_DUPLICATE_ENTRY_S); + return DbError(DbError::IdCollision, ERR_ID_DUPLICATE_ENTRY); // Advance result to only record searchResult.result.next(); @@ -766,10 +793,10 @@ Qx::GenericError Db::getEntry(std::variant& entry, const QUuid& en else qFatal("Entry search result source must be 'game' or 'additional_app'"); - return Qx::GenericError(); + return DbError(); } -Qx::GenericError Db::getGameData(GameData& data, const QUuid& gameId) +DbError Db::getGameData(GameData& data, const QUuid& gameId) { // Clear buffer data = GameData(); @@ -779,13 +806,13 @@ Qx::GenericError Db::getGameData(GameData& data, const QUuid& gameId) Fp::Db::QueryBuffer searchResult; if((searchError = queryEntryDataById(searchResult, gameId)).isValid()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_UNEXPECTED_SQL, searchError.text()); + return DbError(DbError::SqlError, searchError.text()); // Check if ID was found and if so that only one instance was found if(searchResult.size == 0) - return Qx::GenericError(); // Game doesn't have data pack + return DbError(); // Game doesn't have data pack else if(searchResult.size > 1) - return Qx::GenericError(Qx::GenericError::Critical, ERR_ID_DUPLICATE_ENTRY_P, ERR_ID_DUPLICATE_ENTRY_S); + return DbError(DbError::IdCollision, ERR_ID_DUPLICATE_ENTRY); // Advance result to only record searchResult.result.next(); @@ -807,7 +834,7 @@ Qx::GenericError Db::getGameData(GameData& data, const QUuid& gameId) data = fpGdb.build(); - return Qx::GenericError(); + return DbError(); } //-Slots ------------------------------------------------------------------------------------------------------ diff --git a/lib/src/fp-install.cpp b/lib/src/fp-install.cpp index 0be6259..2c9764a 100644 --- a/lib/src/fp-install.cpp +++ b/lib/src/fp-install.cpp @@ -2,8 +2,8 @@ #include "fp/fp-install.h" // Qx Includes -#include #include +#include namespace Fp { @@ -46,47 +46,34 @@ Install::Install(QString installPath) : QFileInfo fileInfo(*file); if(!fileInfo.exists() || !fileInfo.isFile()) { - mError = Qx::GenericError(Qx::GenericError::Critical, ERR_INVALID, FILE_DNE.arg(fileInfo.filePath())); + mError = Qx::GenericError(Qx::Critical, 1, ERR_FILE_MISSING, fileInfo.filePath()); return; } } // Get settings - Qx::GenericError readReport; - ConfigReader configReader(&mConfig, mConfigJsonFile); - if((readReport = configReader.readInto()).isValid()) - { - mError = Qx::GenericError(Qx::GenericError::Critical, ERR_INVALID, readReport.primaryInfo() + " [" + readReport.secondaryInfo() + "]"); + if((mError = configReader.readInto()).isValid()) return; - } PreferencesReader prefReader(&mPreferences, mPreferencesJsonFile); - if((readReport = prefReader.readInto()).isValid()) - { - mError = Qx::GenericError(Qx::GenericError::Critical, ERR_INVALID, readReport.primaryInfo() + " [" + readReport.secondaryInfo() + "]"); + if((mError = prefReader.readInto()).isValid()) return; - } + mServicesJsonFile = std::make_shared(installPath + "/" + mPreferences.jsonFolderPath + "/" + SERVICES_JSON_NAME); mExecsJsonFile = std::make_shared(installPath + "/" + mPreferences.jsonFolderPath + "/" + EXECS_JSON_NAME); mLogosDirectory = QDir(installPath + "/" + mPreferences.imageFolderPath + '/' + LOGOS_FOLDER_NAME); mScreenshotsDirectory = QDir(installPath + "/" + mPreferences.imageFolderPath + '/' + SCREENSHOTS_FOLDER_NAME); ServicesReader servicesReader(&mServices, mServicesJsonFile, mMacroResolver); - if((readReport = servicesReader.readInto()).isValid()) - { - mError = Qx::GenericError(Qx::GenericError::Critical, ERR_INVALID, readReport.primaryInfo() + " [" + readReport.secondaryInfo() + "]"); + if((mError = servicesReader.readInto()).isValid()) return; - } if(mExecsJsonFile->exists()) // Optional { ExecsReader execsReader(&mExecs, mExecsJsonFile); - if((readReport = execsReader.readInto()).isValid()) - { - mError = Qx::GenericError(Qx::GenericError::Critical, ERR_INVALID, readReport.primaryInfo() + " [" + readReport.secondaryInfo() + "]"); + if((mError = execsReader.readInto()).isValid()) return; - } } // Add database @@ -115,14 +102,14 @@ Install::~Install() //-Class Functions------------------------------------------------------------------------------------------------ //Private: -QString Install::standardImageSubPath(ImageType imageType, QUuid gameId) +QString Install::standardImageSubPath(QUuid gameId) { QString gameIdString = gameId.toString(QUuid::WithoutBraces); return gameIdString.left(2) + '/' + gameIdString.mid(2, 2) + '/' + gameIdString + IMAGE_EXT; } //Public: -Qx::GenericError Install::appInvolvesSecurePlayer(bool& involvesBuffer, QFileInfo appInfo) +Qx::Error Install::appInvolvesSecurePlayer(bool& involvesBuffer, QFileInfo appInfo) { // Reset buffer involvesBuffer = false; @@ -130,7 +117,7 @@ Qx::GenericError Install::appInvolvesSecurePlayer(bool& involvesBuffer, QFileInf if(appInfo.fileName().contains(SECURE_PLAYER_INFO.baseName())) { involvesBuffer = true; - return Qx::GenericError(); + return Qx::Error(); } else if(appInfo.suffix().compare("bat", Qt::CaseInsensitive) == 0) { @@ -140,12 +127,12 @@ Qx::GenericError Install::appInvolvesSecurePlayer(bool& involvesBuffer, QFileInf // Check for read errors if(readReport.isFailure()) - return Qx::GenericError(Qx::GenericError::Critical, readReport.outcome(), readReport.outcomeInfo()); + return Qx::Error(readReport).setSeverity(Qx::Critical); else - return Qx::GenericError(); + return Qx::Error(); } else - return Qx::GenericError(); + return Qx::Error(); } //-Instance Functions------------------------------------------------------------------------------------------------ @@ -176,7 +163,7 @@ void Install::nullify() //Public: bool Install::isValid() const { return mValid; } -Qx::GenericError Install::error() const { return mError; } +Qx::Error Install::error() const { return mError; } Install::Edition Install::edition() const { @@ -236,13 +223,13 @@ QDir Install::extrasDirectory() const { return mExtrasDirectory; } QString Install::imageLocalPath(ImageType imageType, QUuid gameId) const { const QDir& sourceDir = imageType == ImageType::Logo ? mLogosDirectory : mScreenshotsDirectory; - return sourceDir.absolutePath() + '/' + standardImageSubPath(imageType, gameId); + return sourceDir.absolutePath() + '/' + standardImageSubPath(gameId); } QUrl Install::imageRemoteUrl(ImageType imageType, QUuid gameId) const { const QString typeFolder = (imageType == ImageType::Logo ? LOGOS_FOLDER_NAME : SCREENSHOTS_FOLDER_NAME); - return QUrl(mPreferences.onDemandBaseUrl + typeFolder + '/' + standardImageSubPath(imageType, gameId)); + return QUrl(mPreferences.onDemandBaseUrl + typeFolder + '/' + standardImageSubPath(gameId)); } const MacroResolver* Install::macroResolver() const { return mMacroResolver; } diff --git a/lib/src/settings/fp-config.cpp b/lib/src/settings/fp-config.cpp index e1d2398..9b4ad2d 100644 --- a/lib/src/settings/fp-config.cpp +++ b/lib/src/settings/fp-config.cpp @@ -1,24 +1,9 @@ // Unit Includes #include "fp/settings/fp-config.h" -// Qx Includes -#include - -using namespace Qt::Literals::StringLiterals; - namespace Fp { -namespace Json -{ - namespace Object_Config - { - const QString KEY_FLASHPOINT_PATH = u"flashpointPath"_s; // Reading this value is current redundant and unused, but this may change in the future - const QString KEY_START_SERVER = u"startServer"_s; - const QString KEY_SERVER = u"server"_s; - }; -} - //=============================================================================================================== // ConfigReader //=============================================================================================================== @@ -31,19 +16,13 @@ ConfigReader::ConfigReader(Config* targetConfig, std::shared_ptr sourceJs //-Instance Functions------------------------------------------------------------------------------------------------- //Private: -Qx::GenericError ConfigReader::parseDocument(const QJsonDocument& configDoc) +Qx::JsonError ConfigReader::parseDocument(const QJsonDocument& configDoc) { // Get derivation specific target Config* targetConfig = static_cast(mTargetSettings); - // Get values - const QList kvps{ - {Json::Object_Config::KEY_FLASHPOINT_PATH, &targetConfig->flashpointPath}, - {Json::Object_Config::KEY_START_SERVER, &targetConfig->startServer}, - {Json::Object_Config::KEY_SERVER, &targetConfig->server}, - }; - - return retrieveBasicKeys(kvps, configDoc.object()); + // Parse + return Qx::parseJson(*targetConfig, configDoc); } } diff --git a/lib/src/settings/fp-execs.cpp b/lib/src/settings/fp-execs.cpp index e8862fd..e4e6176 100644 --- a/lib/src/settings/fp-execs.cpp +++ b/lib/src/settings/fp-execs.cpp @@ -4,26 +4,8 @@ // Qx Includes #include -using namespace Qt::Literals::StringLiterals; - namespace Fp { - -namespace Json -{ - namespace Object_Execs - { - const QString KEY_EXECS = u"execs"_s; - }; - - namespace Object_Exec - { - const QString KEY_WIN32 = u"win32"_s; - const QString KEY_LINUX = u"linux"_s; - const QString KEY_WINE = u"wine"_s; - }; -} - //=============================================================================================================== // ExecsReader //=============================================================================================================== @@ -36,56 +18,13 @@ ExecsReader::ExecsReader(Execs* targetExecs, std::shared_ptr sourceJsonFi //-Instance Functions------------------------------------------------------------------------------------------------- //Private: -Qx::GenericError ExecsReader::parseDocument(const QJsonDocument& execsDoc) +Qx::JsonError ExecsReader::parseDocument(const QJsonDocument& execsDoc) { // Get derivation specific target Execs* targetExecs = static_cast(mTargetSettings); - // Value error checking buffer - QJsonObject rootObj = execsDoc.object(); - Qx::GenericError valueError; - - // Get exec entries - QJsonArray jaExecs; - if((valueError = Qx::Json::checkedKeyRetrieval(jaExecs, rootObj, Json::Object_Execs::KEY_EXECS)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse execs - for(const QJsonValue& jvExec : qAsConst(jaExecs)) - { - Exec execBuffer; - if((valueError = parseExec(execBuffer, jvExec)).isValid()) - return valueError; - - targetExecs->list.append(execBuffer); - } - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError ExecsReader::parseExec(Exec& execBuffer, const QJsonValue& jvExec) -{ - // Ensure array element is Object - if(!jvExec.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get exec Object - QJsonObject joExec = jvExec.toObject(); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get direct values (ignore errors for optional values) - if((valueError = Qx::Json::checkedKeyRetrieval(execBuffer.win32, joExec , Json::Object_Exec::KEY_WIN32)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - Qx::Json::checkedKeyRetrieval(execBuffer.linux, joExec, Json::Object_Exec::KEY_LINUX); - Qx::Json::checkedKeyRetrieval(execBuffer.wine, joExec, Json::Object_Exec::KEY_WINE); - - - // Return invalid error on success - return Qx::GenericError(); + // Parse + return Qx::parseJson(*targetExecs, execsDoc); } } diff --git a/lib/src/settings/fp-preferences.cpp b/lib/src/settings/fp-preferences.cpp index e32f854..386b0d0 100644 --- a/lib/src/settings/fp-preferences.cpp +++ b/lib/src/settings/fp-preferences.cpp @@ -4,60 +4,27 @@ // Qx Includes #include -using namespace Qt::Literals::StringLiterals; - -namespace Fp +// Configure key generator for mappable types +namespace QxJson { -namespace Json +template<> +QString keygen(const Fp::GameDataSource& value) { - namespace Object_AppPathOverride - { - const QString KEY_PATH = u"path"_s; - const QString KEY_OVERRIDE = u"override"_s; - const QString KEY_ENABLED = u"enabled"_s; - }; - - namespace Object_GameDataSource - { - const QString KEY_ARGUMENTS = u"arguments"_s; - const QString KEY_NAME = u"name"_s; - const QString KEY_TYPE = u"type"_s; - } - - namespace Object_GameMetadataSource_GamesTags - { - const QString KEY_ACTUAL_UPDATE_TIME = u"actualUpdateTime"_s; - const QString KEY_LAST_DELETE_TIME = u"lastDeleteTime"_s; - const QString KEY_LAST_UPDATE_TIME = u"latestUpdateTime"_s; - } + return value.name; +}; - namespace Object_GameMetadataSource - { - const QString KEY_BASE_URL = u"baseUrl"_s; - const QString KEY_GAMES = u"games"_s; - const QString KEY_NAME = u"name"_s; - const QString KET_TAGS = u"tags"_s; - } +template<> +QString keygen(const Fp::GameMetadataSource& value) +{ + return value.name; +}; - namespace Object_Preferences - { - const QString KEY_APP_PATH_OVERRIDES = u"appPathOverrides"_s; - const QString KEY_BROWSER_MODE_PROXY = u"browserModeProxy"_s; - const QString KEY_DATA_PACKS_FOLDER_PATH = u"dataPacksFolderPath"_s; - const QString KEY_FPFSS_BASE_URL = u"fpfssBaseUrl"_s; - const QString KEY_GAME_DATA_SOURCES = u"gameDataSources"_s; - const QString KEY_GAME_METADATA_SOURCES = u"gameMetadataSources"_s; - const QString KEY_HTDOCS_FOLDER_PATH = u"htdocsFolderPath"_s; - const QString KEY_IMAGE_FOLDER_PATH = u"imageFolderPath"_s; - const QString KEY_JSON_FOLDER_PATH = u"jsonFolderPath"_s; - const QString KEY_NATIVE_PLATFORMS = u"nativePlatforms"_s; - const QString KEY_ON_DEMAND_BASE_URL = u"onDemandBaseUrl"_s; - const QString KEY_ON_DEMAND_IMAGES = u"onDemandImages"_s; - const QString KEY_SERVER = u"server"_s; - }; } +namespace Fp +{ + //=============================================================================================================== // PreferencesReader //=============================================================================================================== @@ -70,206 +37,13 @@ PreferencesReader::PreferencesReader(Preferences* targetPreferences, std::shared //-Instance Functions------------------------------------------------------------------------------------------------- //Private: -Qx::GenericError PreferencesReader::parseDocument(const QJsonDocument& prefDoc) +Qx::JsonError PreferencesReader::parseDocument(const QJsonDocument& prefDoc) { // Get derivation specific target Preferences* targetPreferences = static_cast(mTargetSettings); - // Get values - QJsonObject rootObj = prefDoc.object(); - Qx::GenericError valueError; - - // Single value - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->fpfssBaseUrl, rootObj, Json::Object_Preferences::KEY_FPFSS_BASE_URL)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->imageFolderPath, rootObj, Json::Object_Preferences::KEY_IMAGE_FOLDER_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->jsonFolderPath, rootObj, Json::Object_Preferences::KEY_JSON_FOLDER_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->htdocsFolderPath, rootObj, Json::Object_Preferences::KEY_HTDOCS_FOLDER_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->dataPacksFolderPath, rootObj, Json::Object_Preferences::KEY_DATA_PACKS_FOLDER_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->onDemandImages, rootObj, Json::Object_Preferences::KEY_ON_DEMAND_IMAGES)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->onDemandBaseUrl, rootObj, Json::Object_Preferences::KEY_ON_DEMAND_BASE_URL)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->browserModeProxy, rootObj, Json::Object_Preferences::KEY_BROWSER_MODE_PROXY)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(targetPreferences->server, rootObj, Json::Object_Preferences::KEY_SERVER)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Get app path overrides - QJsonArray appPathOverrides; - if((valueError = Qx::Json::checkedKeyRetrieval(appPathOverrides, rootObj, Json::Object_Preferences::KEY_APP_PATH_OVERRIDES)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse app path overrides - for(const QJsonValue& jvApo : qAsConst(appPathOverrides)) - { - AppPathOverride apoBuffer; - if((valueError = parseAppPathOverride(apoBuffer, jvApo)).isValid()) - return valueError; - - targetPreferences->appPathOverrides.append(apoBuffer); - } - - // Get native platforms - QJsonArray nativePlatforms; - if((valueError = Qx::Json::checkedKeyRetrieval(nativePlatforms, rootObj, Json::Object_Preferences::KEY_NATIVE_PLATFORMS)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse native platforms - for(const QJsonValue& jvNativePlatform : qAsConst(nativePlatforms)) - { - QString nativePlatformBuffer; - if((valueError = parseNativePlatform(nativePlatformBuffer, jvNativePlatform)).isValid()) - return valueError; - - targetPreferences->nativePlatforms.insert(nativePlatformBuffer); - } - - //TODO: PARSE NEW STRUCTUTRES - - // Get game data sources - QJsonArray gameDataSources; - if((valueError = Qx::Json::checkedKeyRetrieval(gameDataSources, rootObj, Json::Object_Preferences::KEY_GAME_DATA_SOURCES)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse game data sources - for(const QJsonValue& jvGameDataSource : qAsConst(gameDataSources)) - { - GameDataSource gameDataSourceBuffer; - if((valueError = parseGameDataSource(gameDataSourceBuffer, jvGameDataSource)).isValid()) - return valueError; - - targetPreferences->gameDataSources.insert(gameDataSourceBuffer.name, gameDataSourceBuffer); - } - - // Get game data sources - QJsonArray gameMetadataSources; - if((valueError = Qx::Json::checkedKeyRetrieval(gameMetadataSources, rootObj, Json::Object_Preferences::KEY_GAME_METADATA_SOURCES)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse game data sources - for(const QJsonValue& jvGameMetadataSource : qAsConst(gameMetadataSources)) - { - GameMetadataSource gameMetadataSourceBuffer; - if((valueError = parseGameMetadataSource(gameMetadataSourceBuffer, jvGameMetadataSource)).isValid()) - return valueError; - - targetPreferences->gameMetadataSources.insert(gameMetadataSourceBuffer.name, gameMetadataSourceBuffer); - } - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError PreferencesReader::parseAppPathOverride(AppPathOverride& apoBuffer, const QJsonValue& jvApo) -{ - // Ensure array element is Object - if(!jvApo.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get app path override Object - QJsonObject joApo = jvApo.toObject(); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get direct values - if((valueError = Qx::Json::checkedKeyRetrieval(apoBuffer.path, joApo, Json::Object_AppPathOverride::KEY_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(apoBuffer.override, joApo, Json::Object_AppPathOverride::KEY_OVERRIDE)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(apoBuffer.enabled, joApo, Json::Object_AppPathOverride::KEY_ENABLED)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError PreferencesReader::parseNativePlatform(QString& nativePlatformBuffer, const QJsonValue& jvNativePlatform) -{ - // Ensure array element is String - if(!jvNativePlatform.isString()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get native platform string - nativePlatformBuffer = jvNativePlatform.toString(); - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError PreferencesReader::parseGameDataSource(GameDataSource& gdsBuffer, const QJsonValue& jvGds) -{ - // Ensure array element is Object - if(!jvGds.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get game data source Object - QJsonObject joGds = jvGds.toObject(); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get direct values - if((valueError = Qx::Json::checkedKeyRetrieval(gdsBuffer.name, joGds, Json::Object_GameDataSource::KEY_NAME)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(gdsBuffer.type, joGds, Json::Object_GameDataSource::KEY_TYPE)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Get arguments - QJsonArray arguments; - if((valueError = Qx::Json::checkedKeyRetrieval(arguments, joGds, Json::Object_GameDataSource::KEY_ARGUMENTS)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse arguments - for(const QJsonValue& jvArgument : qAsConst(arguments)) - { - if(!jvArgument.isString()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - gdsBuffer.arguments.append(jvArgument.toString()); - } - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError PreferencesReader::parseGameMetadataSource(GameMetadataSource& gmsBuffer, const QJsonValue& jvGms) -{ - // Ensure array element is Object - if(!jvGms.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get game data source Object - QJsonObject joGms = jvGms.toObject(); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get direct values - if((valueError = Qx::Json::checkedKeyRetrieval(gmsBuffer.baseUrl, joGms, Json::Object_GameMetadataSource::KEY_BASE_URL)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(gmsBuffer.name, joGms, Json::Object_GameMetadataSource::KEY_NAME)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Return invalid error on success - return Qx::GenericError(); + // Parse + return Qx::parseJson(*targetPreferences, prefDoc); } } diff --git a/lib/src/settings/fp-services.cpp b/lib/src/settings/fp-services.cpp index 238165f..1f47338 100644 --- a/lib/src/settings/fp-services.cpp +++ b/lib/src/settings/fp-services.cpp @@ -4,38 +4,20 @@ // Qx Includes #include -using namespace Qt::Literals::StringLiterals; - -namespace Fp +// Configure key generator for mappable types +namespace QxJson { -namespace Json +template<> +QString keygen(const Fp::ServerDaemon& value) { - namespace Object_ServerDaemon - { - const QString KEY_NAME = u"name"_s; - const QString KEY_PATH = u"path"_s; - const QString KEY_FILENAME = u"filename"_s; - const QString KEY_ARGUMENTS = u"arguments"_s; - const QString KEY_KILL = u"kill"_s; - }; - namespace Object_StartStop - { - const QString KEY_PATH = u"path"_s; - const QString KEY_FILENAME = u"filename"_s; - const QString KEY_ARGUMENTS = u"arguments"_s; - }; + return value.name; +}; - namespace Object_Services - { - const QString KEY_WATCH = u"watch"_s; - const QString KEY_SERVER = u"server"_s; - const QString KEY_DAEMON = u"daemon"_s; - const QString KEY_START = u"start"_s; - const QString KEY_STOP = u"stop"_s; - }; } +namespace Fp +{ //=============================================================================================================== // StartStop //=============================================================================================================== @@ -71,183 +53,31 @@ ServicesReader::ServicesReader(Services* targetServices, std::shared_ptr //-Instance Functions------------------------------------------------------------------------------------------------- //Private: -Qx::GenericError ServicesReader::parseDocument(const QJsonDocument& servicesDoc) +Qx::JsonError ServicesReader::parseDocument(const QJsonDocument& servicesDoc) { // Get derivation specific target Services* targetServices = static_cast(mTargetSettings); - // Value error checking buffer - QJsonObject rootObj = servicesDoc.object(); - Qx::GenericError valueError; - - // Get watches - // TODO: include logs + // Parse + Qx::JsonError err = Qx::parseJson(*targetServices, servicesDoc); + if(err.isValid()) + return err; - // Get servers - QJsonArray jaServers; - if((valueError = Qx::Json::checkedKeyRetrieval(jaServers, rootObj, Json::Object_Services::KEY_SERVER)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse servers - for(const QJsonValue& jvServer : qAsConst(jaServers)) + // Check for known daemons + for(const ServerDaemon& d : targetServices->daemons) { - ServerDaemon serverBuffer; - if((valueError = parseServerDaemon(serverBuffer, jvServer)).isValid()) - return valueError; - - targetServices->servers.insert(serverBuffer.name, serverBuffer); - } - - // Get daemons - QJsonArray jaDaemons; - if((valueError = Qx::Json::checkedKeyRetrieval(jaDaemons, rootObj, Json::Object_Services::KEY_DAEMON)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse daemons - for(const QJsonValue& jvDaemon : qAsConst(jaDaemons)) - { - ServerDaemon daemonBuffer; - if((valueError = parseServerDaemon(daemonBuffer, jvDaemon)).isValid()) - return valueError; - - targetServices->daemons.insert(daemonBuffer.name, daemonBuffer); - /* NOTE: If for some reason this list becomes large, use a hash instead * (e.g. if(hash.contains("NAME")){ recognizedDaemons.setFlag(hash["NAME]); } ) */ - if(daemonBuffer.name.contains("qemu", Qt::CaseInsensitive) || - daemonBuffer.filename.contains("qemu", Qt::CaseInsensitive)) + if(d.name.contains("qemu", Qt::CaseInsensitive) || + d.filename.contains("qemu", Qt::CaseInsensitive)) targetServices->recognizedDaemons.setFlag(KnownDaemon::Qemu); - else if(daemonBuffer.name.contains("docker", Qt::CaseInsensitive) || - daemonBuffer.filename.contains("docker", Qt::CaseInsensitive)) + else if(d.name.contains("docker", Qt::CaseInsensitive) || + d.filename.contains("docker", Qt::CaseInsensitive)) targetServices->recognizedDaemons.setFlag(KnownDaemon::Docker); } - // Get starts - QJsonArray jaStarts; - if((valueError = Qx::Json::checkedKeyRetrieval(jaStarts, rootObj, Json::Object_Services::KEY_START)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse starts - for(const QJsonValue& jvStart : qAsConst(jaStarts)) - { - StartStop startStopBuffer; - if((valueError = parseStartStop(startStopBuffer, jvStart)).isValid()) - return valueError; - - targetServices->starts.insert(startStopBuffer); - } - - // Get stops - QJsonArray jaStops; - if((valueError = Qx::Json::checkedKeyRetrieval(jaStops, rootObj, Json::Object_Services::KEY_STOP)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Parse starts - for(const QJsonValue& jvStop : qAsConst(jaStops)) - { - StartStop startStopBuffer; - if((valueError = parseStartStop(startStopBuffer, jvStop)).isValid()) - return valueError; - - targetServices->stops.insert(startStopBuffer); - } - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError ServicesReader::parseServerDaemon(ServerDaemon& serverBuffer, const QJsonValue& jvServer) -{ - // Ensure array element is Object - if(!jvServer.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get server Object - QJsonObject joServer = jvServer.toObject(); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get direct values - if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.name, joServer, Json::Object_ServerDaemon::KEY_NAME)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.path, joServer, Json::Object_ServerDaemon::KEY_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.filename, joServer, Json::Object_ServerDaemon::KEY_FILENAME)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(serverBuffer.kill, joServer, Json::Object_ServerDaemon::KEY_KILL)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Get arguments - QJsonArray jaArgs; - if((valueError = Qx::Json::checkedKeyRetrieval(jaArgs, joServer, Json::Object_ServerDaemon::KEY_ARGUMENTS)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - for(const QJsonValue& jvArg : qAsConst(jaArgs)) - { - // Ensure array element is String - if(!jvArg.isString()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - serverBuffer.arguments.append(jvArg.toString()); - } - - // Resolve macros for relevant variables - serverBuffer.path = mHostMacroResolver->resolve(serverBuffer.path); - for(QString& arg : serverBuffer.arguments) - arg = mHostMacroResolver->resolve(arg); - - // Return invalid error on success - return Qx::GenericError(); -} - -Qx::GenericError ServicesReader::parseStartStop(StartStop& startStopBuffer, const QJsonValue& jvStartStop) -{ - // Ensure return buffer is null - startStopBuffer = StartStop(); - - // Ensure array element is Object - if(!jvStartStop.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - // Get server Object - QJsonObject joStartStop = jvStartStop.toObject(); - - // Value error checking buffer - Qx::GenericError valueError; - - // Get direct values - if((valueError = Qx::Json::checkedKeyRetrieval(startStopBuffer.path, joStartStop, Json::Object_StartStop::KEY_PATH)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - if((valueError = Qx::Json::checkedKeyRetrieval(startStopBuffer.filename, joStartStop, Json::Object_StartStop::KEY_FILENAME)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - // Get arguments - QJsonArray jaArgs; - if((valueError = Qx::Json::checkedKeyRetrieval(jaArgs, joStartStop, Json::Object_StartStop::KEY_ARGUMENTS)).isValid()) - return valueError.setErrorLevel(Qx::GenericError::Critical); - - for(const QJsonValue& jvArg : qAsConst(jaArgs)) - { - // Ensure array element is String - if(!jvArg.isString()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - - startStopBuffer.arguments.append(jvArg.toString()); - } - - // Resolve macros for relevant variables - startStopBuffer.path = mHostMacroResolver->resolve(startStopBuffer.path); - for(QString& arg : startStopBuffer.arguments) - arg = mHostMacroResolver->resolve(arg); - - // Return invalid error on success - return Qx::GenericError(); + return Qx::JsonError(); } } diff --git a/lib/src/settings/fp-settings.cpp b/lib/src/settings/fp-settings.cpp index c610dee..e12d847 100644 --- a/lib/src/settings/fp-settings.cpp +++ b/lib/src/settings/fp-settings.cpp @@ -24,49 +24,25 @@ SettingsReader::SettingsReader(Settings* targetSettings, std::shared_ptr mSourceJsonFile(sourceJsonFile) {} -//-Class Functions------------------------------------------------------------------------------------------------- -//Protected: -Qx::GenericError SettingsReader::retrieveBasicKeys(QList keyValuePairs, const QJsonObject& obj) -{ - for(const KeyValuePtr& kvp : keyValuePairs) - { - QStringView key = kvp.key; - auto fn = [&obj, &key](const auto& vPtr)->Qx::GenericError{ - Q_ASSERT(vPtr); - return Qx::Json::checkedKeyRetrieval(*vPtr, obj, key); - }; - if(auto e = std::visit(fn, kvp.val); e.isValid()) - return e; - } - - return Qx::GenericError(); -} - //-Instance Functions------------------------------------------------------------------------------------------------- //Public: -Qx::GenericError SettingsReader::readInto() +Qx::Error SettingsReader::readInto() { // Load original JSON file QByteArray settingsData; Qx::IoOpReport settingsLoadReport = Qx::readBytesFromFile(settingsData, *mSourceJsonFile); if(settingsLoadReport.isFailure()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), settingsLoadReport.outcomeInfo()); + return settingsLoadReport; // Parse original JSON data QJsonParseError parseError; QJsonDocument settingsDocument = QJsonDocument::fromJson(settingsData, &parseError); if(settingsDocument.isNull()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), parseError.errorString()); + return Qx::Error(parseError).setSeverity(Qx::Critical); else - { - // Ensure top level container is object - if(!settingsDocument.isObject()) - return Qx::GenericError(Qx::GenericError::Critical, ERR_PARSING_JSON_DOC.arg(mSourceJsonFile->fileName()), ERR_JSON_UNEXP_FORMAT); - return parseDocument(settingsDocument); - } } } From b830905d21ba7e4b73fa2264b54c70aafe1292ff Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Thu, 13 Jul 2023 04:36:32 -0400 Subject: [PATCH 06/29] Drop GCC 10 builds due to compiler bug Experiences an ICE when expanding template pack parameters in qx-json. --- .github/workflows/build-libfp-linux.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-libfp-linux.yml b/.github/workflows/build-libfp-linux.yml index ad53bda..51a042d 100644 --- a/.github/workflows/build-libfp-linux.yml +++ b/.github/workflows/build-libfp-linux.yml @@ -18,14 +18,9 @@ jobs: fail-fast: false matrix: os: [ubuntu-20.04, ubuntu-22.04] - compiler: [gcc, clang] + compiler: [clang] lib_linkage: [shared, static] include: - - os: ubuntu-20.04 - compiler: gcc - c_comp: gcc-10 - cxx_comp: g++-10 - qt_comp: clang12 - os: ubuntu-20.04 compiler: clang c_comp: clang-12 @@ -36,6 +31,13 @@ jobs: c_comp: gcc-12 cxx_comp: g++-12 qt_comp: clang14 + lib_linkage: shared + - os: ubuntu-22.04 + compiler: gcc + c_comp: gcc-12 + cxx_comp: g++-12 + qt_comp: clang14 + lib_linkage: static - os: ubuntu-22.04 compiler: clang c_comp: clang-14 From d2914744aeaef2140dcae5da47c5f0b1ad1861cd Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Thu, 13 Jul 2023 04:49:52 -0400 Subject: [PATCH 07/29] Actions: Update to Qt 6.5.1 --- .github/workflows/build-libfp-linux.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-libfp-linux.yml b/.github/workflows/build-libfp-linux.yml index 51a042d..7f56011 100644 --- a/.github/workflows/build-libfp-linux.yml +++ b/.github/workflows/build-libfp-linux.yml @@ -60,7 +60,7 @@ jobs: - name: Install Qt (custom build) uses: oblivioncth/actions/general/install-and-cache-qt-from-ffynnon@dev with: - version: 6.4.2 + version: 6.5.1 os: linux compiler: ${{ matrix.qt_comp }} linkage: ${{ matrix.lib_linkage }} From 65fea2a6086a3c73a78e03b6655b20899ad7061f Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Thu, 13 Jul 2023 20:21:10 -0400 Subject: [PATCH 08/29] Exclusively use DbError for errors in public interface for Db --- lib/include/fp/fp-db.h | 18 +++++++---- lib/src/fp-db.cpp | 73 +++++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 40 deletions(-) diff --git a/lib/include/fp/fp-db.h b/lib/include/fp/fp-db.h index 736dffa..056ed2e 100644 --- a/lib/include/fp/fp-db.h +++ b/lib/include/fp/fp-db.h @@ -54,6 +54,10 @@ class FP_FP_EXPORT QX_ERROR_TYPE(DbError, "Fp::DbError", 1101) private: DbError(Type t = NoError, const QString& c = {}, const QString& d = {}); +//-Class Functions--------------------------------------------------------------- +private: + static DbError fromSqlError(const QSqlError& e); + //-Instance Functions------------------------------------------------------------- private: Qx::Severity deriveSeverity() const override; @@ -344,22 +348,22 @@ class FP_FP_EXPORT Db : public QObject // TODO: See if these query functions can be consolidated via by better filtration arguments // Queries - OFLIb - QSqlError queryGamesByPlatform(QList& resultBuffer, QStringList platforms, InclusionOptions inclusionOptions, + DbError queryGamesByPlatform(QList& resultBuffer, QStringList platforms, InclusionOptions inclusionOptions, std::optional*> idInclusionFilter = std::nullopt); - QSqlError queryAllAddApps(QueryBuffer& resultBuffer); - QSqlError queryAllEntryTags(QueryBuffer& resultBuffer); + DbError queryAllAddApps(QueryBuffer& resultBuffer); + DbError queryAllEntryTags(QueryBuffer& resultBuffer); // Queries - CLIFp - QSqlError queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter); - QSqlError queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId); - QSqlError queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter filter); + DbError queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter); + DbError queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId); + DbError queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter filter); // Info QStringList platformList() const; QMap tags() const; // Checks - QSqlError entryUsesDataPack(bool& resultBuffer, QUuid gameId); + DbError entryUsesDataPack(bool& resultBuffer, QUuid gameId); // Helper DbError getEntry(std::variant& entry, const QUuid& entryId); diff --git a/lib/src/fp-db.cpp b/lib/src/fp-db.cpp index 5f9dfbd..b1b3b08 100644 --- a/lib/src/fp-db.cpp +++ b/lib/src/fp-db.cpp @@ -20,6 +20,13 @@ DbError::DbError(Type t, const QString& c, const QString& d): mDetails(d) {} +//-Class Functions--------------------------------------------------------------- +//Private: +DbError DbError::fromSqlError(const QSqlError& e) +{ + return e.isValid() ? DbError(SqlError, e.text()) : DbError(); +} + //-Instance Functions------------------------------------------------------------------------------------------------ //Private: Qx::Severity DbError::deriveSeverity() const { return Qx::Critical; } @@ -400,7 +407,7 @@ QSqlError Db::populateTags() return QSqlError(); } -QSqlError Db::queryGamesByPlatform(QList& resultBuffer, QStringList platforms, InclusionOptions inclusionOptions, +DbError Db::queryGamesByPlatform(QList& resultBuffer, QStringList platforms, InclusionOptions inclusionOptions, std::optional*> idInclusionFilter) { // Ensure return buffer is reset @@ -408,13 +415,13 @@ QSqlError Db::queryGamesByPlatform(QList& resultBuffer, QStringList // Empty shortcuts if(platforms.isEmpty() || (idInclusionFilter.has_value() && idInclusionFilter.value()->isEmpty())) - return QSqlError(); + return DbError(); // Get database QSqlDatabase fpDb; QSqlError dbError = getThreadConnection(fpDb); if(dbError.isValid()) - return dbError; + return DbError::fromSqlError(dbError); // Determine game exclusion filter from tag exclusions if applicable QSet idExclusionFilter; @@ -427,7 +434,7 @@ QSqlError Db::queryGamesByPlatform(QList& resultBuffer, QStringList QSqlError tagQueryError = tagQuery.lastError(); if(tagQueryError.isValid()) - return tagQueryError; + return DbError::fromSqlError(tagQueryError); // Populate exclusion filter while(tagQuery.next()) @@ -468,7 +475,7 @@ QSqlError Db::queryGamesByPlatform(QList& resultBuffer, QStringList // Execute query and return if error occurs if(!initialQuery.exec()) - return initialQuery.lastError(); + return DbError::fromSqlError(initialQuery.lastError()); // Create size query and bind current platform QSqlQuery sizeQuery(fpDb); @@ -477,7 +484,7 @@ QSqlError Db::queryGamesByPlatform(QList& resultBuffer, QStringList // Execute query and return if error occurs if(!sizeQuery.exec()) - return sizeQuery.lastError(); + return DbError::fromSqlError(sizeQuery.lastError()); // Get query size sizeQuery.next(); @@ -488,11 +495,11 @@ QSqlError Db::queryGamesByPlatform(QList& resultBuffer, QStringList resultBuffer.append({platform, initialQuery, querySize}); } - // Return invalid SqlError - return QSqlError(); + // Return invalid error + return DbError(); } -QSqlError Db::queryAllAddApps(QueryBuffer& resultBuffer) +DbError Db::queryAllAddApps(QueryBuffer& resultBuffer) { // Ensure return buffer is effectively null resultBuffer = QueryBuffer(); @@ -501,7 +508,7 @@ QSqlError Db::queryAllAddApps(QueryBuffer& resultBuffer) QSqlDatabase fpDb; QSqlError dbError = getThreadConnection(fpDb); if(dbError.isValid()) - return dbError; + return DbError::fromSqlError(dbError); // Make query QString baseQueryCommand = "SELECT %1 FROM " + Table_Add_App::NAME; @@ -509,10 +516,10 @@ QSqlError Db::queryAllAddApps(QueryBuffer& resultBuffer) QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); resultBuffer.source = Table_Add_App::NAME; - return makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand); + return DbError::fromSqlError(makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand)); } -QSqlError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) +DbError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) { // Ensure return buffer is effectively null resultBuffer = QueryBuffer(); @@ -526,7 +533,7 @@ QSqlError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) QSqlDatabase fpDb; QSqlError dbError = getThreadConnection(fpDb); if(dbError.isValid()) - return dbError; + return DbError::fromSqlError(dbError); // Check for entry as a game first if(filter.type != EntryType::AddApp) @@ -570,11 +577,11 @@ QSqlError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) resultBuffer.source = Table_Game::NAME; if((queryError = makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand)).isValid()) - return queryError; + return DbError::fromSqlError(queryError); // Return result if one or more results were found (receiver handles situation in latter case) if(resultBuffer.size >= 1) - return QSqlError(); + return DbError(); } // Check for entry as an additional app second @@ -625,18 +632,18 @@ QSqlError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) resultBuffer.source = Table_Add_App::NAME; if((queryError = makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand)).isValid()) - return queryError; + return DbError::fromSqlError(queryError); // Return result if one or more results were found (receiver handles situation in latter case) if(resultBuffer.size >= 1) - return QSqlError(); + return DbError(); } // No result found, return - return QSqlError(); + return DbError(); } -QSqlError Db::queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId) +DbError Db::queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId) { // Ensure return buffer is effectively null resultBuffer = QueryBuffer(); @@ -645,7 +652,7 @@ QSqlError Db::queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId) QSqlDatabase fpDb; QSqlError dbError = getThreadConnection(fpDb); if(dbError.isValid()) - return dbError; + return DbError::fromSqlError(dbError); // Setup ID query QString baseQueryCommand = "SELECT %1 FROM " + Table_Game_Data::NAME + " WHERE " + @@ -657,10 +664,10 @@ QSqlError Db::queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId) QSqlError queryError; resultBuffer.source = Table_Game_Data::NAME; - return makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand); + return DbError::fromSqlError(makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand)); } -QSqlError Db::queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter includeFilter) +DbError Db::queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter includeFilter) { // Ensure return buffer is effectively null resultBuffer = QueryBuffer(); @@ -669,7 +676,7 @@ QSqlError Db::queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter includeFi QSqlDatabase fpDb; QSqlError dbError = getThreadConnection(fpDb); if(dbError.isValid()) - return dbError; + return DbError::fromSqlError(dbError); // Make query QString baseQueryCommand = "SELECT %2 FROM " + Table_Game::NAME + " WHERE " + @@ -679,13 +686,13 @@ QSqlError Db::queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter includeFi QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); resultBuffer.source = Table_Game::NAME; - return makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand); + return DbError::fromSqlError(makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand)); } QStringList Db::platformList() const { return mPlatformList; } //TODO: Probably should use RAII for this. QMap Db::tags() const { return mTagMap; } -QSqlError Db::entryUsesDataPack(bool& resultBuffer, QUuid gameId) +DbError Db::entryUsesDataPack(bool& resultBuffer, QUuid gameId) { /* NOTE: The launcher performs this check and other data pack tasks by checking if the `activeDataId` column * of the `game` table has a value, and if it does, then matching that to the `id` column in the `game_data` @@ -708,7 +715,7 @@ QSqlError Db::entryUsesDataPack(bool& resultBuffer, QUuid gameId) QSqlDatabase fpDb; QSqlError dbError = getThreadConnection(fpDb); if(dbError.isValid()) - return dbError; + return DbError::fromSqlError(dbError); // Make query QString packCheckQueryCommand = "SELECT " + GENERAL_QUERY_SIZE_COMMAND + " FROM " + Table_Game_Data::NAME + " WHERE " + @@ -720,14 +727,14 @@ QSqlError Db::entryUsesDataPack(bool& resultBuffer, QUuid gameId) // Execute query and return if error occurs if(!packCheckQuery.exec()) - return packCheckQuery.lastError(); + return DbError::fromSqlError(packCheckQuery.lastError()); // Set buffer based on result packCheckQuery.next(); resultBuffer = packCheckQuery.value(0).toInt() > 0; - // Return invalid SqlError - return QSqlError(); + // Return invalid error + return DbError(); } DbError Db::getEntry(std::variant& entry, const QUuid& entryId) @@ -736,9 +743,9 @@ DbError Db::getEntry(std::variant& entry, const QUuid& entryId) Db::EntryFilter mainFilter{.type = Fp::Db::EntryType::PrimaryThenAddApp, .id = entryId}; Fp::Db::QueryBuffer searchResult; - QSqlError searchError = queryEntrys(searchResult, mainFilter); + DbError searchError = queryEntrys(searchResult, mainFilter); if(searchError.isValid()) - return DbError(DbError::SqlError, searchError.text()); + return searchError; // Check if ID was found and that only one instance was found if(searchResult.size == 0) @@ -802,11 +809,11 @@ DbError Db::getGameData(GameData& data, const QUuid& gameId) data = GameData(); // Get entry data - QSqlError searchError; + DbError searchError; Fp::Db::QueryBuffer searchResult; if((searchError = queryEntryDataById(searchResult, gameId)).isValid()) - return DbError(DbError::SqlError, searchError.text()); + return searchError; // Check if ID was found and if so that only one instance was found if(searchResult.size == 0) From a03d31888a2c876e109b8b24e0533decc3aa21d2 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Thu, 13 Jul 2023 20:29:26 -0400 Subject: [PATCH 09/29] Allow DbError to be default constructed publically --- lib/include/fp/fp-db.h | 5 ++++- lib/src/fp-db.cpp | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/include/fp/fp-db.h b/lib/include/fp/fp-db.h index 056ed2e..9ab7840 100644 --- a/lib/include/fp/fp-db.h +++ b/lib/include/fp/fp-db.h @@ -52,7 +52,10 @@ class FP_FP_EXPORT QX_ERROR_TYPE(DbError, "Fp::DbError", 1101) //-Class Constructor------------------------------------------------------------- private: - DbError(Type t = NoError, const QString& c = {}, const QString& d = {}); + DbError(Type t, const QString& c, const QString& d = {}); + +public: + DbError(); //-Class Functions--------------------------------------------------------------- private: diff --git a/lib/src/fp-db.cpp b/lib/src/fp-db.cpp index b1b3b08..f823d9f 100644 --- a/lib/src/fp-db.cpp +++ b/lib/src/fp-db.cpp @@ -13,13 +13,18 @@ namespace Fp //=============================================================================================================== //-Constructor------------------------------------------------------------------------------------------------ -//Public: +//Private: DbError::DbError(Type t, const QString& c, const QString& d): mType(t), mCause(c), mDetails(d) {} +//Public: +DbError::DbError() : + mType(NoError) +{} + //-Class Functions--------------------------------------------------------------- //Private: DbError DbError::fromSqlError(const QSqlError& e) From d195b549101064710b9bc2bfe35136ee14ff6161 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Sat, 15 Jul 2023 05:21:47 -0400 Subject: [PATCH 10/29] Update Qx --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a4e12b..b6462c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ set(LIBFP_QX_COMPONENTS include(OB/FetchQx) ob_fetch_qx( - REF "d32e81de4c7eca233de826944f2a4d60059da83a" + REF "71a148fcacf648636cb0bcb96b3345424ac4f90d" COMPONENTS ${LIBFP_QX_COMPONENTS} ) From ecf3c78ad5c8090ef0a67b419849bb3f44f3eb34 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Mon, 17 Jul 2023 00:56:23 -0400 Subject: [PATCH 11/29] Fix settings key names --- lib/include/fp/settings/fp-services.h | 18 ++++++++---------- lib/src/settings/fp-services.cpp | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/include/fp/settings/fp-services.h b/lib/include/fp/settings/fp-services.h index 2e0f98b..9ef69f8 100644 --- a/lib/include/fp/settings/fp-services.h +++ b/lib/include/fp/settings/fp-services.h @@ -55,18 +55,18 @@ struct FP_FP_EXPORT StartStop struct FP_FP_EXPORT Services : public Settings { //QSet watches; - QHash servers; - QHash daemons; - QSet starts; - QSet stops; + QHash server; + QHash daemon; + QSet start; + QSet stop; KnownDaemons recognizedDaemons; // Non-standard // TODO: ^If Settings container obj is made (see other todo), move this there QX_JSON_STRUCT( - servers, - daemons, - starts, - stops, + server, + daemon, + start, + stop, ); }; @@ -83,8 +83,6 @@ class FP_FP_EXPORT ServicesReader : public SettingsReader //-Instance Functions------------------------------------------------------------------------------------------------- private: Qx::JsonError parseDocument(const QJsonDocument& servicesDoc); - Qx::JsonError parseServerDaemon(ServerDaemon& serverBuffer, const QJsonValue& jvServer); - Qx::JsonError parseStartStop(StartStop& startStopBuffer, const QJsonValue& jvStartStop); }; } diff --git a/lib/src/settings/fp-services.cpp b/lib/src/settings/fp-services.cpp index 1f47338..6a77168 100644 --- a/lib/src/settings/fp-services.cpp +++ b/lib/src/settings/fp-services.cpp @@ -64,7 +64,7 @@ Qx::JsonError ServicesReader::parseDocument(const QJsonDocument& servicesDoc) return err; // Check for known daemons - for(const ServerDaemon& d : targetServices->daemons) + for(const ServerDaemon& d : qAsConst(targetServices->daemon)) { /* NOTE: If for some reason this list becomes large, use a hash instead * (e.g. if(hash.contains("NAME")){ recognizedDaemons.setFlag(hash["NAME]); } ) From 3c51825a9be7638cb1bef0fd85286b06264c87ab Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Mon, 17 Jul 2023 04:29:04 -0400 Subject: [PATCH 12/29] Add helper for updating the on-disk state of game data --- lib/include/fp/fp-db.h | 9 +++++++-- lib/src/fp-db.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/include/fp/fp-db.h b/lib/include/fp/fp-db.h index 9ab7840..4bfd6ed 100644 --- a/lib/include/fp/fp-db.h +++ b/lib/include/fp/fp-db.h @@ -31,7 +31,9 @@ class FP_FP_EXPORT QX_ERROR_TYPE(DbError, "Fp::DbError", 1101) SqlError = 1, InvalidSchema = 2, IdCollision = 3, - IncompleteSearch = 4 + IncompleteSearch = 4, + UpdateIneffective = 5, + UpdateTooMany = 6 }; //-Class Variables------------------------------------------------------------- @@ -41,7 +43,9 @@ class FP_FP_EXPORT QX_ERROR_TYPE(DbError, "Fp::DbError", 1101) {SqlError, QSL("An unexpected SQL error occurred.")}, {InvalidSchema, QSL("The schema of the database was different than expected.")}, {IdCollision, QSL("A duplicate of a unique ID was found.")}, - {IncompleteSearch, QSL("A data search could not be completed.")} + {IncompleteSearch, QSL("A data search could not be completed.")}, + {UpdateIneffective, QSL("An update statement unexpectedly affected 0 rows.")}, + {UpdateTooMany, QSL("An update statement affected more rows than expected.")} }; //-Instance Variables------------------------------------------------------------- @@ -371,6 +375,7 @@ class FP_FP_EXPORT Db : public QObject // Helper DbError getEntry(std::variant& entry, const QUuid& entryId); DbError getGameData(GameData& data, const QUuid& gameId); + DbError updateGameDataOnDiskState(int packId, bool onDisk); //-Slots ------------------------------------------------------------------------------------------------------ private: diff --git a/lib/src/fp-db.cpp b/lib/src/fp-db.cpp index f823d9f..df502c1 100644 --- a/lib/src/fp-db.cpp +++ b/lib/src/fp-db.cpp @@ -849,6 +849,36 @@ DbError Db::getGameData(GameData& data, const QUuid& gameId) return DbError(); } +DbError Db::updateGameDataOnDiskState(int packId, bool onDisk) +{ + // Get database + QSqlDatabase fpDb; + QSqlError dbError = getThreadConnection(fpDb); + if(dbError.isValid()) + return DbError::fromSqlError(dbError); + + // Make query + QString dataUpdateCommand = "UPDATE " + Table_Game_Data::NAME + " SET " + Table_Game_Data::COL_PRES_ON_DISK + " = " + QString::number(onDisk) + + " WHERE " + Table_Game_Data::COL_ID + " = " + QString::number(packId); + + QSqlQuery packUpdateQuery(fpDb); + packUpdateQuery.setForwardOnly(true); + packUpdateQuery.prepare(dataUpdateCommand); + + // Execute query and return if error occurs + if(!packUpdateQuery.exec()) + return DbError::fromSqlError(packUpdateQuery.lastError()); + + // Check that expected count was affected + int rows = packUpdateQuery.numRowsAffected(); + if(rows < 1) + return DbError(DbError::UpdateIneffective, Table_Game_Data::NAME + " SET " + Table_Game_Data::COL_PRES_ON_DISK); + else if(rows > 1) + return DbError(DbError::UpdateTooMany, Table_Game_Data::NAME + " SET " + Table_Game_Data::COL_PRES_ON_DISK); + + return DbError(); +} + //-Slots ------------------------------------------------------------------------------------------------------ //Private: void Db::connectedThreadDestroyed(QObject* thread) From ae60106896bb73c3840d9c368c0edb15c7090919 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Mon, 17 Jul 2023 04:37:01 -0400 Subject: [PATCH 13/29] Use latest datapack in rare cases where an entry has more than one --- lib/src/fp-db.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/src/fp-db.cpp b/lib/src/fp-db.cpp index df502c1..177ac27 100644 --- a/lib/src/fp-db.cpp +++ b/lib/src/fp-db.cpp @@ -650,6 +650,9 @@ DbError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) DbError Db::queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId) { + // A few entries have more than one data pack. The results are sorted + // by most to least recently added + // Ensure return buffer is effectively null resultBuffer = QueryBuffer(); @@ -661,7 +664,8 @@ DbError Db::queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId) // Setup ID query QString baseQueryCommand = "SELECT %1 FROM " + Table_Game_Data::NAME + " WHERE " + - Table_Game_Data::COL_GAME_ID + " == '" + appId.toString(QUuid::WithoutBraces) + "'"; + Table_Game_Data::COL_GAME_ID + " == '" + appId.toString(QUuid::WithoutBraces) + "' " + + "ORDER BY " + Table_Game_Data::COL_DATE_ADDED + " DESC"; QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Game_Data::COLUMN_LIST.join("`,`") + "`"); QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); @@ -824,9 +828,9 @@ DbError Db::getGameData(GameData& data, const QUuid& gameId) if(searchResult.size == 0) return DbError(); // Game doesn't have data pack else if(searchResult.size > 1) - return DbError(DbError::IdCollision, ERR_ID_DUPLICATE_ENTRY); + qWarning("Entry with more than one data pack, using most recent."); - // Advance result to only record + // Advance result to first record searchResult.result.next(); // Fill buffer From 737939552cd4c6ac320e9470d2ecf48288acf485 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Mon, 17 Jul 2023 05:18:00 -0400 Subject: [PATCH 14/29] Don't open DB in read-only mode --- lib/src/fp-db.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/fp-db.cpp b/lib/src/fp-db.cpp index 177ac27..819f981 100644 --- a/lib/src/fp-db.cpp +++ b/lib/src/fp-db.cpp @@ -192,7 +192,7 @@ QSqlError Db::getThreadConnection(QSqlDatabase& connection) else { connection = QSqlDatabase::addDatabase("QSQLITE", tcn); - connection.setConnectOptions("QSQLITE_OPEN_READONLY"); + //connection.setConnectOptions("QSQLITE_OPEN_READONLY"); Lib features some DB writing now connection.setDatabaseName(mDatabaseName); if(connection.open()) From 02bc4d636bf910a4db639a12d3ba19424e235e3e Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Mon, 17 Jul 2023 05:56:39 -0400 Subject: [PATCH 15/29] Move JSON struct parsing implementation to cpp Better hides implementation details from interface. --- lib/include/fp/settings/fp-config.h | 2 -- lib/include/fp/settings/fp-execs.h | 4 --- lib/include/fp/settings/fp-preferences.h | 22 --------------- lib/include/fp/settings/fp-services.h | 21 --------------- lib/src/settings/fp-config.cpp | 7 +++++ lib/src/settings/fp-execs.cpp | 12 +++++++-- lib/src/settings/fp-preferences.cpp | 34 ++++++++++++++++++++++++ lib/src/settings/fp-services.cpp | 24 +++++++++++++++++ 8 files changed, 75 insertions(+), 51 deletions(-) diff --git a/lib/include/fp/settings/fp-config.h b/lib/include/fp/settings/fp-config.h index 0896b80..da05e22 100644 --- a/lib/include/fp/settings/fp-config.h +++ b/lib/include/fp/settings/fp-config.h @@ -12,8 +12,6 @@ struct FP_FP_EXPORT Config : public Settings QString flashpointPath; bool startServer; QString server; - - QX_JSON_STRUCT(flashpointPath, startServer, server); }; class FP_FP_EXPORT ConfigReader : public SettingsReader diff --git a/lib/include/fp/settings/fp-execs.h b/lib/include/fp/settings/fp-execs.h index 2c1ee1b..44e9032 100644 --- a/lib/include/fp/settings/fp-execs.h +++ b/lib/include/fp/settings/fp-execs.h @@ -17,15 +17,11 @@ struct FP_FP_EXPORT Exec QString linux; QString win32; QString wine; - - QX_JSON_STRUCT(linux, win32, wine); }; struct FP_FP_EXPORT Execs : public Settings { QList list; - - QX_JSON_STRUCT(list); }; class FP_FP_EXPORT ExecsReader : public SettingsReader diff --git a/lib/include/fp/settings/fp-preferences.h b/lib/include/fp/settings/fp-preferences.h index 8627dac..8a575e4 100644 --- a/lib/include/fp/settings/fp-preferences.h +++ b/lib/include/fp/settings/fp-preferences.h @@ -15,8 +15,6 @@ struct FP_FP_EXPORT AppPathOverride QString path; QString override; bool enabled; - - QX_JSON_STRUCT(path, override, enabled); }; struct FP_FP_EXPORT GameDataSource @@ -24,8 +22,6 @@ struct FP_FP_EXPORT GameDataSource QList arguments; QString name; QString type; - - QX_JSON_STRUCT(arguments, name, type); }; //struct FP_FP_EXPORT GameMetadataSource_GamesTags @@ -41,8 +37,6 @@ struct FP_FP_EXPORT GameMetadataSource //GameMetadataSource_GamesTags games; QString name; //GameMetadataSource_GamesTags tags; - - QX_JSON_STRUCT(baseUrl, name); }; struct FP_FP_EXPORT Preferences : public Settings @@ -60,22 +54,6 @@ struct FP_FP_EXPORT Preferences : public Settings QSet nativePlatforms; QString browserModeProxy; QString server; - - QX_JSON_STRUCT( - fpfssBaseUrl, - gameDataSources, - gameMetadataSources, - imageFolderPath, - jsonFolderPath, - htdocsFolderPath, - dataPacksFolderPath, - onDemandImages, - onDemandBaseUrl, - appPathOverrides, - nativePlatforms, - browserModeProxy, - server - ); }; class FP_FP_EXPORT PreferencesReader : public SettingsReader diff --git a/lib/include/fp/settings/fp-services.h b/lib/include/fp/settings/fp-services.h index 9ef69f8..ef6b349 100644 --- a/lib/include/fp/settings/fp-services.h +++ b/lib/include/fp/settings/fp-services.h @@ -26,14 +26,6 @@ struct FP_FP_EXPORT ServerDaemon QString filename; QStringList arguments; bool kill; - - QX_JSON_STRUCT( - name, - path, - filename, - arguments, - kill - ); }; struct FP_FP_EXPORT StartStop @@ -44,12 +36,6 @@ struct FP_FP_EXPORT StartStop friend bool operator== (const StartStop& lhs, const StartStop& rhs) noexcept; friend size_t qHash(const StartStop& key, size_t seed) noexcept; - - QX_JSON_STRUCT( - path, - filename, - arguments - ); }; struct FP_FP_EXPORT Services : public Settings @@ -61,13 +47,6 @@ struct FP_FP_EXPORT Services : public Settings QSet stop; KnownDaemons recognizedDaemons; // Non-standard // TODO: ^If Settings container obj is made (see other todo), move this there - - QX_JSON_STRUCT( - server, - daemon, - start, - stop, - ); }; class FP_FP_EXPORT ServicesReader : public SettingsReader diff --git a/lib/src/settings/fp-config.cpp b/lib/src/settings/fp-config.cpp index 9b4ad2d..db1732c 100644 --- a/lib/src/settings/fp-config.cpp +++ b/lib/src/settings/fp-config.cpp @@ -1,6 +1,13 @@ // Unit Includes #include "fp/settings/fp-config.h" +// Json struct parsing implementation +QX_JSON_STRUCT_OUTSIDE(Fp::Config, + flashpointPath, + startServer, + server +) + namespace Fp { diff --git a/lib/src/settings/fp-execs.cpp b/lib/src/settings/fp-execs.cpp index e4e6176..07f056b 100644 --- a/lib/src/settings/fp-execs.cpp +++ b/lib/src/settings/fp-execs.cpp @@ -1,8 +1,16 @@ // Unit Includes #include "fp/settings/fp-execs.h" -// Qx Includes -#include +// Json struct parsing implementation +QX_JSON_STRUCT_OUTSIDE(Fp::Exec, + linux, + win32, + wine +); + +QX_JSON_STRUCT_OUTSIDE(Fp::Execs, + list +); namespace Fp { diff --git a/lib/src/settings/fp-preferences.cpp b/lib/src/settings/fp-preferences.cpp index 386b0d0..2938bbd 100644 --- a/lib/src/settings/fp-preferences.cpp +++ b/lib/src/settings/fp-preferences.cpp @@ -22,6 +22,40 @@ QString keygen(const Fp::GameMetadataSource& va } +// Json struct parsing implementation +QX_JSON_STRUCT_OUTSIDE(Fp::AppPathOverride, + path, + override, + enabled +); + +QX_JSON_STRUCT_OUTSIDE(Fp::GameDataSource, + arguments, + name, + type +); + +QX_JSON_STRUCT_OUTSIDE(Fp::GameMetadataSource, + baseUrl, + name +); + +QX_JSON_STRUCT_OUTSIDE(Fp::Preferences, + fpfssBaseUrl, + gameDataSources, + gameMetadataSources, + imageFolderPath, + jsonFolderPath, + htdocsFolderPath, + dataPacksFolderPath, + onDemandImages, + onDemandBaseUrl, + appPathOverrides, + nativePlatforms, + browserModeProxy, + server +); + namespace Fp { diff --git a/lib/src/settings/fp-services.cpp b/lib/src/settings/fp-services.cpp index 6a77168..3e15183 100644 --- a/lib/src/settings/fp-services.cpp +++ b/lib/src/settings/fp-services.cpp @@ -4,6 +4,8 @@ // Qx Includes #include +// Json struct parsing implementation + // Configure key generator for mappable types namespace QxJson { @@ -16,6 +18,28 @@ QString keygen(const Fp::ServerDaemon& value) } +// Json struct parsing implementation +QX_JSON_STRUCT_OUTSIDE(Fp::ServerDaemon, + name, + path, + filename, + arguments, + kill +); + +QX_JSON_STRUCT_OUTSIDE(Fp::StartStop, + path, + filename, + arguments +); + +QX_JSON_STRUCT_OUTSIDE(Fp::Services, + server, + daemon, + start, + stop, +); + namespace Fp { //=============================================================================================================== From 078edeec20e8ee1ec23ea3b38aeda32263830554 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Mon, 17 Jul 2023 06:08:32 -0400 Subject: [PATCH 16/29] Move Db member function under correct category --- lib/include/fp/fp-db.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/include/fp/fp-db.h b/lib/include/fp/fp-db.h index 4bfd6ed..3c68591 100644 --- a/lib/include/fp/fp-db.h +++ b/lib/include/fp/fp-db.h @@ -326,10 +326,6 @@ class FP_FP_EXPORT Db : public QObject public: ~Db(); -//-Class Functions-------------------------------------------------------------------------------------------- -private: - QString threadConnectionName(const QThread* thread); - //-Instance Functions------------------------------------------------------------------------------------------------------ private: // Validity @@ -338,6 +334,7 @@ class FP_FP_EXPORT Db : public QObject // Connection void closeConnection(const QThread* thread); void closeAllConnections(); + QString threadConnectionName(const QThread* thread); QSqlError getThreadConnection(QSqlDatabase& connection); QSqlError makeNonBindQuery(QueryBuffer& resultBuffer, QSqlDatabase* database, QString queryCommand, QString sizeQueryCommand) const; From b30e069e1f1243fe38cad8aa89364bc9fb49fb88 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Mon, 17 Jul 2023 07:24:58 -0400 Subject: [PATCH 17/29] Add parsing of JSON playlists Also matches Fp::Playlist and Fp::PlaylistGame to the new JSON layout in which each Playlist directly contains its children. --- lib/CMakeLists.txt | 2 + lib/include/fp/fp-install.h | 8 ++ lib/include/fp/fp-items.h | 85 ++++++++-------- lib/include/fp/fp-playlistmanager.h | 55 ++++++++++ lib/include/fp/settings/fp-preferences.h | 1 + lib/src/fp-install.cpp | 10 ++ lib/src/fp-items.cpp | 75 +++++++------- lib/src/fp-playlistmanager.cpp | 124 +++++++++++++++++++++++ lib/src/settings/fp-preferences.cpp | 1 + 9 files changed, 279 insertions(+), 82 deletions(-) create mode 100644 lib/include/fp/fp-playlistmanager.h create mode 100644 lib/src/fp-playlistmanager.cpp diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 3de6d3e..ce07077 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -12,6 +12,7 @@ ob_add_standard_library(${LIB_TARGET_NAME} fp-install.h fp-items.h fp-macro.h + fp-playlistmanager.h settings/fp-config.h settings/fp-execs.h settings/fp-preferences.h @@ -22,6 +23,7 @@ ob_add_standard_library(${LIB_TARGET_NAME} fp-install.cpp fp-macro.cpp fp-items.cpp + fp-playlistmanager.cpp settings/fp-config.cpp settings/fp-execs.cpp settings/fp-preferences.cpp diff --git a/lib/include/fp/fp-install.h b/lib/include/fp/fp-install.h index 750cf92..4090ee5 100644 --- a/lib/include/fp/fp-install.h +++ b/lib/include/fp/fp-install.h @@ -22,6 +22,7 @@ #include "fp/fp-macro.h" #include "fp/fp-db.h" #include "fp/fp-items.h" +#include "fp/fp-playlistmanager.h" namespace Fp { @@ -87,6 +88,7 @@ enum class Edition {Ultimate, Infinity, Core}; QDir mLogosDirectory; QDir mScreenshotsDirectory; QDir mExtrasDirectory; + QDir mPlaylistsDirectory; std::unique_ptr mLauncherFile; std::unique_ptr mDatabaseFile; std::shared_ptr mConfigJsonFile; @@ -104,6 +106,9 @@ enum class Edition {Ultimate, Infinity, Core}; // Database Db* mDatabase = nullptr; + // Playlist Manager + PlaylistManager* mPlaylistManager = nullptr; + // Utilities MacroResolver* mMacroResolver = nullptr; @@ -140,6 +145,9 @@ enum class Edition {Ultimate, Infinity, Core}; // Database Db* database(); + // Playlist Manager + PlaylistManager* playlistManager(); + // Support Application Checks // TODO: At some point create a "Settings" object that wraps all of these, would need to rename existing Fp::Settings const Config& config() const; diff --git a/lib/include/fp/fp-items.h b/lib/include/fp/fp-items.h index af7afdb..295d63c 100644 --- a/lib/include/fp/fp-items.h +++ b/lib/include/fp/fp-items.h @@ -296,53 +296,52 @@ class FP_FP_EXPORT Set::Builder Set build(); }; -class FP_FP_EXPORT Playlist +class FP_FP_EXPORT PlaylistGame { -//-Inner Classes---------------------------------------------------------------------------------------------------- + //-Inner Classes---------------------------------------------------------------------------------------------------- public: class Builder; -//-Instance Variables----------------------------------------------------------------------------------------------- + //-Instance Variables----------------------------------------------------------------------------------------------- private: - QUuid mId; - QString mTitle; - QString mDescription; - QString mAuthor; + int mId; + QUuid mPlaylistId; + int mOrder; + QUuid mGameId; -//-Constructor------------------------------------------------------------------------------------------------- + //-Constructor------------------------------------------------------------------------------------------------- public: - Playlist(); + PlaylistGame(); -//-Instance Functions------------------------------------------------------------------------------------------------------ + //-Instance Functions------------------------------------------------------------------------------------------------------ public: - QUuid id() const; - QString title() const; - QString description() const; - QString author() const; - + int id() const; + QUuid playlistId() const; + int order() const; + QUuid gameId() const; }; -class FP_FP_EXPORT Playlist::Builder +class FP_FP_EXPORT PlaylistGame::Builder { -//-Instance Variables------------------------------------------------------------------------------------------ + //-Instance Variables------------------------------------------------------------------------------------------ private: - Playlist mPlaylistBlueprint; + PlaylistGame mPlaylistGameBlueprint; -//-Constructor------------------------------------------------------------------------------------------------- + //-Constructor------------------------------------------------------------------------------------------------- public: Builder(); -//-Instance Functions------------------------------------------------------------------------------------------ + //-Instance Functions------------------------------------------------------------------------------------------ public: - Builder& wId(QString rawId); - Builder& wTitle(QString title); - Builder& wDescription(QString description); - Builder& wAuthor(QString author); + Builder& wId(int id); + Builder& wPlaylistId(QString rawPlaylistId); + Builder& wOrder(int order); + Builder& wGameId(QString rawGameId); - Playlist build(); + PlaylistGame build(); }; -class FP_FP_EXPORT PlaylistGame +class FP_FP_EXPORT Playlist { //-Inner Classes---------------------------------------------------------------------------------------------------- public: @@ -350,28 +349,31 @@ class FP_FP_EXPORT PlaylistGame //-Instance Variables----------------------------------------------------------------------------------------------- private: - int mId; - QUuid mPlaylistId; - int mOrder; - QUuid mGameId; + QUuid mId; + QString mTitle; + QString mDescription; + QString mAuthor; + QList mPlaylistGames; //-Constructor------------------------------------------------------------------------------------------------- public: - PlaylistGame(); + Playlist(); //-Instance Functions------------------------------------------------------------------------------------------------------ public: - int id() const; - QUuid playlistId() const; - int order() const; - QUuid gameId() const; + QUuid id() const; + QString title() const; + QString description() const; + QString author() const; + const QList& playlistGames() const; + }; -class FP_FP_EXPORT PlaylistGame::Builder +class FP_FP_EXPORT Playlist::Builder { //-Instance Variables------------------------------------------------------------------------------------------ private: - PlaylistGame mPlaylistGameBlueprint; + Playlist mPlaylistBlueprint; //-Constructor------------------------------------------------------------------------------------------------- public: @@ -380,11 +382,12 @@ class FP_FP_EXPORT PlaylistGame::Builder //-Instance Functions------------------------------------------------------------------------------------------ public: Builder& wId(QString rawId); - Builder& wPlaylistId(QString rawPlaylistId); - Builder& wOrder(QString rawOrder); - Builder& wGameId(QString rawGameId); + Builder& wTitle(QString title); + Builder& wDescription(QString description); + Builder& wAuthor(QString author); + Builder& wPlaylistGame(const PlaylistGame& playlistGame); - PlaylistGame build(); + Playlist build(); }; } diff --git a/lib/include/fp/fp-playlistmanager.h b/lib/include/fp/fp-playlistmanager.h new file mode 100644 index 0000000..b3d8b07 --- /dev/null +++ b/lib/include/fp/fp-playlistmanager.h @@ -0,0 +1,55 @@ +#ifndef FLASHPOINT_PLAYLISTMANAGER_H +#define FLASHPOINT_PLAYLISTMANAGER_H + +// Shared Lib Support +#include "fp/fp_export.h" + +// Qt Includes +#include + +// Qx Includes +#include + +// Project Includes +#include "fp/fp-items.h" + +namespace Fp +{ + +class FP_FP_EXPORT PlaylistManager +{ +//-Inner Classes------------------------------------------------------------------------------------------------- +public: + class Key + { + friend class Install; + private: + Key() {}; + Key(const Key&) = default; + }; + +//-Class Variables----------------------------------------------------------------------------------------------- +private: + +//-Instance Variables----------------------------------------------------------------------------------------------- +private: + bool mPopulated; + QDir mFolder; + QList mPlaylists; + +//-Constructor------------------------------------------------------------------------------------------------- +public: + explicit PlaylistManager(const QDir& folder, const Key&); + +//-Instance Functions------------------------------------------------------------------------------------------------------ +private: + +public: + bool isPopulated() const; + Qx::Error populate(); + const QList playlists() const; +}; + +} + +#endif // FLASHPOINT_PLAYLISTMANAGER_H diff --git a/lib/include/fp/settings/fp-preferences.h b/lib/include/fp/settings/fp-preferences.h index 8a575e4..baf2e09 100644 --- a/lib/include/fp/settings/fp-preferences.h +++ b/lib/include/fp/settings/fp-preferences.h @@ -45,6 +45,7 @@ struct FP_FP_EXPORT Preferences : public Settings QHash gameDataSources; QHash gameMetadataSources; QString imageFolderPath; + QString playlistFolderPath; QString jsonFolderPath; QString htdocsFolderPath; QString dataPacksFolderPath; diff --git a/lib/src/fp-install.cpp b/lib/src/fp-install.cpp index 2c9764a..6b25356 100644 --- a/lib/src/fp-install.cpp +++ b/lib/src/fp-install.cpp @@ -64,6 +64,7 @@ Install::Install(QString installPath) : mExecsJsonFile = std::make_shared(installPath + "/" + mPreferences.jsonFolderPath + "/" + EXECS_JSON_NAME); mLogosDirectory = QDir(installPath + "/" + mPreferences.imageFolderPath + '/' + LOGOS_FOLDER_NAME); mScreenshotsDirectory = QDir(installPath + "/" + mPreferences.imageFolderPath + '/' + SCREENSHOTS_FOLDER_NAME); + mPlaylistsDirectory = QDir(installPath + "/" + mPreferences.playlistFolderPath); ServicesReader servicesReader(&mServices, mServicesJsonFile, mMacroResolver); if((mError = servicesReader.readInto()).isValid()) @@ -85,6 +86,9 @@ Install::Install(QString installPath) : return; } + // Add playlists manager + mPlaylistManager = new PlaylistManager(mPlaylistsDirectory, {}); + // Give the OK mValid = true; validityGuard.dismiss(); @@ -98,6 +102,8 @@ Install::~Install() delete mMacroResolver; if(mDatabase) delete mDatabase; + if(mPlaylistManager) + delete mPlaylistManager; } //-Class Functions------------------------------------------------------------------------------------------------ @@ -144,6 +150,7 @@ void Install::nullify() mLogosDirectory = QDir(); mScreenshotsDirectory = QDir(); mExtrasDirectory = QDir(); + mPlaylistsDirectory = QDir(); mLauncherFile.reset(); mDatabaseFile.reset(); mConfigJsonFile.reset(); @@ -154,6 +161,8 @@ void Install::nullify() qxDelete(mMacroResolver); if(mDatabase) qxDelete(mDatabase); + if(mPlaylistManager) + qxDelete(mPlaylistManager); // Settings mConfig = {}; @@ -209,6 +218,7 @@ QString Install::launcherChecksum() const } Db* Install::database() { return mDatabase; } +PlaylistManager* Install::playlistManager() { return mPlaylistManager; } const Config& Install::config() const { return mConfig; } const Preferences& Install::preferences() const { return mPreferences; } diff --git a/lib/src/fp-items.cpp b/lib/src/fp-items.cpp index 20d1e39..93656bd 100644 --- a/lib/src/fp-items.cpp +++ b/lib/src/fp-items.cpp @@ -244,77 +244,70 @@ Set::Builder& Set::Builder::wAddApps(const QList& addApps) { mSetBluepri Set Set::Builder::build() { return mSetBlueprint; } //=============================================================================================================== -// Playlist +// PlaylistGame //=============================================================================================================== -//-Constructor------------------------------------------------------------------------------------------------- +//-Constructor------------------------------------------------------------------------------------------------ //Public: -Playlist::Playlist() {} +PlaylistGame::PlaylistGame() {} -//-Instance Functions------------------------------------------------------------------------------------------------------ +//-Instance Functions------------------------------------------------------------------------------------------------ //Public: -QUuid Playlist::id() const { return mId; } -QString Playlist::title() const { return mTitle; } -QString Playlist::description() const { return mDescription; } -QString Playlist::author() const { return mAuthor; } + +int PlaylistGame::id() const { return mId; } +QUuid PlaylistGame::playlistId() const { return mPlaylistId; } +int PlaylistGame::order() const { return mOrder; } +QUuid PlaylistGame::gameId() const { return mGameId; } //=============================================================================================================== -// Playlist::Builder +// PlaylistGame::Builder //=============================================================================================================== //-Constructor------------------------------------------------------------------------------------------------- //Public: -Playlist::Builder::Builder() {} +PlaylistGame::Builder::Builder() {} //-Instance Functions------------------------------------------------------------------------------------------ //Public: -Playlist::Builder& Playlist::Builder::wId(QString rawId) { mPlaylistBlueprint.mId = QUuid(rawId); return *this; } -Playlist::Builder& Playlist::Builder::wTitle(QString title) { mPlaylistBlueprint.mTitle = title; return *this; } -Playlist::Builder& Playlist::Builder::wDescription(QString description) { mPlaylistBlueprint.mDescription = description; return *this; } -Playlist::Builder& Playlist::Builder::wAuthor(QString author) { mPlaylistBlueprint.mAuthor = author; return *this; } +PlaylistGame::Builder& PlaylistGame::Builder::wId(int id) { mPlaylistGameBlueprint.mId = id; return *this; } +PlaylistGame::Builder& PlaylistGame::Builder::wPlaylistId(QString rawPlaylistId) { mPlaylistGameBlueprint.mPlaylistId = QUuid(rawPlaylistId); return *this; } +PlaylistGame::Builder& PlaylistGame::Builder::wOrder(int order) { mPlaylistGameBlueprint.mOrder = order; return *this; } +PlaylistGame::Builder& PlaylistGame::Builder::wGameId(QString rawGameId) { mPlaylistGameBlueprint.mGameId = QUuid(rawGameId); return *this; } -Playlist Playlist::Builder::build() { return mPlaylistBlueprint; } +PlaylistGame PlaylistGame::Builder::build() { return mPlaylistGameBlueprint; } //=============================================================================================================== -// PlaylistGame +// Playlist //=============================================================================================================== -//-Constructor------------------------------------------------------------------------------------------------ +//-Constructor------------------------------------------------------------------------------------------------- //Public: -PlaylistGame::PlaylistGame() {} +Playlist::Playlist() {} -//-Instance Functions------------------------------------------------------------------------------------------------ +//-Instance Functions------------------------------------------------------------------------------------------------------ //Public: - -int PlaylistGame::id() const { return mId; } -QUuid PlaylistGame::playlistId() const { return mPlaylistId; } -int PlaylistGame::order() const { return mOrder; } -QUuid PlaylistGame::gameId() const { return mGameId; } +QUuid Playlist::id() const { return mId; } +QString Playlist::title() const { return mTitle; } +QString Playlist::description() const { return mDescription; } +QString Playlist::author() const { return mAuthor; } +const QList& Playlist::playlistGames() const { return mPlaylistGames; } //=============================================================================================================== -// PlaylistGame::Builder +// Playlist::Builder //=============================================================================================================== //-Constructor------------------------------------------------------------------------------------------------- //Public: - PlaylistGame::Builder::Builder() {} +Playlist::Builder::Builder() {} //-Instance Functions------------------------------------------------------------------------------------------ //Public: - PlaylistGame::Builder& PlaylistGame::Builder::wId(QString rawId) { mPlaylistGameBlueprint.mId = rawId.toInt(); return *this; } - PlaylistGame::Builder& PlaylistGame::Builder::wPlaylistId(QString rawPlaylistId) { mPlaylistGameBlueprint.mPlaylistId = QUuid(rawPlaylistId); return *this; } - - PlaylistGame::Builder& PlaylistGame::Builder::wOrder(QString rawOrder) - { - bool validInt = false; - mPlaylistGameBlueprint.mOrder = rawOrder.toInt(&validInt); - if(!validInt) - mPlaylistGameBlueprint.mOrder = -1; - - return *this; - } +Playlist::Builder& Playlist::Builder::wId(QString rawId) { mPlaylistBlueprint.mId = QUuid(rawId); return *this; } +Playlist::Builder& Playlist::Builder::wTitle(QString title) { mPlaylistBlueprint.mTitle = title; return *this; } +Playlist::Builder& Playlist::Builder::wDescription(QString description) { mPlaylistBlueprint.mDescription = description; return *this; } +Playlist::Builder& Playlist::Builder::wAuthor(QString author) { mPlaylistBlueprint.mAuthor = author; return *this; } +Playlist::Builder& Playlist::Builder::wPlaylistGame(const PlaylistGame& playlistGame) { mPlaylistBlueprint.mPlaylistGames.append(playlistGame); return *this; } - PlaylistGame::Builder& PlaylistGame::Builder::wGameId(QString rawGameId) { mPlaylistGameBlueprint.mGameId = QUuid(rawGameId); return *this; } +Playlist Playlist::Builder::build() { return mPlaylistBlueprint; } - PlaylistGame PlaylistGame::Builder::build() { return mPlaylistGameBlueprint; } -}; +} diff --git a/lib/src/fp-playlistmanager.cpp b/lib/src/fp-playlistmanager.cpp new file mode 100644 index 0000000..0559fc1 --- /dev/null +++ b/lib/src/fp-playlistmanager.cpp @@ -0,0 +1,124 @@ +// Unit Includes +#include "fp/fp-playlistmanager.h" + +// Qt Includes +#include + +// Qx Includes +#include +#include + +namespace Json +{ + +struct PlaylistGame +{ + int id; + QString playlistId; + int order; + QString gameId; + + QX_JSON_STRUCT( + id, + playlistId, + order, + gameId + ); +}; + +struct Playlist +{ + QString id; + QList games; + QString title; + QString description; + QString author; + + QX_JSON_STRUCT( + id, + games, + title, + description, + author + ); +}; + +} + +namespace Fp +{ + +//=============================================================================================================== +// PlaylistManager +//=============================================================================================================== + +//-Constructor------------------------------------------------------------------------------------------------ +//Public: +PlaylistManager::PlaylistManager(const QDir& folder, const Key&) : + mPopulated(false), + mFolder(folder) +{ + mFolder.setNameFilters({"*.json"}); + mFolder.setFilter(QDir::Files); +} + +//-Instance Functions------------------------------------------------------------------------------------------------ +//Public: +bool PlaylistManager::isPopulated() const { return mPopulated; } + +Qx::Error PlaylistManager::populate() +{ + if(mPopulated) + return Qx::Error(); + + mPopulated = true; + + // Parse each JSON format playlist + QDirIterator playlistItr(mFolder); + while (playlistItr.hasNext()) + { + QFile playlistFile(playlistItr.next()); + + // Read raw data + QByteArray playlistData; + if(Qx::IoOpReport rr = Qx::readBytesFromFile(playlistData, playlistFile); rr.isFailure()) + return rr; + + // Parse to JSON + QJsonParseError parseError; + QJsonDocument playlistDoc = QJsonDocument::fromJson(playlistData, &parseError); + if(parseError.error != QJsonParseError::NoError) + return parseError; + + // Parse to known JSON structure + Json::Playlist jPlaylist; + if(Qx::JsonError je = Qx::parseJson(jPlaylist, playlistDoc); je.isValid()) + return je; + + // Convert to FP item + Playlist::Builder pb; + pb.wId(jPlaylist.id) + .wTitle(jPlaylist.title) + .wDescription(jPlaylist.description) + .wAuthor(jPlaylist.author); + + for(const Json::PlaylistGame& jPlaylistGame : qAsConst(jPlaylist.games)) + { + PlaylistGame::Builder pgb; + pgb.wId(jPlaylistGame.id) + .wPlaylistId(jPlaylistGame.playlistId) + .wOrder(jPlaylistGame.order) + .wGameId(jPlaylistGame.gameId); + + pb.wPlaylistGame(pgb.build()); + } + + mPlaylists.append(pb.build()); + } + + return Qx::Error(); +} + +const QList PlaylistManager::playlists() const { return mPlaylists; } + +} diff --git a/lib/src/settings/fp-preferences.cpp b/lib/src/settings/fp-preferences.cpp index 2938bbd..505f9a9 100644 --- a/lib/src/settings/fp-preferences.cpp +++ b/lib/src/settings/fp-preferences.cpp @@ -45,6 +45,7 @@ QX_JSON_STRUCT_OUTSIDE(Fp::Preferences, gameDataSources, gameMetadataSources, imageFolderPath, + playlistFolderPath, jsonFolderPath, htdocsFolderPath, dataPacksFolderPath, From 91a57859a56d731b51db8131d3a270446d133267 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Wed, 19 Jul 2023 03:21:34 -0400 Subject: [PATCH 18/29] Read Playlist library value --- lib/include/fp/fp-items.h | 4 ++++ lib/src/fp-items.cpp | 2 ++ lib/src/fp-playlistmanager.cpp | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/include/fp/fp-items.h b/lib/include/fp/fp-items.h index 295d63c..2bd4264 100644 --- a/lib/include/fp/fp-items.h +++ b/lib/include/fp/fp-items.h @@ -353,6 +353,8 @@ class FP_FP_EXPORT Playlist QString mTitle; QString mDescription; QString mAuthor; + QString mLibrary; + QList mPlaylistGames; //-Constructor------------------------------------------------------------------------------------------------- @@ -365,6 +367,7 @@ class FP_FP_EXPORT Playlist QString title() const; QString description() const; QString author() const; + QString library() const; const QList& playlistGames() const; }; @@ -385,6 +388,7 @@ class FP_FP_EXPORT Playlist::Builder Builder& wTitle(QString title); Builder& wDescription(QString description); Builder& wAuthor(QString author); + Builder& wLibrary(QString library); Builder& wPlaylistGame(const PlaylistGame& playlistGame); Playlist build(); diff --git a/lib/src/fp-items.cpp b/lib/src/fp-items.cpp index 93656bd..4c1fdc3 100644 --- a/lib/src/fp-items.cpp +++ b/lib/src/fp-items.cpp @@ -290,6 +290,7 @@ QUuid Playlist::id() const { return mId; } QString Playlist::title() const { return mTitle; } QString Playlist::description() const { return mDescription; } QString Playlist::author() const { return mAuthor; } +QString Playlist::library() const { return mLibrary; } const QList& Playlist::playlistGames() const { return mPlaylistGames; } //=============================================================================================================== @@ -306,6 +307,7 @@ Playlist::Builder& Playlist::Builder::wId(QString rawId) { mPlaylistBlueprint.mI Playlist::Builder& Playlist::Builder::wTitle(QString title) { mPlaylistBlueprint.mTitle = title; return *this; } Playlist::Builder& Playlist::Builder::wDescription(QString description) { mPlaylistBlueprint.mDescription = description; return *this; } Playlist::Builder& Playlist::Builder::wAuthor(QString author) { mPlaylistBlueprint.mAuthor = author; return *this; } +Playlist::Builder& Playlist::Builder::wLibrary(QString library) { mPlaylistBlueprint.mLibrary = library; return *this; } Playlist::Builder& Playlist::Builder::wPlaylistGame(const PlaylistGame& playlistGame) { mPlaylistBlueprint.mPlaylistGames.append(playlistGame); return *this; } Playlist Playlist::Builder::build() { return mPlaylistBlueprint; } diff --git a/lib/src/fp-playlistmanager.cpp b/lib/src/fp-playlistmanager.cpp index 0559fc1..00bf7cc 100644 --- a/lib/src/fp-playlistmanager.cpp +++ b/lib/src/fp-playlistmanager.cpp @@ -33,13 +33,15 @@ struct Playlist QString title; QString description; QString author; + QString library; QX_JSON_STRUCT( id, games, title, description, - author + author, + library ); }; From dd0d9d75cdbc54325336a60c4010e405db42b2ed Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Wed, 19 Jul 2023 05:50:47 -0400 Subject: [PATCH 19/29] Add non-const accessor for Playlist::playlistGames() --- lib/include/fp/fp-items.h | 1 + lib/src/fp-items.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/include/fp/fp-items.h b/lib/include/fp/fp-items.h index 2bd4264..43389b2 100644 --- a/lib/include/fp/fp-items.h +++ b/lib/include/fp/fp-items.h @@ -369,6 +369,7 @@ class FP_FP_EXPORT Playlist QString author() const; QString library() const; const QList& playlistGames() const; + QList& playlistGames(); }; diff --git a/lib/src/fp-items.cpp b/lib/src/fp-items.cpp index 4c1fdc3..da7463d 100644 --- a/lib/src/fp-items.cpp +++ b/lib/src/fp-items.cpp @@ -292,6 +292,7 @@ QString Playlist::description() const { return mDescription; } QString Playlist::author() const { return mAuthor; } QString Playlist::library() const { return mLibrary; } const QList& Playlist::playlistGames() const { return mPlaylistGames; } +QList& Playlist::playlistGames() { return mPlaylistGames; } //=============================================================================================================== // Playlist::Builder From 484ea13f2d9a5b035fa39c6aab785b00cba54f42 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Wed, 19 Jul 2023 06:31:21 -0400 Subject: [PATCH 20/29] Unify playlist/platform title convenience lists --- lib/include/fp/fp-db.h | 4 ++-- lib/include/fp/fp-playlistmanager.h | 4 +++- lib/src/fp-db.cpp | 10 +++++----- lib/src/fp-playlistmanager.cpp | 5 +++-- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/include/fp/fp-db.h b/lib/include/fp/fp-db.h index 3c68591..d787c5d 100644 --- a/lib/include/fp/fp-db.h +++ b/lib/include/fp/fp-db.h @@ -314,7 +314,7 @@ class FP_FP_EXPORT Db : public QObject // Database information QSet mConnectedThreads; const QString mDatabaseName; - QStringList mPlatformList; + QStringList mPlatformNames; QStringList mPlaylistList; QMap mTagMap; // Order matters for display in tag selector @@ -363,7 +363,7 @@ class FP_FP_EXPORT Db : public QObject DbError queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter filter); // Info - QStringList platformList() const; + QStringList platformNames() const; QMap tags() const; // Checks diff --git a/lib/include/fp/fp-playlistmanager.h b/lib/include/fp/fp-playlistmanager.h index b3d8b07..6fc774b 100644 --- a/lib/include/fp/fp-playlistmanager.h +++ b/lib/include/fp/fp-playlistmanager.h @@ -36,6 +36,7 @@ class FP_FP_EXPORT PlaylistManager bool mPopulated; QDir mFolder; QList mPlaylists; + QStringList mTitles; //-Constructor------------------------------------------------------------------------------------------------- public: @@ -47,7 +48,8 @@ class FP_FP_EXPORT PlaylistManager public: bool isPopulated() const; Qx::Error populate(); - const QList playlists() const; + QList playlists() const; + QStringList playlistTitles() const; }; } diff --git a/lib/src/fp-db.cpp b/lib/src/fp-db.cpp index 819f981..ce92a87 100644 --- a/lib/src/fp-db.cpp +++ b/lib/src/fp-db.cpp @@ -144,7 +144,7 @@ QString Db::threadConnectionName(const QThread* thread) //Private: void Db::nullify() { - mPlatformList.clear(); + mPlatformNames.clear(); mPlaylistList.clear(); mTagMap.clear(); } @@ -328,7 +328,7 @@ QSqlError Db::populateAvailableItems() return dbError; // Ensure lists are reset - mPlatformList.clear(); + mPlatformNames.clear(); mPlaylistList.clear(); // Make platform query @@ -340,10 +340,10 @@ QSqlError Db::populateAvailableItems() // Parse query while(platformQuery.next()) - mPlatformList.append(platformQuery.value(Table_Game::COL_PLATFORM_NAME).toString()); + mPlatformNames.append(platformQuery.value(Table_Game::COL_PLATFORM_NAME).toString()); // Sort list - mPlatformList.sort(); + mPlatformNames.sort(); // Return invalid SqlError return QSqlError(); @@ -698,7 +698,7 @@ DbError Db::queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter includeFilt return DbError::fromSqlError(makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand)); } -QStringList Db::platformList() const { return mPlatformList; } //TODO: Probably should use RAII for this. +QStringList Db::platformNames() const { return mPlatformNames; } //TODO: Probably should use RAII for this. QMap Db::tags() const { return mTagMap; } DbError Db::entryUsesDataPack(bool& resultBuffer, QUuid gameId) diff --git a/lib/src/fp-playlistmanager.cpp b/lib/src/fp-playlistmanager.cpp index 00bf7cc..f3372e0 100644 --- a/lib/src/fp-playlistmanager.cpp +++ b/lib/src/fp-playlistmanager.cpp @@ -115,12 +115,13 @@ Qx::Error PlaylistManager::populate() pb.wPlaylistGame(pgb.build()); } + mTitles.append(jPlaylist.title); mPlaylists.append(pb.build()); } return Qx::Error(); } -const QList PlaylistManager::playlists() const { return mPlaylists; } - +QList PlaylistManager::playlists() const { return mPlaylists; } +QStringList PlaylistManager::playlistTitles() const { return mTitles; } } From 6cf53b79160d058f0e3938b925cc1c8837a91082 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Wed, 19 Jul 2023 15:17:39 -0400 Subject: [PATCH 21/29] Respect onDemandImagesCompressed preference --- lib/include/fp/fp-install.h | 5 +++-- lib/include/fp/settings/fp-preferences.h | 1 + lib/src/fp-install.cpp | 15 ++++++++++++--- lib/src/settings/fp-preferences.cpp | 1 + 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/lib/include/fp/fp-install.h b/lib/include/fp/fp-install.h index 4090ee5..fc69a94 100644 --- a/lib/include/fp/fp-install.h +++ b/lib/include/fp/fp-install.h @@ -51,8 +51,9 @@ enum class Edition {Ultimate, Infinity, Core}; static inline const QString VER_TXT_PATH = "version.txt"; // File Info - static inline const QString IMAGE_EXT = ".png"; - + static inline const QString IMAGE_UC_EXT = ".png"; + static inline const QString IMAGE_C_EXT = ".jpg"; + static inline const QString IMAGE_C_URL_SUFFIX = "?type=jpg"; // Dynamic path file names static inline const QString SERVICES_JSON_NAME = "services.json"; diff --git a/lib/include/fp/settings/fp-preferences.h b/lib/include/fp/settings/fp-preferences.h index baf2e09..0300a00 100644 --- a/lib/include/fp/settings/fp-preferences.h +++ b/lib/include/fp/settings/fp-preferences.h @@ -50,6 +50,7 @@ struct FP_FP_EXPORT Preferences : public Settings QString htdocsFolderPath; QString dataPacksFolderPath; bool onDemandImages; + bool onDemandImagesCompressed; QString onDemandBaseUrl; QList appPathOverrides; QSet nativePlatforms; diff --git a/lib/src/fp-install.cpp b/lib/src/fp-install.cpp index 6b25356..468255f 100644 --- a/lib/src/fp-install.cpp +++ b/lib/src/fp-install.cpp @@ -111,7 +111,7 @@ Install::~Install() QString Install::standardImageSubPath(QUuid gameId) { QString gameIdString = gameId.toString(QUuid::WithoutBraces); - return gameIdString.left(2) + '/' + gameIdString.mid(2, 2) + '/' + gameIdString + IMAGE_EXT; + return gameIdString.left(2) + '/' + gameIdString.mid(2, 2) + '/' + gameIdString; } //Public: @@ -233,13 +233,22 @@ QDir Install::extrasDirectory() const { return mExtrasDirectory; } QString Install::imageLocalPath(ImageType imageType, QUuid gameId) const { const QDir& sourceDir = imageType == ImageType::Logo ? mLogosDirectory : mScreenshotsDirectory; - return sourceDir.absolutePath() + '/' + standardImageSubPath(gameId); + bool compressed = mPreferences.onDemandImagesCompressed; + QString localSubPath = standardImageSubPath(gameId) + (compressed ? IMAGE_C_EXT : IMAGE_UC_EXT); + + return sourceDir.absolutePath() + '/' + localSubPath; } QUrl Install::imageRemoteUrl(ImageType imageType, QUuid gameId) const { const QString typeFolder = (imageType == ImageType::Logo ? LOGOS_FOLDER_NAME : SCREENSHOTS_FOLDER_NAME); - return QUrl(mPreferences.onDemandBaseUrl + typeFolder + '/' + standardImageSubPath(gameId)); + bool compressed = mPreferences.onDemandImagesCompressed; + QString remoteSubPath = standardImageSubPath(gameId) + IMAGE_UC_EXT; + + if(compressed) + remoteSubPath += IMAGE_C_URL_SUFFIX; + + return QUrl(mPreferences.onDemandBaseUrl + typeFolder + '/' + remoteSubPath); } const MacroResolver* Install::macroResolver() const { return mMacroResolver; } diff --git a/lib/src/settings/fp-preferences.cpp b/lib/src/settings/fp-preferences.cpp index 505f9a9..aa66ca3 100644 --- a/lib/src/settings/fp-preferences.cpp +++ b/lib/src/settings/fp-preferences.cpp @@ -50,6 +50,7 @@ QX_JSON_STRUCT_OUTSIDE(Fp::Preferences, htdocsFolderPath, dataPacksFolderPath, onDemandImages, + onDemandImagesCompressed, onDemandBaseUrl, appPathOverrides, nativePlatforms, From ac3df779f55a6b0acdcc26640f4f990e038c108f Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Sat, 22 Jul 2023 06:50:15 -0400 Subject: [PATCH 22/29] Use u""_s where possible --- CMakeLists.txt | 2 +- lib/include/fp/fp-db.h | 162 +++++++++++++++---------------- lib/include/fp/fp-install.h | 40 ++++---- lib/include/fp/fp-items.h | 6 +- lib/include/fp/fp-macro.h | 4 +- lib/src/fp-db.cpp | 116 +++++++++++----------- lib/src/fp-install.cpp | 30 +++--- lib/src/fp-items.cpp | 4 +- lib/src/fp-playlistmanager.cpp | 2 +- lib/src/settings/fp-services.cpp | 10 +- 10 files changed, 190 insertions(+), 186 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b6462c2..477487e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ set(LIBFP_QX_COMPONENTS include(OB/FetchQx) ob_fetch_qx( - REF "71a148fcacf648636cb0bcb96b3345424ac4f90d" + REF "520cc55d4a38aeb98c945b5c0c1c6eb70459af35" COMPONENTS ${LIBFP_QX_COMPONENTS} ) diff --git a/lib/include/fp/fp-db.h b/lib/include/fp/fp-db.h index d787c5d..25f2a45 100644 --- a/lib/include/fp/fp-db.h +++ b/lib/include/fp/fp-db.h @@ -39,13 +39,13 @@ class FP_FP_EXPORT QX_ERROR_TYPE(DbError, "Fp::DbError", 1101) //-Class Variables------------------------------------------------------------- private: static inline const QHash ERR_STRINGS{ - {NoError, QSL("No error occurred.")}, - {SqlError, QSL("An unexpected SQL error occurred.")}, - {InvalidSchema, QSL("The schema of the database was different than expected.")}, - {IdCollision, QSL("A duplicate of a unique ID was found.")}, - {IncompleteSearch, QSL("A data search could not be completed.")}, - {UpdateIneffective, QSL("An update statement unexpectedly affected 0 rows.")}, - {UpdateTooMany, QSL("An update statement affected more rows than expected.")} + {NoError, u"No error occurred."_s}, + {SqlError, u"An unexpected SQL error occurred."_s}, + {InvalidSchema, u"The schema of the database was different than expected."_s}, + {IdCollision, u"A duplicate of a unique ID was found."_s}, + {IncompleteSearch, u"A data search could not be completed."_s}, + {UpdateIneffective, u"An update statement unexpectedly affected 0 rows."_s}, + {UpdateTooMany, u"An update statement affected more rows than expected."_s} }; //-Instance Variables------------------------------------------------------------- @@ -90,58 +90,58 @@ class FP_FP_EXPORT Db : public QObject class Table_Game { public: - static inline const QString NAME = "game"; - - static inline const QString COL_ID = "id"; - static inline const QString COL_PARENT_ID = "parentGameId"; - static inline const QString COL_TITLE = "title"; - static inline const QString COL_SERIES = "series"; - static inline const QString COL_DEVELOPER = "developer"; - static inline const QString COL_PUBLISHER = "publisher"; - static inline const QString COL_DATE_ADDED = "dateAdded"; - static inline const QString COL_DATE_MODIFIED = "dateModified"; - static inline const QString COL_BROKEN = "broken"; - static inline const QString COL_EXTREME = "extreme"; - static inline const QString COL_PLAY_MODE = "playMode"; - static inline const QString COL_STATUS = "status"; - static inline const QString COL_NOTES = "notes"; - static inline const QString COL_SOURCE = "source"; - static inline const QString COL_APP_PATH = "applicationPath"; - static inline const QString COL_LAUNCH_COMMAND = "launchCommand"; - static inline const QString COL_RELEASE_DATE = "releaseDate"; - static inline const QString COL_VERSION = "version"; - static inline const QString COL_ORIGINAL_DESC = "originalDescription"; - static inline const QString COL_LANGUAGE = "language"; - static inline const QString COL_LIBRARY = "library"; - static inline const QString COL_ORDER_TITLE = "orderTitle"; - static inline const QString COL_PLATFORM_NAME = "platformName"; + static inline const QString NAME = u"game"_s; + + static inline const QString COL_ID = u"id"_s; + static inline const QString COL_PARENT_ID = u"parentGameId"_s; + static inline const QString COL_TITLE = u"title"_s; + static inline const QString COL_SERIES = u"series"_s; + static inline const QString COL_DEVELOPER = u"developer"_s; + static inline const QString COL_PUBLISHER = u"publisher"_s; + static inline const QString COL_DATE_ADDED = u"dateAdded"_s; + static inline const QString COL_DATE_MODIFIED = u"dateModified"_s; + static inline const QString COL_BROKEN = u"broken"_s; + static inline const QString COL_EXTREME = u"extreme"_s; + static inline const QString COL_PLAY_MODE = u"playMode"_s; + static inline const QString COL_STATUS = u"status"_s; + static inline const QString COL_NOTES = u"notes"_s; + static inline const QString COL_SOURCE = u"source"_s; + static inline const QString COL_APP_PATH = u"applicationPath"_s; + static inline const QString COL_LAUNCH_COMMAND = u"launchCommand"_s; + static inline const QString COL_RELEASE_DATE = u"releaseDate"_s; + static inline const QString COL_VERSION = u"version"_s; + static inline const QString COL_ORIGINAL_DESC = u"originalDescription"_s; + static inline const QString COL_LANGUAGE = u"language"_s; + static inline const QString COL_LIBRARY = u"library"_s; + static inline const QString COL_ORDER_TITLE = u"orderTitle"_s; + static inline const QString COL_PLATFORM_NAME = u"platformName"_s; static inline const QStringList COLUMN_LIST = {COL_ID, COL_PARENT_ID, COL_TITLE, COL_SERIES, COL_DEVELOPER, COL_PUBLISHER, COL_DATE_ADDED, COL_DATE_MODIFIED, COL_BROKEN, COL_EXTREME, COL_PLAY_MODE, COL_STATUS, COL_NOTES, COL_SOURCE, COL_APP_PATH, COL_LAUNCH_COMMAND, COL_RELEASE_DATE, COL_VERSION, COL_ORIGINAL_DESC, COL_LANGUAGE, COL_LIBRARY, COL_ORDER_TITLE, COL_PLATFORM_NAME}; - static inline const QString ENTRY_GAME_LIBRARY = "arcade"; - static inline const QString ENTRY_ANIM_LIBRARY = "theatre"; - static inline const QString ENTRY_NOT_WORK = "Not Working"; + static inline const QString ENTRY_GAME_LIBRARY = u"arcade"_s; + static inline const QString ENTRY_ANIM_LIBRARY = u"theatre"_s; + static inline const QString ENTRY_NOT_WORK = u"Not Working"_s; }; class Table_Game_Data { public: - static inline const QString NAME = "game_data"; - - static inline const QString COL_ID = "id"; - static inline const QString COL_GAME_ID = "gameId"; - static inline const QString COL_TITLE = "title"; - static inline const QString COL_DATE_ADDED = "dateAdded"; - static inline const QString COL_SHA256 = "sha256"; - static inline const QString COL_CRC32 = "crc32"; - static inline const QString COL_PRES_ON_DISK = "presentOnDisk"; - static inline const QString COL_PATH = "path"; - static inline const QString COL_SIZE = "size"; - static inline const QString COL_PARAM = "parameters"; - static inline const QString COL_APP_PATH = "applicationPath"; - static inline const QString COL_LAUNCH_COMMAND = "launchCommand"; + static inline const QString NAME = u"game_data"_s; + + static inline const QString COL_ID = u"id"_s; + static inline const QString COL_GAME_ID = u"gameId"_s; + static inline const QString COL_TITLE = u"title"_s; + static inline const QString COL_DATE_ADDED = u"dateAdded"_s; + static inline const QString COL_SHA256 = u"sha256"_s; + static inline const QString COL_CRC32 = u"crc32"_s; + static inline const QString COL_PRES_ON_DISK = u"presentOnDisk"_s; + static inline const QString COL_PATH = u"path"_s; + static inline const QString COL_SIZE = u"size"_s; + static inline const QString COL_PARAM = u"parameters"_s; + static inline const QString COL_APP_PATH = u"applicationPath"_s; + static inline const QString COL_LAUNCH_COMMAND = u"launchCommand"_s; static inline const QStringList COLUMN_LIST = {COL_ID, COL_GAME_ID, COL_TITLE, COL_DATE_ADDED, COL_SHA256, COL_CRC32, COL_PRES_ON_DISK, COL_PATH, COL_SIZE, COL_PARAM, COL_APP_PATH, COL_LAUNCH_COMMAND}; @@ -150,30 +150,30 @@ class FP_FP_EXPORT Db : public QObject class Table_Add_App { public: - static inline const QString NAME = "additional_app"; + static inline const QString NAME = u"additional_app"_s; - static inline const QString COL_ID = "id"; - static inline const QString COL_APP_PATH = "applicationPath"; - static inline const QString COL_AUTORUN = "autoRunBefore"; - static inline const QString COL_LAUNCH_COMMAND = "launchCommand"; - static inline const QString COL_NAME = "name"; - static inline const QString COL_WAIT_EXIT = "waitForExit"; - static inline const QString COL_PARENT_ID = "parentGameId"; + static inline const QString COL_ID = u"id"_s; + static inline const QString COL_APP_PATH = u"applicationPath"_s; + static inline const QString COL_AUTORUN = u"autoRunBefore"_s; + static inline const QString COL_LAUNCH_COMMAND = u"launchCommand"_s; + static inline const QString COL_NAME = u"name"_s; + static inline const QString COL_WAIT_EXIT = u"waitForExit"_s; + static inline const QString COL_PARENT_ID = u"parentGameId"_s; static inline const QStringList COLUMN_LIST = {COL_ID, COL_APP_PATH, COL_AUTORUN, COL_LAUNCH_COMMAND, COL_NAME, COL_WAIT_EXIT, COL_PARENT_ID}; - static inline const QString ENTRY_EXTRAS = ":extras:"; - static inline const QString ENTRY_MESSAGE = ":message:"; + static inline const QString ENTRY_EXTRAS = u":extras:"_s; + static inline const QString ENTRY_MESSAGE = u":message:"_s; }; class Table_Game_Tags_Tag { public: - static inline const QString NAME = "game_tags_tag"; + static inline const QString NAME = u"game_tags_tag"_s; - static inline const QString COL_GAME_ID = "gameId"; - static inline const QString COL_TAG_ID = "tagId"; + static inline const QString COL_GAME_ID = u"gameId"_s; + static inline const QString COL_TAG_ID = u"tagId"_s; static inline const QStringList COLUMN_LIST = {COL_GAME_ID, COL_TAG_ID}; }; @@ -181,11 +181,11 @@ class FP_FP_EXPORT Db : public QObject class Table_Tag { public: - static inline const QString NAME = "tag"; + static inline const QString NAME = u"tag"_s; - static inline const QString COL_ID = "id"; - static inline const QString COL_PRIMARY_ALIAS_ID = "primaryAliasId"; - static inline const QString COL_CATEGORY_ID = "categoryId"; + static inline const QString COL_ID = u"id"_s; + static inline const QString COL_PRIMARY_ALIAS_ID = u"primaryAliasId"_s; + static inline const QString COL_CATEGORY_ID = u"categoryId"_s; static inline const QStringList COLUMN_LIST = {COL_ID, COL_PRIMARY_ALIAS_ID, COL_CATEGORY_ID}; }; @@ -193,11 +193,11 @@ class FP_FP_EXPORT Db : public QObject class Table_Tag_Alias { public: - static inline const QString NAME = "tag_alias"; + static inline const QString NAME = u"tag_alias"_s; - static inline const QString COL_ID = "id"; - static inline const QString COL_TAG_ID = "tagId"; - static inline const QString COL_NAME = "name"; + static inline const QString COL_ID = u"id"_s; + static inline const QString COL_TAG_ID = u"tagId"_s; + static inline const QString COL_NAME = u"name"_s; static inline const QStringList COLUMN_LIST = {COL_ID, COL_TAG_ID, COL_NAME}; }; @@ -205,11 +205,11 @@ class FP_FP_EXPORT Db : public QObject class Table_Tag_Category { public: - static inline const QString NAME = "tag_category"; + static inline const QString NAME = u"tag_category"_s; - static inline const QString COL_ID = "id"; - static inline const QString COL_NAME = "name"; - static inline const QString COL_COLOR = "color"; + static inline const QString COL_ID = u"id"_s; + static inline const QString COL_NAME = u"name"_s; + static inline const QString COL_COLOR = u"color"_s; static inline const QStringList COLUMN_LIST = {COL_ID, COL_NAME, COL_COLOR}; @@ -281,7 +281,7 @@ class FP_FP_EXPORT Db : public QObject //-Class Variables----------------------------------------------------------------------------------------------- private: - static inline const QString DATABASE_CONNECTION_NAME = "flashpoint_database"; + static inline const QString DATABASE_CONNECTION_NAME = u"flashpoint_database"_s; // TODO: Self register this somehow so that it doesnt need to be modified when tables are added or removed. // Might require wrapping tables in actual classes @@ -294,15 +294,15 @@ class FP_FP_EXPORT Db : public QObject {Db::Table_Tag_Alias::NAME, Db::Table_Tag_Alias::COLUMN_LIST}, {Db::Table_Tag_Category::NAME, Db::Table_Tag_Category::COLUMN_LIST}, }; - static inline const QString GENERAL_QUERY_SIZE_COMMAND = "COUNT(1)"; + static inline const QString GENERAL_QUERY_SIZE_COMMAND = u"COUNT(1)"_s; - static inline const QString GAME_ONLY_FILTER = Db::Table_Game::COL_LIBRARY + " = '" + Db::Table_Game::ENTRY_GAME_LIBRARY + "'"; - static inline const QString ANIM_ONLY_FILTER = Db::Table_Game::COL_LIBRARY + " = '" + Db::Table_Game::ENTRY_ANIM_LIBRARY + "'"; - static inline const QString GAME_AND_ANIM_FILTER = "(" + GAME_ONLY_FILTER + " OR " + ANIM_ONLY_FILTER + ")"; + static inline const QString GAME_ONLY_FILTER = Db::Table_Game::COL_LIBRARY + u" = '"_s + Db::Table_Game::ENTRY_GAME_LIBRARY + u"'"_s; + static inline const QString ANIM_ONLY_FILTER = Db::Table_Game::COL_LIBRARY + u" = '"_s + Db::Table_Game::ENTRY_ANIM_LIBRARY + u"'"_s; + static inline const QString GAME_AND_ANIM_FILTER = u"("_s + GAME_ONLY_FILTER + u" OR "_s + ANIM_ONLY_FILTER + u")"_s; // Error - static inline const QString ERR_MISSING_TABLE = "The Flashpoint database is missing expected tables."; - static inline const QString ERR_TABLE_MISSING_COLUMN = "The Flashpoint database tables are missing expected columns."; + static inline const QString ERR_MISSING_TABLE = u"The Flashpoint database is missing expected tables."_s; + static inline const QString ERR_TABLE_MISSING_COLUMN = u"The Flashpoint database tables are missing expected columns."_s; static inline const QString ERR_ID_NOT_FOUND = u"An entry matching the specified ID could not be found in the Flashpoint database."_s; static inline const QString ERR_ID_DUPLICATE_ENTRY = u"This should not be possible and may indicate an error within the Flashpoint database"_s; diff --git a/lib/include/fp/fp-install.h b/lib/include/fp/fp-install.h index fc69a94..516b3c5 100644 --- a/lib/include/fp/fp-install.h +++ b/lib/include/fp/fp-install.h @@ -27,7 +27,7 @@ namespace Fp { -inline const QString NAME = QStringLiteral("Flashpoint"); +inline const QString NAME = u"Flashpoint"_s; class FP_FP_EXPORT Install { @@ -37,46 +37,46 @@ enum class Edition {Ultimate, Infinity, Core}; //-Class Variables----------------------------------------------------------------------------------------------- public: // Ugh #if defined _WIN32 - static inline const QString LAUNCHER_NAME = "Flashpoint.exe"; + static inline const QString LAUNCHER_NAME = u"Flashpoint.exe"_s; #elif defined __linux__ - static inline const QString LAUNCHER_NAME = "flashpoint-launcher"; + static inline const QString LAUNCHER_NAME = u"flashpoint-launcher"_s; #endif private: // Static paths - static inline const QString LAUNCHER_PATH = "Launcher/" + LAUNCHER_NAME; - static inline const QString DATABASE_PATH = "Data/flashpoint.sqlite"; - static inline const QString CONFIG_JSON_PATH = "Launcher/config.json"; - static inline const QString PREFERENCES_JSON_PATH = "preferences.json"; - static inline const QString VER_TXT_PATH = "version.txt"; + static inline const QString LAUNCHER_PATH = u"Launcher/"_s + LAUNCHER_NAME; + static inline const QString DATABASE_PATH = u"Data/flashpoint.sqlite"_s; + static inline const QString CONFIG_JSON_PATH = u"Launcher/config.json"_s; + static inline const QString PREFERENCES_JSON_PATH = u"preferences.json"_s; + static inline const QString VER_TXT_PATH = u"version.txt"_s; // File Info - static inline const QString IMAGE_UC_EXT = ".png"; - static inline const QString IMAGE_C_EXT = ".jpg"; - static inline const QString IMAGE_C_URL_SUFFIX = "?type=jpg"; + static inline const QString IMAGE_UC_EXT = u".png"_s; + static inline const QString IMAGE_C_EXT = u".jpg"_s; + static inline const QString IMAGE_C_URL_SUFFIX = u"?type=jpg"_s; // Dynamic path file names - static inline const QString SERVICES_JSON_NAME = "services.json"; - static inline const QString EXECS_JSON_NAME = "execs.json"; + static inline const QString SERVICES_JSON_NAME = u"services.json"_s; + static inline const QString EXECS_JSON_NAME = u"execs.json"_s; // Static Folders - static inline const QString EXTRAS_PATH = "Extras"; + static inline const QString EXTRAS_PATH = u"Extras"_s; // Dynamic path folder names - static inline const QString LOGOS_FOLDER_NAME = "Logos"; - static inline const QString SCREENSHOTS_FOLDER_NAME = "Screenshots"; + static inline const QString LOGOS_FOLDER_NAME = u"Logos"_s; + static inline const QString SCREENSHOTS_FOLDER_NAME = u"Screenshots"_s; // Error - static inline const QString ERR_FILE_MISSING = QSL("A required flashpoint install file is missing."); + static inline const QString ERR_FILE_MISSING = u"A required flashpoint install file is missing."_s; // Settings - static inline const QString MACRO_FP_PATH = ""; + static inline const QString MACRO_FP_PATH = u""_s; // Regex - static inline const QRegularExpression VERSION_NUMBER_REGEX = QRegularExpression("[fF]lashpoint (?.*?) "); + static inline const QRegularExpression VERSION_NUMBER_REGEX = QRegularExpression(u"[fF]lashpoint (?.*?) "_s); public: - static inline const QFileInfo SECURE_PLAYER_INFO = QFileInfo("FlashpointSecurePlayer.exe"); + static inline const QFileInfo SECURE_PLAYER_INFO = QFileInfo(u"FlashpointSecurePlayer.exe"_s); //-Instance Variables----------------------------------------------------------------------------------------------- private: diff --git a/lib/include/fp/fp-items.h b/lib/include/fp/fp-items.h index 43389b2..a3f87c4 100644 --- a/lib/include/fp/fp-items.h +++ b/lib/include/fp/fp-items.h @@ -9,6 +9,8 @@ #include #include +using namespace Qt::Literals::StringLiterals; + namespace Fp { //-Enums---------------------------------------------------------------------------------------------------------- @@ -196,8 +198,8 @@ class FP_FP_EXPORT AddApp //-Class Variables----------------------------------------------------------------------------------------------- private: - QString SPEC_PATH_MSG = ":message:"; - QString SPEC_PATH_EXTRA = ":extras:"; + static inline const QString SPEC_PATH_MSG = u":message:"_s; + static inline const QString SPEC_PATH_EXTRA = u":extras:"_s; //-Instance Variables----------------------------------------------------------------------------------------------- private: diff --git a/lib/include/fp/fp-macro.h b/lib/include/fp/fp-macro.h index 0d4e8ae..6e0ee6d 100644 --- a/lib/include/fp/fp-macro.h +++ b/lib/include/fp/fp-macro.h @@ -7,6 +7,8 @@ // Qt Includes #include +using namespace Qt::Literals::StringLiterals; + namespace Fp { @@ -24,7 +26,7 @@ class FP_FP_EXPORT MacroResolver //-Class Variables----------------------------------------------------------------------------------------------- private: - static inline const QString FP_PATH = ""; + static inline const QString FP_PATH = u""_s; //-Instance Variables----------------------------------------------------------------------------------------------- private: diff --git a/lib/src/fp-db.cpp b/lib/src/fp-db.cpp index ce92a87..2ab44d4 100644 --- a/lib/src/fp-db.cpp +++ b/lib/src/fp-db.cpp @@ -83,7 +83,7 @@ Db::Db(const QString& databaseName, const Key&) : if(!missingTables.isEmpty()) { mError = DbError(DbError::InvalidSchema, ERR_MISSING_TABLE, - QStringList(missingTables.begin(), missingTables.end()).join("\n")); + QStringList(missingTables.begin(), missingTables.end()).join(u"\n"_s)); return; } @@ -99,7 +99,7 @@ Db::Db(const QString& databaseName, const Key&) : if(!missingColumns.isEmpty()) { mError = DbError(DbError::InvalidSchema, ERR_MISSING_TABLE, - QStringList(missingColumns.begin(), missingColumns.end()).join("\n")); + QStringList(missingColumns.begin(), missingColumns.end()).join(u"\n"_s)); return; } @@ -135,8 +135,8 @@ QString Db::threadConnectionName(const QThread* thread) // Important to also salt using instance "id" so that // different instances don't use the same connection return DATABASE_CONNECTION_NAME + - "_i" + QString::number((quint64)this, 16) + - "_t" + QString::number((quint64)thread, 16); + u"_i"_s + QString::number((quint64)this, 16) + + u"_t"_s + QString::number((quint64)thread, 16); } @@ -191,7 +191,7 @@ QSqlError Db::getThreadConnection(QSqlDatabase& connection) } else { - connection = QSqlDatabase::addDatabase("QSQLITE", tcn); + connection = QSqlDatabase::addDatabase(u"QSQLITE"_s, tcn); //connection.setConnectOptions("QSQLITE_OPEN_READONLY"); Lib features some DB writing now connection.setDatabaseName(mDatabaseName); @@ -298,7 +298,7 @@ QSqlError Db::checkDatabaseForRequiredColumns(QSet &missingColumsReturn existingColumns.clear(); // Make column name query - QSqlQuery columnQuery("PRAGMA table_info(" + tableAndColumns.name + ")", fpDb); + QSqlQuery columnQuery(u"PRAGMA table_info("_s + tableAndColumns.name + u")"_s, fpDb); // Return if error occurs if(columnQuery.lastError().isValid()) @@ -306,12 +306,12 @@ QSqlError Db::checkDatabaseForRequiredColumns(QSet &missingColumsReturn // Parse query while(columnQuery.next()) - existingColumns.insert(columnQuery.value("name").toString()); + existingColumns.insert(columnQuery.value(u"name"_s).toString()); // Check for missing columns for(const QString& column : tableAndColumns.columns) if(!existingColumns.contains(column)) - missingColumsReturnBuffer.insert(tableAndColumns.name + ": " + column); + missingColumsReturnBuffer.insert(tableAndColumns.name + u": "_s + column); } @@ -332,7 +332,7 @@ QSqlError Db::populateAvailableItems() mPlaylistList.clear(); // Make platform query - QSqlQuery platformQuery("SELECT DISTINCT " + Table_Game::COL_PLATFORM_NAME + " FROM " + Table_Game::NAME, fpDb); + QSqlQuery platformQuery(u"SELECT DISTINCT "_s + Table_Game::COL_PLATFORM_NAME + u" FROM "_s + Table_Game::NAME, fpDb); // Return if error occurs if(platformQuery.lastError().isValid()) @@ -364,7 +364,7 @@ QSqlError Db::populateTags() QHash primaryAliases; // Make tag category query - QSqlQuery categoryQuery("SELECT `" + Table_Tag_Category::COLUMN_LIST.join("`,`") + "` FROM " + Table_Tag_Category::NAME, fpDb); + QSqlQuery categoryQuery(u"SELECT `"_s + Table_Tag_Category::COLUMN_LIST.join(u"`,`"_s) + u"` FROM "_s + Table_Tag_Category::NAME, fpDb); // Return if error occurs if(categoryQuery.lastError().isValid()) @@ -381,7 +381,7 @@ QSqlError Db::populateTags() } // Make tag alias query - QSqlQuery aliasQuery("SELECT `" + Table_Tag_Alias::COLUMN_LIST.join("`,`") + "` FROM " + Table_Tag_Alias::NAME, fpDb); + QSqlQuery aliasQuery(u"SELECT `"_s + Table_Tag_Alias::COLUMN_LIST.join(u"`,`"_s) + u"` FROM "_s + Table_Tag_Alias::NAME, fpDb); // Return if error occurs if(aliasQuery.lastError().isValid()) @@ -392,7 +392,7 @@ QSqlError Db::populateTags() primaryAliases[aliasQuery.value(Table_Tag_Alias::COL_ID).toInt()] = aliasQuery.value(Table_Tag_Alias::COL_NAME).toString(); // Make tag query - QSqlQuery tagQuery("SELECT `" + Table_Tag::COLUMN_LIST.join("`,`") + "` FROM " + Table_Tag::NAME, fpDb); + QSqlQuery tagQuery(u"SELECT `"_s + Table_Tag::COLUMN_LIST.join(u"`,`"_s) + u"` FROM "_s + Table_Tag::NAME, fpDb); // Return if error occurs if(tagQuery.lastError().isValid()) @@ -433,9 +433,9 @@ DbError Db::queryGamesByPlatform(QList& resultBuffer, QStringList p if(!inclusionOptions.excludedTagIds.isEmpty()) { // Make game tag sets query - QString tagIdCSV = Qx::String::join(inclusionOptions.excludedTagIds, [](int tagId){return QString::number(tagId);}, "','"); - QSqlQuery tagQuery("SELECT `" + Table_Game_Tags_Tag::COL_GAME_ID + "` FROM " + Table_Game_Tags_Tag::NAME + - " WHERE " + Table_Game_Tags_Tag::COL_TAG_ID + " IN('" + tagIdCSV + "')", fpDb); + QString tagIdCSV = Qx::String::join(inclusionOptions.excludedTagIds, [](int tagId){return QString::number(tagId);}, u"','"_s); + QSqlQuery tagQuery(u"SELECT `"_s + Table_Game_Tags_Tag::COL_GAME_ID + u"` FROM "_s + Table_Game_Tags_Tag::NAME + + u" WHERE "_s + Table_Game_Tags_Tag::COL_TAG_ID + u" IN('"_s + tagIdCSV + u"')"_s, fpDb); QSqlError tagQueryError = tagQuery.lastError(); if(tagQueryError.isValid()) @@ -449,27 +449,27 @@ DbError Db::queryGamesByPlatform(QList& resultBuffer, QStringList p for(const QString& platform : platforms) { // Create platform query string - QString placeholder = ":platform"; - QString baseQueryCommand = "SELECT %1 FROM " + Table_Game::NAME + " WHERE " + - Table_Game::COL_PLATFORM_NAME + " = " + placeholder + " AND "; + QString placeholder = u":platform"_s; + QString baseQueryCommand = u"SELECT %1 FROM "_s + Table_Game::NAME + u" WHERE "_s + + Table_Game::COL_PLATFORM_NAME + u" = "_s + placeholder + u" AND "_s; // Handle filtering QString filteredQueryCommand = baseQueryCommand.append(inclusionOptions.includeAnimations ? GAME_AND_ANIM_FILTER : GAME_ONLY_FILTER); if(!idExclusionFilter.isEmpty()) { - QString gameIdCSV = Qx::String::join(idExclusionFilter, [](QUuid id){return id.toString(QUuid::WithoutBraces);}, "','"); - filteredQueryCommand += " AND " + Table_Game::COL_ID + " NOT IN('" + gameIdCSV + "')"; + QString gameIdCSV = Qx::String::join(idExclusionFilter, [](QUuid id){return id.toString(QUuid::WithoutBraces);}, u"','"_s); + filteredQueryCommand += u" AND "_s + Table_Game::COL_ID + u" NOT IN('"_s + gameIdCSV + u"')"_s; } if(idInclusionFilter.has_value()) { - QString gameIdCSV = Qx::String::join(*idInclusionFilter.value(), [](QUuid id){return id.toString(QUuid::WithoutBraces);}, "','"); - filteredQueryCommand += " AND " + Table_Game::COL_ID + " IN('" + gameIdCSV + "')"; + QString gameIdCSV = Qx::String::join(*idInclusionFilter.value(), [](QUuid id){return id.toString(QUuid::WithoutBraces);}, u"','"_s); + filteredQueryCommand += u" AND "_s + Table_Game::COL_ID + u" IN('"_s + gameIdCSV + u"')"_s; } // Create final command strings - QString mainQueryCommand = filteredQueryCommand.arg("`" + Table_Game::COLUMN_LIST.join("`,`") + "`"); + QString mainQueryCommand = filteredQueryCommand.arg(u"`"_s + Table_Game::COLUMN_LIST.join(u"`,`"_s) + u"`"_s); QString sizeQueryCommand = filteredQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); // Create main query and bind current platform @@ -516,8 +516,8 @@ DbError Db::queryAllAddApps(QueryBuffer& resultBuffer) return DbError::fromSqlError(dbError); // Make query - QString baseQueryCommand = "SELECT %1 FROM " + Table_Add_App::NAME; - QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Add_App::COLUMN_LIST.join("`,`") + "`"); + QString baseQueryCommand = u"SELECT %1 FROM "_s + Table_Add_App::NAME; + QString mainQueryCommand = baseQueryCommand.arg(u"`"_s + Table_Add_App::COLUMN_LIST.join(u"`,`"_s) + u"`"_s); QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); resultBuffer.source = Table_Add_App::NAME; @@ -530,9 +530,9 @@ DbError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) resultBuffer = QueryBuffer(); // Query Constants - const QString where = " WHERE "; - const QString nd = " AND "; - const QString likeTempl = " LIKE '%%1%' ESCAPE '\\'"; + const QString where = u" WHERE "_s; + const QString nd = u" AND "_s; + const QString likeTempl = u" LIKE '%%1%' ESCAPE '\\'"_s; // Get database QSqlDatabase fpDb; @@ -544,26 +544,26 @@ DbError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) if(filter.type != EntryType::AddApp) { // Assemble Base Query Command - QString baseQueryCommand = "SELECT %1 FROM " + Table_Game::NAME; + QString baseQueryCommand = u"SELECT %1 FROM "_s + Table_Game::NAME; if(!filter.parent.isNull() || !filter.id.isNull() || !filter.name.isNull()) { baseQueryCommand += where; if(!filter.id.isNull()) - baseQueryCommand += Table_Game::COL_ID + " == '" + filter.id.toString(QUuid::WithoutBraces) + "'" + nd; + baseQueryCommand += Table_Game::COL_ID + u" == '"_s + filter.id.toString(QUuid::WithoutBraces) + u"'"_s + nd; if(!filter.parent.isNull()) - baseQueryCommand += Table_Game::COL_PARENT_ID + " == '" + filter.parent.toString(QUuid::WithoutBraces) + "'" + nd; + baseQueryCommand += Table_Game::COL_PARENT_ID + u" == '"_s + filter.parent.toString(QUuid::WithoutBraces) + u"'"_s + nd; if(!filter.name.isNull()) { if(filter.exactName) - baseQueryCommand += Table_Game::COL_TITLE + " == '" + filter.name + "'" + nd; + baseQueryCommand += Table_Game::COL_TITLE + u" == '"_s + filter.name + u"'"_s + nd; else { // Escape name to account for SQL LITE % QString escapedName = filter.name; - escapedName.replace(R"(\)", R"(\\)"); // Have to escape the escape char - escapedName.replace(R"(%)",R"(\%)"); + escapedName.replace(uR"(\)"_s, uR"(\\)"_s); // Have to escape the escape char + escapedName.replace(uR"(%)"_s, uR"(\%)"_s); baseQueryCommand += Table_Game::COL_TITLE + likeTempl.arg(escapedName) + nd; } @@ -574,7 +574,7 @@ DbError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) } // Assemble final query commands - QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Game::COLUMN_LIST.join("`,`") + "`"); + QString mainQueryCommand = baseQueryCommand.arg(u"`"_s + Table_Game::COLUMN_LIST.join(u"`,`"_s) + u"`"_s); QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); // Make query @@ -593,34 +593,34 @@ DbError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) if(filter.type != EntryType::Primary) { // Assemble Base Query Command - QString baseQueryCommand = "SELECT %1 FROM " + Table_Add_App::NAME; + QString baseQueryCommand = u"SELECT %1 FROM "_s + Table_Add_App::NAME; if(!filter.parent.isNull() || !filter.id.isNull() || !filter.name.isNull()) { baseQueryCommand += where; if(!filter.id.isNull()) - baseQueryCommand += Table_Add_App::COL_ID + " == '" + filter.id.toString(QUuid::WithoutBraces) + "'" + nd; + baseQueryCommand += Table_Add_App::COL_ID + u" == '"_s + filter.id.toString(QUuid::WithoutBraces) + u"'"_s + nd; if(!filter.parent.isNull()) - baseQueryCommand += Table_Add_App::COL_PARENT_ID + " == '" + filter.parent.toString(QUuid::WithoutBraces) + "'" + nd; + baseQueryCommand += Table_Add_App::COL_PARENT_ID + u" == '"_s + filter.parent.toString(QUuid::WithoutBraces) + u"'"_s + nd; if(!filter.name.isNull()) { if(filter.exactName) - baseQueryCommand += Table_Add_App::COL_NAME + " == '" + filter.name + "'" + nd; + baseQueryCommand += Table_Add_App::COL_NAME + u" == '"_s + filter.name + u"'"_s + nd; else { // Escape name to account for SQL LITE % QString escapedName = filter.name; - escapedName.replace(R"(\)", R"(\\)"); // Have to escape the escape char - escapedName.replace(R"(%)",R"(\%)"); + escapedName.replace(uR"(\)"_s, uR"(\\)"_s); // Have to escape the escape char + escapedName.replace(uR"(%)"_s, uR"(\%)"_s); baseQueryCommand += Table_Add_App::COL_NAME + likeTempl.arg(escapedName) + nd; } } if(filter.playableOnly) { - baseQueryCommand += Table_Add_App::COL_APP_PATH + " NOT IN ('" + Table_Add_App::ENTRY_EXTRAS + "','" + - Table_Add_App::ENTRY_MESSAGE + "') AND " + Table_Add_App::COL_AUTORUN + " != 1" + + baseQueryCommand += Table_Add_App::COL_APP_PATH + u" NOT IN ('"_s + Table_Add_App::ENTRY_EXTRAS + u"','"_s + + Table_Add_App::ENTRY_MESSAGE + u"') AND "_s + Table_Add_App::COL_AUTORUN + u" != 1"_s + nd; } @@ -629,7 +629,7 @@ DbError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) } // Assemble final query commands - QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Add_App::COLUMN_LIST.join("`,`") + "`"); + QString mainQueryCommand = baseQueryCommand.arg(u"`"_s + Table_Add_App::COLUMN_LIST.join(u"`,`"_s) + u"`"_s); QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); // Make query @@ -663,10 +663,10 @@ DbError Db::queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId) return DbError::fromSqlError(dbError); // Setup ID query - QString baseQueryCommand = "SELECT %1 FROM " + Table_Game_Data::NAME + " WHERE " + - Table_Game_Data::COL_GAME_ID + " == '" + appId.toString(QUuid::WithoutBraces) + "' " + - "ORDER BY " + Table_Game_Data::COL_DATE_ADDED + " DESC"; - QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Game_Data::COLUMN_LIST.join("`,`") + "`"); + QString baseQueryCommand = u"SELECT %1 FROM "_s + Table_Game_Data::NAME + u" WHERE "_s + + Table_Game_Data::COL_GAME_ID + u" == '"_s + appId.toString(QUuid::WithoutBraces) + u"' "_s + + u"ORDER BY "_s + Table_Game_Data::COL_DATE_ADDED + u" DESC"_s; + QString mainQueryCommand = baseQueryCommand.arg(u"`"_s + Table_Game_Data::COLUMN_LIST.join(u"`,`"_s) + u"`"_s); QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); // Make query @@ -688,10 +688,10 @@ DbError Db::queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter includeFilt return DbError::fromSqlError(dbError); // Make query - QString baseQueryCommand = "SELECT %2 FROM " + Table_Game::NAME + " WHERE " + - Table_Game::COL_STATUS + " != '" + Table_Game::ENTRY_NOT_WORK + "'%1"; - baseQueryCommand = baseQueryCommand.arg(includeFilter == LibraryFilter::Game ? " AND " + GAME_ONLY_FILTER : (includeFilter == LibraryFilter::Anim ? " AND " + ANIM_ONLY_FILTER : "")); - QString mainQueryCommand = baseQueryCommand.arg("`" + Table_Game::COL_ID + "`"); + QString baseQueryCommand = u"SELECT %2 FROM "_s + Table_Game::NAME + u" WHERE "_s + + Table_Game::COL_STATUS + u" != '"_s + Table_Game::ENTRY_NOT_WORK + u"'%1"_s; + baseQueryCommand = baseQueryCommand.arg(includeFilter == LibraryFilter::Game ? u" AND "_s + GAME_ONLY_FILTER : (includeFilter == LibraryFilter::Anim ? u" AND "_s + ANIM_ONLY_FILTER : u""_s)); + QString mainQueryCommand = baseQueryCommand.arg(u"`"_s + Table_Game::COL_ID + u"`"_s); QString sizeQueryCommand = baseQueryCommand.arg(GENERAL_QUERY_SIZE_COMMAND); resultBuffer.source = Table_Game::NAME; @@ -727,8 +727,8 @@ DbError Db::entryUsesDataPack(bool& resultBuffer, QUuid gameId) return DbError::fromSqlError(dbError); // Make query - QString packCheckQueryCommand = "SELECT " + GENERAL_QUERY_SIZE_COMMAND + " FROM " + Table_Game_Data::NAME + " WHERE " + - Table_Game_Data::COL_GAME_ID + " == '" + gameId.toString(QUuid::WithoutBraces) + "'"; + QString packCheckQueryCommand = u"SELECT "_s + GENERAL_QUERY_SIZE_COMMAND + u" FROM "_s + Table_Game_Data::NAME + u" WHERE "_s + + Table_Game_Data::COL_GAME_ID + u" == '"_s + gameId.toString(QUuid::WithoutBraces) + u"'"_s; QSqlQuery packCheckQuery(fpDb); packCheckQuery.setForwardOnly(true); @@ -862,8 +862,8 @@ DbError Db::updateGameDataOnDiskState(int packId, bool onDisk) return DbError::fromSqlError(dbError); // Make query - QString dataUpdateCommand = "UPDATE " + Table_Game_Data::NAME + " SET " + Table_Game_Data::COL_PRES_ON_DISK + " = " + QString::number(onDisk) + - " WHERE " + Table_Game_Data::COL_ID + " = " + QString::number(packId); + QString dataUpdateCommand = u"UPDATE "_s + Table_Game_Data::NAME + u" SET "_s + Table_Game_Data::COL_PRES_ON_DISK + u" = "_s + QString::number(onDisk) + + u" WHERE "_s + Table_Game_Data::COL_ID + u" = "_s + QString::number(packId); QSqlQuery packUpdateQuery(fpDb); packUpdateQuery.setForwardOnly(true); @@ -876,9 +876,9 @@ DbError Db::updateGameDataOnDiskState(int packId, bool onDisk) // Check that expected count was affected int rows = packUpdateQuery.numRowsAffected(); if(rows < 1) - return DbError(DbError::UpdateIneffective, Table_Game_Data::NAME + " SET " + Table_Game_Data::COL_PRES_ON_DISK); + return DbError(DbError::UpdateIneffective, Table_Game_Data::NAME + u" SET "_s + Table_Game_Data::COL_PRES_ON_DISK); else if(rows > 1) - return DbError(DbError::UpdateTooMany, Table_Game_Data::NAME + " SET " + Table_Game_Data::COL_PRES_ON_DISK); + return DbError(DbError::UpdateTooMany, Table_Game_Data::NAME + u" SET "_s + Table_Game_Data::COL_PRES_ON_DISK); return DbError(); } diff --git a/lib/src/fp-install.cpp b/lib/src/fp-install.cpp index 468255f..742d930 100644 --- a/lib/src/fp-install.cpp +++ b/lib/src/fp-install.cpp @@ -20,12 +20,12 @@ Install::Install(QString installPath) : // Initialize static files and directories mRootDirectory = QDir(installPath); - mLauncherFile = std::make_unique(installPath + "/" + LAUNCHER_PATH); - mDatabaseFile = std::make_unique(installPath + "/" + DATABASE_PATH); - mConfigJsonFile = std::make_shared(installPath + "/" + CONFIG_JSON_PATH); - mPreferencesJsonFile = std::make_shared(installPath + "/" + PREFERENCES_JSON_PATH); - mVersionFile = std::make_unique(installPath + "/" + VER_TXT_PATH); - mExtrasDirectory = QDir(installPath + "/" + EXTRAS_PATH); + mLauncherFile = std::make_unique(installPath + u"/"_s + LAUNCHER_PATH); + mDatabaseFile = std::make_unique(installPath + u"/"_s + DATABASE_PATH); + mConfigJsonFile = std::make_shared(installPath + u"/"_s + CONFIG_JSON_PATH); + mPreferencesJsonFile = std::make_shared(installPath + u"/"_s + PREFERENCES_JSON_PATH); + mVersionFile = std::make_unique(installPath + u"/"_s + VER_TXT_PATH); + mExtrasDirectory = QDir(installPath + u"/"_s + EXTRAS_PATH); // Create macro resolver mMacroResolver = new MacroResolver(mRootDirectory.absolutePath(), {}); @@ -60,11 +60,11 @@ Install::Install(QString installPath) : if((mError = prefReader.readInto()).isValid()) return; - mServicesJsonFile = std::make_shared(installPath + "/" + mPreferences.jsonFolderPath + "/" + SERVICES_JSON_NAME); - mExecsJsonFile = std::make_shared(installPath + "/" + mPreferences.jsonFolderPath + "/" + EXECS_JSON_NAME); - mLogosDirectory = QDir(installPath + "/" + mPreferences.imageFolderPath + '/' + LOGOS_FOLDER_NAME); - mScreenshotsDirectory = QDir(installPath + "/" + mPreferences.imageFolderPath + '/' + SCREENSHOTS_FOLDER_NAME); - mPlaylistsDirectory = QDir(installPath + "/" + mPreferences.playlistFolderPath); + mServicesJsonFile = std::make_shared(installPath + u"/"_s + mPreferences.jsonFolderPath + u"/"_s + SERVICES_JSON_NAME); + mExecsJsonFile = std::make_shared(installPath + u"/"_s + mPreferences.jsonFolderPath + u"/"_s + EXECS_JSON_NAME); + mLogosDirectory = QDir(installPath + u"/"_s + mPreferences.imageFolderPath + '/' + LOGOS_FOLDER_NAME); + mScreenshotsDirectory = QDir(installPath + u"/"_s + mPreferences.imageFolderPath + '/' + SCREENSHOTS_FOLDER_NAME); + mPlaylistsDirectory = QDir(installPath + u"/"_s + mPreferences.playlistFolderPath); ServicesReader servicesReader(&mServices, mServicesJsonFile, mMacroResolver); if((mError = servicesReader.readInto()).isValid()) @@ -125,7 +125,7 @@ Qx::Error Install::appInvolvesSecurePlayer(bool& involvesBuffer, QFileInfo appIn involvesBuffer = true; return Qx::Error(); } - else if(appInfo.suffix().compare("bat", Qt::CaseInsensitive) == 0) + else if(appInfo.suffix().compare(u"bat"_s, Qt::CaseInsensitive) == 0) { // Check if bat uses secure player QFile batFile(appInfo.absoluteFilePath()); @@ -178,8 +178,8 @@ Install::Edition Install::edition() const { QString nameVer = nameVersionString(); - return nameVer.contains("ultimate", Qt::CaseInsensitive) ? Edition::Ultimate : - nameVer.contains("infinity", Qt::CaseInsensitive) ? Edition::Infinity : + return nameVer.contains(u"ultimate"_s, Qt::CaseInsensitive) ? Edition::Ultimate : + nameVer.contains(u"infinity"_s, Qt::CaseInsensitive) ? Edition::Infinity : Edition::Core; } @@ -200,7 +200,7 @@ Qx::VersionNumber Install::version() const if(versionMatch.hasMatch()) { - Qx::VersionNumber fpVersion = Qx::VersionNumber::fromString(versionMatch.captured("version")); + Qx::VersionNumber fpVersion = Qx::VersionNumber::fromString(versionMatch.captured(u"version"_s)); if(!fpVersion.isNull()) return fpVersion; } diff --git a/lib/src/fp-items.cpp b/lib/src/fp-items.cpp index da7463d..24b18b2 100644 --- a/lib/src/fp-items.cpp +++ b/lib/src/fp-items.cpp @@ -51,8 +51,8 @@ Game::Builder::Builder() {} //Private: QString Game::Builder::kosherizeRawDate(QString date) { - static const QString DEFAULT_MONTH = "-01"; - static const QString DEFAULT_DAY = "-01"; + static const QString DEFAULT_MONTH = u"-01"_s; + static const QString DEFAULT_DAY = u"-01"_s; if(Qx::String::isOnlyNumbers(date) && date.length() == 4) // Year only return date + DEFAULT_MONTH + DEFAULT_DAY; diff --git a/lib/src/fp-playlistmanager.cpp b/lib/src/fp-playlistmanager.cpp index f3372e0..fb410bf 100644 --- a/lib/src/fp-playlistmanager.cpp +++ b/lib/src/fp-playlistmanager.cpp @@ -60,7 +60,7 @@ PlaylistManager::PlaylistManager(const QDir& folder, const Key&) : mPopulated(false), mFolder(folder) { - mFolder.setNameFilters({"*.json"}); + mFolder.setNameFilters({u"*.json"_s}); mFolder.setFilter(QDir::Files); } diff --git a/lib/src/settings/fp-services.cpp b/lib/src/settings/fp-services.cpp index 3e15183..bea03d8 100644 --- a/lib/src/settings/fp-services.cpp +++ b/lib/src/settings/fp-services.cpp @@ -91,13 +91,13 @@ Qx::JsonError ServicesReader::parseDocument(const QJsonDocument& servicesDoc) for(const ServerDaemon& d : qAsConst(targetServices->daemon)) { /* NOTE: If for some reason this list becomes large, use a hash instead - * (e.g. if(hash.contains("NAME")){ recognizedDaemons.setFlag(hash["NAME]); } ) + * (e.g. if(hash.contains(u"NAME"_s)){ recognizedDaemons.setFlag(hash["NAME]); } ) */ - if(d.name.contains("qemu", Qt::CaseInsensitive) || - d.filename.contains("qemu", Qt::CaseInsensitive)) + if(d.name.contains(u"qemu"_s, Qt::CaseInsensitive) || + d.filename.contains(u"qemu"_s, Qt::CaseInsensitive)) targetServices->recognizedDaemons.setFlag(KnownDaemon::Qemu); - else if(d.name.contains("docker", Qt::CaseInsensitive) || - d.filename.contains("docker", Qt::CaseInsensitive)) + else if(d.name.contains(u"docker"_s, Qt::CaseInsensitive) || + d.filename.contains(u"docker"_s, Qt::CaseInsensitive)) targetServices->recognizedDaemons.setFlag(KnownDaemon::Docker); } From 7663b1eff2813dfa54efee1aaad32f501ea58fba Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Sat, 22 Jul 2023 07:08:30 -0400 Subject: [PATCH 23/29] More pass by const& --- lib/include/fp/fp-db.h | 10 +++--- lib/include/fp/fp-install.h | 4 +-- lib/include/fp/fp-items.h | 72 ++++++++++++++++++------------------- lib/include/fp/fp-macro.h | 4 +-- lib/src/fp-db.cpp | 12 +++---- lib/src/fp-install.cpp | 4 +-- lib/src/fp-items.cpp | 72 ++++++++++++++++++------------------- lib/src/fp-macro.cpp | 4 +-- 8 files changed, 91 insertions(+), 91 deletions(-) diff --git a/lib/include/fp/fp-db.h b/lib/include/fp/fp-db.h index 25f2a45..bdf3f3c 100644 --- a/lib/include/fp/fp-db.h +++ b/lib/include/fp/fp-db.h @@ -336,7 +336,7 @@ class FP_FP_EXPORT Db : public QObject void closeAllConnections(); QString threadConnectionName(const QThread* thread); QSqlError getThreadConnection(QSqlDatabase& connection); - QSqlError makeNonBindQuery(QueryBuffer& resultBuffer, QSqlDatabase* database, QString queryCommand, QString sizeQueryCommand) const; + QSqlError makeNonBindQuery(QueryBuffer& resultBuffer, QSqlDatabase* database, const QString& queryCommand, const QString& sizeQueryCommand) const; // Init QSqlError checkDatabaseForRequiredTables(QSet& missingTablesBuffer); @@ -352,22 +352,22 @@ class FP_FP_EXPORT Db : public QObject // TODO: See if these query functions can be consolidated via by better filtration arguments // Queries - OFLIb - DbError queryGamesByPlatform(QList& resultBuffer, QStringList platforms, InclusionOptions inclusionOptions, + DbError queryGamesByPlatform(QList& resultBuffer, const QStringList& platforms, const InclusionOptions& inclusionOptions, std::optional*> idInclusionFilter = std::nullopt); DbError queryAllAddApps(QueryBuffer& resultBuffer); DbError queryAllEntryTags(QueryBuffer& resultBuffer); // Queries - CLIFp - DbError queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter); + DbError queryEntrys(QueryBuffer& resultBuffer, const EntryFilter& filter); DbError queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId); - DbError queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter filter); + DbError queryAllGameIds(QueryBuffer& resultBuffer, const LibraryFilter& filter); // Info QStringList platformNames() const; QMap tags() const; // Checks - DbError entryUsesDataPack(bool& resultBuffer, QUuid gameId); + DbError entryUsesDataPack(bool& resultBuffer, const QUuid& gameId); // Helper DbError getEntry(std::variant& entry, const QUuid& entryId); diff --git a/lib/include/fp/fp-install.h b/lib/include/fp/fp-install.h index 516b3c5..4e372de 100644 --- a/lib/include/fp/fp-install.h +++ b/lib/include/fp/fp-install.h @@ -161,8 +161,8 @@ enum class Edition {Ultimate, Infinity, Core}; QDir logosDirectory() const; QDir screenshotsDirectory() const; QDir extrasDirectory() const; - QString imageLocalPath(ImageType imageType, QUuid gameId) const; - QUrl imageRemoteUrl(ImageType imageType, QUuid gameId) const; + QString imageLocalPath(ImageType imageType, const QUuid& gameId) const; + QUrl imageRemoteUrl(ImageType imageType, const QUuid& gameId) const; const MacroResolver* macroResolver() const; // Helper diff --git a/lib/include/fp/fp-items.h b/lib/include/fp/fp-items.h index a3f87c4..9f0fdc5 100644 --- a/lib/include/fp/fp-items.h +++ b/lib/include/fp/fp-items.h @@ -88,31 +88,31 @@ class FP_FP_EXPORT Game::Builder //-Class Functions--------------------------------------------------------------------------------------------- private: - static QString kosherizeRawDate(QString date); + static QString kosherizeRawDate(const QString& date); //-Instance Functions------------------------------------------------------------------------------------------ public: - Builder& wId(QString rawId); - Builder& wTitle(QString title); - Builder& wSeries(QString series); - Builder& wDeveloper(QString developer); - Builder& wPublisher(QString publisher); - Builder& wDateAdded(QString rawDateAdded); - Builder& wDateModified(QString rawDateModified); - Builder& wBroken(QString rawBroken); - Builder& wPlayMode(QString playMode); - Builder& wStatus(QString status); - Builder& wNotes(QString notes); - Builder& wSource(QString source); - Builder& wAppPath(QString appPath); - Builder& wLaunchCommand(QString launchCommand); - Builder& wReleaseDate(QString rawReleaseDate); - Builder& wVersion(QString version); - Builder& wOriginalDescription(QString originalDescription); - Builder& wLanguage(QString language); - Builder& wOrderTitle(QString orderTitle); - Builder& wLibrary(QString library); - Builder& wPlatformName(QString platformName); + Builder& wId(QStringView rawId); + Builder& wTitle(const QString& title); + Builder& wSeries(const QString& series); + Builder& wDeveloper(const QString& developer); + Builder& wPublisher(const QString& publisher); + Builder& wDateAdded(QStringView rawDateAdded); + Builder& wDateModified(QStringView rawDateModified); + Builder& wBroken(QStringView rawBroken); + Builder& wPlayMode(const QString& playMode); + Builder& wStatus(const QString& status); + Builder& wNotes(const QString& notes); + Builder& wSource(const QString& source); + Builder& wAppPath(const QString& appPath); + Builder& wLaunchCommand(const QString& launchCommand); + Builder& wReleaseDate(QStringView rawReleaseDate); + Builder& wVersion(const QString& version); + Builder& wOriginalDescription(const QString& originalDescription); + Builder& wLanguage(const QString& language); + Builder& wOrderTitle(const QString& orderTitle); + Builder& wLibrary(const QString& library); + Builder& wPlatformName(const QString& platformName); Game build(); }; @@ -247,13 +247,13 @@ class FP_FP_EXPORT AddApp::Builder //-Instance Functions------------------------------------------------------------------------------------------ public: - Builder& wId(QString rawId); - Builder& wAppPath(QString appPath); - Builder& wAutorunBefore(QString rawAutorunBefore); - Builder& wLaunchCommand(QString launchCommand); - Builder& wName(QString name); - Builder& wWaitExit(QString rawWaitExit); - Builder& wParentId(QString rawParentId); + Builder& wId(QStringView rawId); + Builder& wAppPath(const QString& appPath); + Builder& wAutorunBefore(QStringView rawAutorunBefore); + Builder& wLaunchCommand(const QString& launchCommand); + Builder& wName(const QString& name); + Builder& wWaitExit(QStringView rawWaitExit); + Builder& wParentId(QStringView rawParentId); AddApp build(); }; @@ -336,9 +336,9 @@ class FP_FP_EXPORT PlaylistGame::Builder //-Instance Functions------------------------------------------------------------------------------------------ public: Builder& wId(int id); - Builder& wPlaylistId(QString rawPlaylistId); + Builder& wPlaylistId(QStringView rawPlaylistId); Builder& wOrder(int order); - Builder& wGameId(QString rawGameId); + Builder& wGameId(QStringView rawGameId); PlaylistGame build(); }; @@ -387,11 +387,11 @@ class FP_FP_EXPORT Playlist::Builder //-Instance Functions------------------------------------------------------------------------------------------ public: - Builder& wId(QString rawId); - Builder& wTitle(QString title); - Builder& wDescription(QString description); - Builder& wAuthor(QString author); - Builder& wLibrary(QString library); + Builder& wId(QStringView rawId); + Builder& wTitle(const QString& title); + Builder& wDescription(const QString& description); + Builder& wAuthor(const QString& author); + Builder& wLibrary(const QString& library); Builder& wPlaylistGame(const PlaylistGame& playlistGame); Playlist build(); diff --git a/lib/include/fp/fp-macro.h b/lib/include/fp/fp-macro.h index 6e0ee6d..f5eece3 100644 --- a/lib/include/fp/fp-macro.h +++ b/lib/include/fp/fp-macro.h @@ -34,11 +34,11 @@ class FP_FP_EXPORT MacroResolver //-Constructor------------------------------------------------------------------------------------------------- public: - MacroResolver(QString installPath, const Key&); // Will need to be improved if many more macros are added + MacroResolver(const QString& installPath, const Key&); // Will need to be improved if many more macros are added //-Instance Functions------------------------------------------------------------------------------------------------------ public: - QString resolve(QString macroStr) const; + QString resolve(const QString& macroStr) const; }; } diff --git a/lib/src/fp-db.cpp b/lib/src/fp-db.cpp index 2ab44d4..584eb7f 100644 --- a/lib/src/fp-db.cpp +++ b/lib/src/fp-db.cpp @@ -214,7 +214,7 @@ QSqlError Db::getThreadConnection(QSqlDatabase& connection) } } -QSqlError Db::makeNonBindQuery(QueryBuffer& resultBuffer, QSqlDatabase* database, QString queryCommand, QString sizeQueryCommand) const +QSqlError Db::makeNonBindQuery(QueryBuffer& resultBuffer, QSqlDatabase* database, const QString& queryCommand, const QString& sizeQueryCommand) const { // Create main query QSqlQuery mainQuery(*database); @@ -277,7 +277,7 @@ QSqlError Db::checkDatabaseForRequiredTables(QSet& missingTablesReturnB return QSqlError(); } -QSqlError Db::checkDatabaseForRequiredColumns(QSet &missingColumsReturnBuffer) +QSqlError Db::checkDatabaseForRequiredColumns(QSet& missingColumsReturnBuffer) { // Ensure return buffer starts empty @@ -412,7 +412,7 @@ QSqlError Db::populateTags() return QSqlError(); } -DbError Db::queryGamesByPlatform(QList& resultBuffer, QStringList platforms, InclusionOptions inclusionOptions, +DbError Db::queryGamesByPlatform(QList& resultBuffer, const QStringList& platforms, const InclusionOptions& inclusionOptions, std::optional*> idInclusionFilter) { // Ensure return buffer is reset @@ -524,7 +524,7 @@ DbError Db::queryAllAddApps(QueryBuffer& resultBuffer) return DbError::fromSqlError(makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand)); } -DbError Db::queryEntrys(QueryBuffer& resultBuffer, EntryFilter filter) +DbError Db::queryEntrys(QueryBuffer& resultBuffer, const EntryFilter& filter) { // Ensure return buffer is effectively null resultBuffer = QueryBuffer(); @@ -676,7 +676,7 @@ DbError Db::queryEntryDataById(QueryBuffer& resultBuffer, const QUuid& appId) return DbError::fromSqlError(makeNonBindQuery(resultBuffer, &fpDb, mainQueryCommand, sizeQueryCommand)); } -DbError Db::queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter includeFilter) +DbError Db::queryAllGameIds(QueryBuffer& resultBuffer, const LibraryFilter& includeFilter) { // Ensure return buffer is effectively null resultBuffer = QueryBuffer(); @@ -701,7 +701,7 @@ DbError Db::queryAllGameIds(QueryBuffer& resultBuffer, LibraryFilter includeFilt QStringList Db::platformNames() const { return mPlatformNames; } //TODO: Probably should use RAII for this. QMap Db::tags() const { return mTagMap; } -DbError Db::entryUsesDataPack(bool& resultBuffer, QUuid gameId) +DbError Db::entryUsesDataPack(bool& resultBuffer, const QUuid& gameId) { /* NOTE: The launcher performs this check and other data pack tasks by checking if the `activeDataId` column * of the `game` table has a value, and if it does, then matching that to the `id` column in the `game_data` diff --git a/lib/src/fp-install.cpp b/lib/src/fp-install.cpp index 742d930..355142c 100644 --- a/lib/src/fp-install.cpp +++ b/lib/src/fp-install.cpp @@ -230,7 +230,7 @@ QDir Install::logosDirectory() const { return mLogosDirectory; } QDir Install::screenshotsDirectory() const { return mScreenshotsDirectory; } QDir Install::extrasDirectory() const { return mExtrasDirectory; } -QString Install::imageLocalPath(ImageType imageType, QUuid gameId) const +QString Install::imageLocalPath(ImageType imageType, const QUuid& gameId) const { const QDir& sourceDir = imageType == ImageType::Logo ? mLogosDirectory : mScreenshotsDirectory; bool compressed = mPreferences.onDemandImagesCompressed; @@ -239,7 +239,7 @@ QString Install::imageLocalPath(ImageType imageType, QUuid gameId) const return sourceDir.absolutePath() + '/' + localSubPath; } -QUrl Install::imageRemoteUrl(ImageType imageType, QUuid gameId) const +QUrl Install::imageRemoteUrl(ImageType imageType, const QUuid& gameId) const { const QString typeFolder = (imageType == ImageType::Logo ? LOGOS_FOLDER_NAME : SCREENSHOTS_FOLDER_NAME); bool compressed = mPreferences.onDemandImagesCompressed; diff --git a/lib/src/fp-items.cpp b/lib/src/fp-items.cpp index 24b18b2..eea4bbd 100644 --- a/lib/src/fp-items.cpp +++ b/lib/src/fp-items.cpp @@ -49,7 +49,7 @@ Game::Builder::Builder() {} //-Class Functions--------------------------------------------------------------------------------------------- //Private: -QString Game::Builder::kosherizeRawDate(QString date) +QString Game::Builder::kosherizeRawDate(const QString& date) { static const QString DEFAULT_MONTH = u"-01"_s; static const QString DEFAULT_DAY = u"-01"_s; @@ -71,27 +71,27 @@ QString Game::Builder::kosherizeRawDate(QString date) //-Instance Functions------------------------------------------------------------------------------------------ //Public: -Game::Builder& Game::Builder::wId(QString rawId) { mGameBlueprint.mId = QUuid(rawId); return *this; } -Game::Builder& Game::Builder::wTitle(QString title) { mGameBlueprint.mTitle = title; return *this; } -Game::Builder& Game::Builder::wSeries(QString series) { mGameBlueprint.mSeries = series; return *this; } -Game::Builder& Game::Builder::wDeveloper(QString developer) { mGameBlueprint.mDeveloper = developer; return *this; } -Game::Builder& Game::Builder::wPublisher(QString publisher) { mGameBlueprint.mPublisher = publisher; return *this; } -Game::Builder& Game::Builder::wDateAdded(QString rawDateAdded) { mGameBlueprint.mDateAdded = QDateTime::fromString(rawDateAdded, Qt::ISODateWithMs); return *this; } -Game::Builder& Game::Builder::wDateModified(QString rawDateModified) { mGameBlueprint.mDateModified = QDateTime::fromString(rawDateModified, Qt::ISODateWithMs); return *this; } -Game::Builder& Game::Builder::wBroken(QString rawBroken) { mGameBlueprint.mBroken = rawBroken.toInt() != 0; return *this; } -Game::Builder& Game::Builder::wPlayMode(QString playMode) { mGameBlueprint.mPlayMode = playMode; return *this; } -Game::Builder& Game::Builder::wStatus(QString status) { mGameBlueprint.mStatus = status; return *this; } -Game::Builder& Game::Builder::wNotes(QString notes) { mGameBlueprint.mNotes = notes; return *this; } -Game::Builder& Game::Builder::wSource(QString source) { mGameBlueprint.mSource = source; return *this; } -Game::Builder& Game::Builder::wAppPath(QString appPath) { mGameBlueprint.mAppPath = appPath; return *this; } -Game::Builder& Game::Builder::wLaunchCommand(QString launchCommand) { mGameBlueprint.mLaunchCommand = launchCommand; return *this; } -Game::Builder& Game::Builder::wReleaseDate(QString rawReleaseDate) { mGameBlueprint.mReleaseDate = QDateTime::fromString(kosherizeRawDate(rawReleaseDate), Qt::ISODate); return *this; } -Game::Builder& Game::Builder::wVersion(QString version) { mGameBlueprint.mVersion = version; return *this; } -Game::Builder& Game::Builder::wOriginalDescription(QString originalDescription) { mGameBlueprint.mOriginalDescription = originalDescription; return *this; } -Game::Builder& Game::Builder::wLanguage(QString language) { mGameBlueprint.mLanguage = language; return *this; } -Game::Builder& Game::Builder::wOrderTitle(QString orderTitle) { mGameBlueprint.mOrderTitle = orderTitle; return *this; } -Game::Builder& Game::Builder::wLibrary(QString library) { mGameBlueprint.mLibrary = library; return *this; } -Game::Builder& Game::Builder::wPlatformName(QString platformName) { mGameBlueprint.mPlatformName = platformName; return *this; } +Game::Builder& Game::Builder::wId(QStringView rawId) { mGameBlueprint.mId = QUuid(rawId); return *this; } +Game::Builder& Game::Builder::wTitle(const QString& title) { mGameBlueprint.mTitle = title; return *this; } +Game::Builder& Game::Builder::wSeries(const QString& series) { mGameBlueprint.mSeries = series; return *this; } +Game::Builder& Game::Builder::wDeveloper(const QString& developer) { mGameBlueprint.mDeveloper = developer; return *this; } +Game::Builder& Game::Builder::wPublisher(const QString& publisher) { mGameBlueprint.mPublisher = publisher; return *this; } +Game::Builder& Game::Builder::wDateAdded(QStringView rawDateAdded) { mGameBlueprint.mDateAdded = QDateTime::fromString(rawDateAdded, Qt::ISODateWithMs); return *this; } +Game::Builder& Game::Builder::wDateModified(QStringView rawDateModified) { mGameBlueprint.mDateModified = QDateTime::fromString(rawDateModified, Qt::ISODateWithMs); return *this; } +Game::Builder& Game::Builder::wBroken(QStringView rawBroken) { mGameBlueprint.mBroken = rawBroken.toInt() != 0; return *this; } +Game::Builder& Game::Builder::wPlayMode(const QString& playMode) { mGameBlueprint.mPlayMode = playMode; return *this; } +Game::Builder& Game::Builder::wStatus(const QString& status) { mGameBlueprint.mStatus = status; return *this; } +Game::Builder& Game::Builder::wNotes(const QString& notes) { mGameBlueprint.mNotes = notes; return *this; } +Game::Builder& Game::Builder::wSource(const QString& source) { mGameBlueprint.mSource = source; return *this; } +Game::Builder& Game::Builder::wAppPath(const QString& appPath) { mGameBlueprint.mAppPath = appPath; return *this; } +Game::Builder& Game::Builder::wLaunchCommand(const QString& launchCommand) { mGameBlueprint.mLaunchCommand = launchCommand; return *this; } +Game::Builder& Game::Builder::wReleaseDate(QStringView rawReleaseDate) { mGameBlueprint.mReleaseDate = QDateTime::fromString(kosherizeRawDate(rawReleaseDate.toString()), Qt::ISODate); return *this; } +Game::Builder& Game::Builder::wVersion(const QString& version) { mGameBlueprint.mVersion = version; return *this; } +Game::Builder& Game::Builder::wOriginalDescription(const QString& originalDescription) { mGameBlueprint.mOriginalDescription = originalDescription; return *this; } +Game::Builder& Game::Builder::wLanguage(const QString& language) { mGameBlueprint.mLanguage = language; return *this; } +Game::Builder& Game::Builder::wOrderTitle(const QString& orderTitle) { mGameBlueprint.mOrderTitle = orderTitle; return *this; } +Game::Builder& Game::Builder::wLibrary(const QString& library) { mGameBlueprint.mLibrary = library; return *this; } +Game::Builder& Game::Builder::wPlatformName(const QString& platformName) { mGameBlueprint.mPlatformName = platformName; return *this; } Game Game::Builder::build() { return mGameBlueprint; } @@ -204,13 +204,13 @@ AddApp::Builder::Builder() {} //-Instance Functions------------------------------------------------------------------------------------------ //Public: -AddApp::Builder& AddApp::Builder::wId(QString rawId) { mAddAppBlueprint.mId = QUuid(rawId); return *this; } -AddApp::Builder& AddApp::Builder::wAppPath(QString appPath) { mAddAppBlueprint.mAppPath = appPath; return *this; } -AddApp::Builder& AddApp::Builder::wAutorunBefore(QString rawAutorunBefore) { mAddAppBlueprint.mAutorunBefore = rawAutorunBefore.toInt() != 0; return *this; } -AddApp::Builder& AddApp::Builder::wLaunchCommand(QString launchCommand) { mAddAppBlueprint.mLaunchCommand = launchCommand; return *this; } -AddApp::Builder& AddApp::Builder::wName(QString name) { mAddAppBlueprint.mName = name; return *this; } -AddApp::Builder& AddApp::Builder::wWaitExit(QString rawWaitExit) { mAddAppBlueprint.mWaitExit = rawWaitExit.toInt() != 0; return *this; } -AddApp::Builder& AddApp::Builder::wParentId(QString rawParentId) { mAddAppBlueprint.mParentId = QUuid(rawParentId); return *this; } +AddApp::Builder& AddApp::Builder::wId(QStringView rawId) { mAddAppBlueprint.mId = QUuid(rawId); return *this; } +AddApp::Builder& AddApp::Builder::wAppPath(const QString& appPath) { mAddAppBlueprint.mAppPath = appPath; return *this; } +AddApp::Builder& AddApp::Builder::wAutorunBefore(QStringView rawAutorunBefore) { mAddAppBlueprint.mAutorunBefore = rawAutorunBefore.toInt() != 0; return *this; } +AddApp::Builder& AddApp::Builder::wLaunchCommand(const QString& launchCommand) { mAddAppBlueprint.mLaunchCommand = launchCommand; return *this; } +AddApp::Builder& AddApp::Builder::wName(const QString& name) { mAddAppBlueprint.mName = name; return *this; } +AddApp::Builder& AddApp::Builder::wWaitExit(QStringView rawWaitExit) { mAddAppBlueprint.mWaitExit = rawWaitExit.toInt() != 0; return *this; } +AddApp::Builder& AddApp::Builder::wParentId(QStringView rawParentId) { mAddAppBlueprint.mParentId = QUuid(rawParentId); return *this; } AddApp AddApp::Builder::build() { return mAddAppBlueprint; } @@ -270,9 +270,9 @@ PlaylistGame::Builder::Builder() {} //-Instance Functions------------------------------------------------------------------------------------------ //Public: PlaylistGame::Builder& PlaylistGame::Builder::wId(int id) { mPlaylistGameBlueprint.mId = id; return *this; } -PlaylistGame::Builder& PlaylistGame::Builder::wPlaylistId(QString rawPlaylistId) { mPlaylistGameBlueprint.mPlaylistId = QUuid(rawPlaylistId); return *this; } +PlaylistGame::Builder& PlaylistGame::Builder::wPlaylistId(QStringView rawPlaylistId) { mPlaylistGameBlueprint.mPlaylistId = QUuid(rawPlaylistId); return *this; } PlaylistGame::Builder& PlaylistGame::Builder::wOrder(int order) { mPlaylistGameBlueprint.mOrder = order; return *this; } -PlaylistGame::Builder& PlaylistGame::Builder::wGameId(QString rawGameId) { mPlaylistGameBlueprint.mGameId = QUuid(rawGameId); return *this; } +PlaylistGame::Builder& PlaylistGame::Builder::wGameId(QStringView rawGameId) { mPlaylistGameBlueprint.mGameId = QUuid(rawGameId); return *this; } PlaylistGame PlaylistGame::Builder::build() { return mPlaylistGameBlueprint; } @@ -304,11 +304,11 @@ Playlist::Builder::Builder() {} //-Instance Functions------------------------------------------------------------------------------------------ //Public: -Playlist::Builder& Playlist::Builder::wId(QString rawId) { mPlaylistBlueprint.mId = QUuid(rawId); return *this; } -Playlist::Builder& Playlist::Builder::wTitle(QString title) { mPlaylistBlueprint.mTitle = title; return *this; } -Playlist::Builder& Playlist::Builder::wDescription(QString description) { mPlaylistBlueprint.mDescription = description; return *this; } -Playlist::Builder& Playlist::Builder::wAuthor(QString author) { mPlaylistBlueprint.mAuthor = author; return *this; } -Playlist::Builder& Playlist::Builder::wLibrary(QString library) { mPlaylistBlueprint.mLibrary = library; return *this; } +Playlist::Builder& Playlist::Builder::wId(QStringView rawId) { mPlaylistBlueprint.mId = QUuid(rawId); return *this; } +Playlist::Builder& Playlist::Builder::wTitle(const QString& title) { mPlaylistBlueprint.mTitle = title; return *this; } +Playlist::Builder& Playlist::Builder::wDescription(const QString& description) { mPlaylistBlueprint.mDescription = description; return *this; } +Playlist::Builder& Playlist::Builder::wAuthor(const QString& author) { mPlaylistBlueprint.mAuthor = author; return *this; } +Playlist::Builder& Playlist::Builder::wLibrary(const QString& library) { mPlaylistBlueprint.mLibrary = library; return *this; } Playlist::Builder& Playlist::Builder::wPlaylistGame(const PlaylistGame& playlistGame) { mPlaylistBlueprint.mPlaylistGames.append(playlistGame); return *this; } Playlist Playlist::Builder::build() { return mPlaylistBlueprint; } diff --git a/lib/src/fp-macro.cpp b/lib/src/fp-macro.cpp index 85af2c9..dc214db 100644 --- a/lib/src/fp-macro.cpp +++ b/lib/src/fp-macro.cpp @@ -10,14 +10,14 @@ namespace Fp //-Constructor------------------------------------------------------------------------------------------------ //Public: -MacroResolver::MacroResolver(QString installPath, const Key&) +MacroResolver::MacroResolver(const QString& installPath, const Key&) { mMacroMap[FP_PATH] = installPath; } //-Instance Functions------------------------------------------------------------------------------------------------ //Public: -QString MacroResolver::resolve(QString macroStr) const +QString MacroResolver::resolve(const QString& macroStr) const { QHash::const_iterator i; for(i = mMacroMap.constBegin(); i != mMacroMap.constEnd(); i++) From 12fb5e56c105a9e66c1e214d403722f721015789 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Sat, 22 Jul 2023 20:59:40 -0400 Subject: [PATCH 24/29] Fix macro resolver argument --- CMakeLists.txt | 2 +- lib/include/fp/fp-macro.h | 2 +- lib/src/fp-macro.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 477487e..b924d4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ set(LIBFP_QX_COMPONENTS include(OB/FetchQx) ob_fetch_qx( - REF "520cc55d4a38aeb98c945b5c0c1c6eb70459af35" + REF "6812df5c1fe1c584a9dfa0ded76db8727ca059b5" COMPONENTS ${LIBFP_QX_COMPONENTS} ) diff --git a/lib/include/fp/fp-macro.h b/lib/include/fp/fp-macro.h index f5eece3..1b0387b 100644 --- a/lib/include/fp/fp-macro.h +++ b/lib/include/fp/fp-macro.h @@ -38,7 +38,7 @@ class FP_FP_EXPORT MacroResolver //-Instance Functions------------------------------------------------------------------------------------------------------ public: - QString resolve(const QString& macroStr) const; + QString resolve(QString macroStr) const; }; } diff --git a/lib/src/fp-macro.cpp b/lib/src/fp-macro.cpp index dc214db..0d588dc 100644 --- a/lib/src/fp-macro.cpp +++ b/lib/src/fp-macro.cpp @@ -17,7 +17,7 @@ MacroResolver::MacroResolver(const QString& installPath, const Key&) //-Instance Functions------------------------------------------------------------------------------------------------ //Public: -QString MacroResolver::resolve(const QString& macroStr) const +QString MacroResolver::resolve(QString macroStr) const { QHash::const_iterator i; for(i = mMacroMap.constBegin(); i != mMacroMap.constEnd(); i++) From 166f04aed3c69bdc3a87d72335e508fdf4bcf97c Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Sun, 23 Jul 2023 01:44:58 -0400 Subject: [PATCH 25/29] Update deps --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b924d4c..e89d389 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ project(libfp # Get helper scripts include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/FetchOBCMake.cmake) -fetch_ob_cmake("v0.3") +fetch_ob_cmake("017b8cafc2d03208c6f1b9c06fbb3ab83cd7562e") # Initialize project according to standard rules include(OB/Project) @@ -52,7 +52,7 @@ set(LIBFP_QX_COMPONENTS include(OB/FetchQx) ob_fetch_qx( - REF "6812df5c1fe1c584a9dfa0ded76db8727ca059b5" + REF "a6f65d5ea4cf49c7be64d2c4ea2b53a41171730f" COMPONENTS ${LIBFP_QX_COMPONENTS} ) From b95889488ebb71a8be7da6701df45bef5fc149db Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Sun, 23 Jul 2023 03:16:44 -0400 Subject: [PATCH 26/29] Add Install constructor option to preload playlists --- lib/include/fp/fp-install.h | 2 +- lib/src/fp-install.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/include/fp/fp-install.h b/lib/include/fp/fp-install.h index 4e372de..089030c 100644 --- a/lib/include/fp/fp-install.h +++ b/lib/include/fp/fp-install.h @@ -115,7 +115,7 @@ enum class Edition {Ultimate, Infinity, Core}; //-Constructor------------------------------------------------------------------------------------------------- public: - Install(QString installPath); + Install(QString installPath, bool preloadPlaylists = false); //-Destructor------------------------------------------------------------------------------------------------- public: diff --git a/lib/src/fp-install.cpp b/lib/src/fp-install.cpp index 355142c..e6b4381 100644 --- a/lib/src/fp-install.cpp +++ b/lib/src/fp-install.cpp @@ -13,7 +13,7 @@ namespace Fp //-Constructor------------------------------------------------------------------------------------------------ //Public: -Install::Install(QString installPath) : +Install::Install(QString installPath, bool preloadPlaylists) : mValid(false) // Install is invalid until proven otherwise { QScopeGuard validityGuard([this](){ nullify(); }); // Automatically nullify on fail @@ -89,6 +89,12 @@ Install::Install(QString installPath) : // Add playlists manager mPlaylistManager = new PlaylistManager(mPlaylistsDirectory, {}); + if(preloadPlaylists) + { + if(mError = mPlaylistManager->populate(); mError.isValid()) + return; + } + // Give the OK mValid = true; validityGuard.dismiss(); From 7107ca019544ae8c656ff7280f6f46f7c921ac8d Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Sun, 23 Jul 2023 19:14:55 -0400 Subject: [PATCH 27/29] Change to Flashpoint Archive branding --- CMakeLists.txt | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e89d389..953913e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.23.0...3.25.0) project(libfp VERSION 0.3.1 LANGUAGES CXX - DESCRIPTION "C++ support library for Flashpoint" + DESCRIPTION "C++ support library for Flashpoint Archive" ) # Get helper scripts diff --git a/README.md b/README.md index a07cd02..0571a5c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # libfp -A C++ interface for instances of [Blue Maxima's Flashpoint](https://bluemaxima.org/flashpoint/) +A C++ interface for instances of [Flashpoint Archive](https://flashpointarchive.org/) [![Dev Builds](https://github.com/oblivioncth/libfp/actions/workflows/push-reaction.yml/badge.svg?branch=dev)](https://github.com/oblivioncth/libfp/actions/workflows/push-reaction.yml) From c5b798d39ef71e30c5513207f79f1ca83e86c488 Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Sun, 23 Jul 2023 19:50:24 -0400 Subject: [PATCH 28/29] Bump verison --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 953913e..3eaadc7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.23.0...3.25.0) # Project # NOTE: DON'T USE TRAILING ZEROS IN VERSIONS project(libfp - VERSION 0.3.1 + VERSION 0.4 LANGUAGES CXX DESCRIPTION "C++ support library for Flashpoint Archive" ) From 87aaaa15d8344d74060cd750a873fb3e4e716fbf Mon Sep 17 00:00:00 2001 From: Christian Heimlich Date: Sun, 23 Jul 2023 20:12:54 -0400 Subject: [PATCH 29/29] Bump version --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3eaadc7..526f53c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ project(libfp # Get helper scripts include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/FetchOBCMake.cmake) -fetch_ob_cmake("017b8cafc2d03208c6f1b9c06fbb3ab83cd7562e") +fetch_ob_cmake("v0.3.2") # Initialize project according to standard rules include(OB/Project) @@ -52,7 +52,7 @@ set(LIBFP_QX_COMPONENTS include(OB/FetchQx) ob_fetch_qx( - REF "a6f65d5ea4cf49c7be64d2c4ea2b53a41171730f" + REF "v0.5.1" COMPONENTS ${LIBFP_QX_COMPONENTS} )