diff options
Diffstat (limited to 'libs/game_gamebryo')
42 files changed, 0 insertions, 4772 deletions
diff --git a/libs/game_gamebryo/.clang-format b/libs/game_gamebryo/.clang-format deleted file mode 100644 index 6098e1f..0000000 --- a/libs/game_gamebryo/.clang-format +++ /dev/null @@ -1,41 +0,0 @@ ---- -# We'll use defaults from the LLVM style, but with 4 columns indentation. -BasedOnStyle: LLVM -IndentWidth: 2 ---- -Language: Cpp -DeriveLineEnding: false -UseCRLF: true -DerivePointerAlignment: false -PointerAlignment: Left -AlignConsecutiveAssignments: true -AllowShortFunctionsOnASingleLine: Inline -AllowShortIfStatementsOnASingleLine: Never -AllowShortLambdasOnASingleLine: Empty -AlwaysBreakTemplateDeclarations: Yes -AccessModifierOffset: -2 -AlignTrailingComments: true -SpacesBeforeTrailingComments: 2 -NamespaceIndentation: Inner -MaxEmptyLinesToKeep: 1 -BreakBeforeBraces: Custom -BraceWrapping: - AfterCaseLabel: false - AfterClass: true - AfterControlStatement: false - AfterEnum: true - AfterFunction: true - AfterNamespace: true - AfterStruct: true - AfterUnion: true - AfterExternBlock: true - BeforeCatch: false - BeforeElse: false - BeforeLambdaBody: false - BeforeWhile: false - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: false - SplitEmptyNamespace: true -ColumnLimit: 88 -ForEachMacros: ['Q_FOREACH', 'foreach'] diff --git a/libs/game_gamebryo/.git-blame-ignore-revs b/libs/game_gamebryo/.git-blame-ignore-revs deleted file mode 100644 index 7db8755..0000000 --- a/libs/game_gamebryo/.git-blame-ignore-revs +++ /dev/null @@ -1 +0,0 @@ -f4c5c5535551ed085bd65cb02058dcab2c9eb110 diff --git a/libs/game_gamebryo/.gitattributes b/libs/game_gamebryo/.gitattributes deleted file mode 100644 index f869712..0000000 --- a/libs/game_gamebryo/.gitattributes +++ /dev/null @@ -1,7 +0,0 @@ -# Set the default behavior, in case people don't have core.autocrlf set. -* text=auto - -# Explicitly declare text files you want to always be normalized and converted -# to native line endings on checkout. -*.cpp text eol=crlf -*.h text eol=crlf diff --git a/libs/game_gamebryo/.github/workflows/build.yml b/libs/game_gamebryo/.github/workflows/build.yml deleted file mode 100644 index 7efc43f..0000000 --- a/libs/game_gamebryo/.github/workflows/build.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Build GameBryo Library - -on: - push: - branches: master - pull_request: - types: [opened, synchronize, reopened] - -jobs: - build: - runs-on: windows-2022 - steps: - - name: Build GameBryo Library - uses: ModOrganizer2/build-with-mob-action@master - with: - mo2-third-parties: lz4 zlib - mo2-dependencies: cmake_common uibase diff --git a/libs/game_gamebryo/.github/workflows/linting.yml b/libs/game_gamebryo/.github/workflows/linting.yml deleted file mode 100644 index 1b8fe2a..0000000 --- a/libs/game_gamebryo/.github/workflows/linting.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Lint GameBryo Library - -on: - push: - pull_request: - types: [opened, synchronize, reopened] - -jobs: - lint: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Check format - uses: ModOrganizer2/check-formatting-action@master - with: - check-path: "." diff --git a/libs/game_gamebryo/.gitignore b/libs/game_gamebryo/.gitignore deleted file mode 100644 index cf71be7..0000000 --- a/libs/game_gamebryo/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -edit -CMakeLists.txt.user -/msbuild.log -/*std*.log -/*build diff --git a/libs/game_gamebryo/CMakeLists.txt b/libs/game_gamebryo/CMakeLists.txt deleted file mode 100644 index 5b7ffba..0000000 --- a/libs/game_gamebryo/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -if(DEFINED DEPENDENCIES_DIR) - include(${DEPENDENCIES_DIR}/modorganizer_super/cmake_common/mo2.cmake) -else() - include(${CMAKE_CURRENT_LIST_DIR}/../cmake_common/mo2.cmake) -endif() - -project(game_gamebryo) - -add_subdirectory(src/gamebryo) -add_subdirectory(src/creation) diff --git a/libs/game_gamebryo/README.md b/libs/game_gamebryo/README.md deleted file mode 100644 index 08b5eb4..0000000 --- a/libs/game_gamebryo/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Archived repository - Check [modorganizer-game_bethesda](https://github.com/ModOrganizer2/modorganizer-game_bethesda) - - -ModOrganizer2 plugins for most Bethesda games are now managed in a single repository -at https://github.com/ModOrganizer2/modorganizer-game_bethesda. diff --git a/libs/game_gamebryo/src/creation/CMakeLists.txt b/libs/game_gamebryo/src/creation/CMakeLists.txt deleted file mode 100644 index f2dce97..0000000 --- a/libs/game_gamebryo/src/creation/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -add_library(game_creation STATIC) -mo2_configure_library(game_creation - WARNINGS OFF - TRANSLATIONS ON - PUBLIC_DEPENDS uibase - PRIVATE_DEPENDS lz4) -target_link_libraries(game_creation PUBLIC game_gamebryo) -mo2_install_target(game_creation) diff --git a/libs/game_gamebryo/src/creation/creationgameplugins.cpp b/libs/game_gamebryo/src/creation/creationgameplugins.cpp deleted file mode 100644 index f5cef62..0000000 --- a/libs/game_gamebryo/src/creation/creationgameplugins.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "creationgameplugins.h" -#include <ipluginlist.h> -#include <report.h> -#include <safewritefile.h> -#include <scopeguard.h> - -#include <QDir> -#include <QSet> -#include <QStringEncoder> -#include <QStringList> - -using MOBase::IOrganizer; -using MOBase::IPluginGame; -using MOBase::IPluginList; -using MOBase::reportError; -using MOBase::SafeWriteFile; - -CreationGamePlugins::CreationGamePlugins(IOrganizer* organizer) - : GamebryoGamePlugins(organizer) -{} - -QStringList CreationGamePlugins::getLoadOrder() -{ - QString loadOrderPath = organizer()->profile()->absolutePath() + "/loadorder.txt"; - QString pluginsPath = organizer()->profile()->absolutePath() + "/plugins.txt"; - - bool loadOrderIsNew = !m_LastRead.isValid() || !QFileInfo(loadOrderPath).exists() || - QFileInfo(loadOrderPath).lastModified() > m_LastRead; - bool pluginsIsNew = - !m_LastRead.isValid() || QFileInfo(pluginsPath).lastModified() > m_LastRead; - - if (loadOrderIsNew || !pluginsIsNew) { - return readLoadOrderList(m_Organizer->pluginList(), loadOrderPath); - } else { - return readPluginList(m_Organizer->pluginList()); - } -} - -void CreationGamePlugins::writePluginList(const IPluginList* pluginList, - const QString& filePath) -{ - SafeWriteFile file(filePath); - - QStringEncoder encoder(QStringConverter::Encoding::System); - - file->resize(0); - - file->write( - encoder.encode("# This file was automatically generated by Mod Organizer.\r\n")); - - bool invalidFileNames = false; - int writtenCount = 0; - - QStringList plugins = pluginList->pluginNames(); - std::sort(plugins.begin(), plugins.end(), - [pluginList](const QString& lhs, const QString& rhs) { - return pluginList->priority(lhs) < pluginList->priority(rhs); - }); - - QStringList PrimaryPlugins = organizer()->managedGame()->primaryPlugins(); - QStringList DLCPlugins = organizer()->managedGame()->DLCPlugins(); - QSet<QString> ManagedMods = - QSet<QString>(PrimaryPlugins.begin(), PrimaryPlugins.end()); - QSet<QString> DLCSet = QSet<QString>(DLCPlugins.begin(), DLCPlugins.end()); - ManagedMods.subtract(DLCSet); - PrimaryPlugins.append(QList<QString>(ManagedMods.begin(), ManagedMods.end())); - - // TODO: do not write plugins in OFFICIAL_FILES container - for (const QString& pluginName : plugins) { - if (!PrimaryPlugins.contains(pluginName, Qt::CaseInsensitive)) { - if (pluginList->state(pluginName) == IPluginList::STATE_ACTIVE) { - auto result = encoder.encode(pluginName); - if (encoder.hasError()) { - invalidFileNames = true; - qCritical("invalid plugin name %s", qUtf8Printable(pluginName)); - } else { - file->write("*"); - file->write(result); - } - file->write("\r\n"); - ++writtenCount; - } else { - auto result = encoder.encode(pluginName); - if (encoder.hasError()) { - invalidFileNames = true; - qCritical("invalid plugin name %s", qUtf8Printable(pluginName)); - } else { - file->write(result); - } - file->write("\r\n"); - ++writtenCount; - } - } - } - - if (invalidFileNames) { - reportError(QObject::tr("Some of your plugins have invalid names! These " - "plugins can not be loaded by the game. Please see " - "mo_interface.log for a list of affected plugins " - "and rename them.")); - } - - file->commit(); -} - -QStringList CreationGamePlugins::readPluginList(MOBase::IPluginList* pluginList) -{ - const auto plugins = pluginList->pluginNames(); - const auto primaryPlugins = organizer()->managedGame()->primaryPlugins(); - QStringList loadOrder(primaryPlugins); - - for (const QString& pluginName : loadOrder) { - if (pluginList->state(pluginName) != IPluginList::STATE_MISSING) { - pluginList->setState(pluginName, IPluginList::STATE_ACTIVE); - } - } - - QString filePath = organizer()->profile()->absolutePath() + "/plugins.txt"; - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly)) { - qWarning("%s not found", qUtf8Printable(filePath)); - return loadOrder; - } - ON_BLOCK_EXIT([&]() { - file.close(); - }); - - if (file.size() == 0) { - // MO stores at least a header in the file. if it's completely empty the - // file is broken - qWarning("%s empty", qUtf8Printable(filePath)); - return loadOrder; - } - - QStringList pluginsFound; - while (!file.atEnd()) { - QByteArray line = file.readLine(); - QString pluginName; - if ((line.size() > 0) && (line.at(0) != '#')) { - pluginName = QStringEncoder(QStringConverter::Encoding::System) - .encode(line.trimmed().constData()); - } - if (!primaryPlugins.contains(pluginName, Qt::CaseInsensitive)) { - if (pluginName.startsWith('*')) { - pluginName.remove(0, 1); - if (pluginName.size() > 0) { - pluginList->setState(pluginName, IPluginList::STATE_ACTIVE); - pluginsFound.append(pluginName); - if (!loadOrder.contains(pluginName, Qt::CaseInsensitive)) { - loadOrder.append(pluginName); - } - } - } else { - if (pluginName.size() > 0) { - pluginList->setState(pluginName, IPluginList::STATE_INACTIVE); - pluginsFound.append(pluginName); - if (!loadOrder.contains(pluginName, Qt::CaseInsensitive)) { - loadOrder.append(pluginName); - } - } - } - } else { - pluginName.remove(0, 1); - pluginsFound.append(pluginName); - } - } - - file.close(); - - // set all plugins not found inactive - for (const auto& pluginName : plugins) { - if (!pluginsFound.contains(pluginName, Qt::CaseInsensitive)) { - pluginList->setState(pluginName, IPluginList::STATE_INACTIVE); - } - } - - return loadOrder; -} - -bool CreationGamePlugins::lightPluginsAreSupported() -{ - return true; -} diff --git a/libs/game_gamebryo/src/creation/creationgameplugins.h b/libs/game_gamebryo/src/creation/creationgameplugins.h deleted file mode 100644 index f7afd80..0000000 --- a/libs/game_gamebryo/src/creation/creationgameplugins.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef CREATIONGAMEPLUGINS_H -#define CREATIONGAMEPLUGINS_H - -#include <gamebryogameplugins.h> -#include <imoinfo.h> -#include <iplugingame.h> -#include <map> - -class CreationGamePlugins : public GamebryoGamePlugins -{ -public: - CreationGamePlugins(MOBase::IOrganizer* organizer); - -protected: - virtual void writePluginList(const MOBase::IPluginList* pluginList, - const QString& filePath) override; - virtual QStringList readPluginList(MOBase::IPluginList* pluginList) override; - virtual QStringList getLoadOrder() override; - virtual bool lightPluginsAreSupported() override; -}; - -#endif // CREATIONGAMEPLUGINS_H diff --git a/libs/game_gamebryo/src/creation/game_creation_en.ts b/libs/game_gamebryo/src/creation/game_creation_en.ts deleted file mode 100644 index f217448..0000000 --- a/libs/game_gamebryo/src/creation/game_creation_en.ts +++ /dev/null @@ -1,12 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!DOCTYPE TS> -<TS version="2.1" language="en_US"> -<context> - <name>QObject</name> - <message> - <location filename="creationgameplugins.cpp" line="97"/> - <source>Some of your plugins have invalid names! These plugins can not be loaded by the game. Please see mo_interface.log for a list of affected plugins and rename them.</source> - <translation type="unfinished"></translation> - </message> -</context> -</TS> diff --git a/libs/game_gamebryo/src/gamebryo/CMakeLists.txt b/libs/game_gamebryo/src/gamebryo/CMakeLists.txt deleted file mode 100644 index cff88fc..0000000 --- a/libs/game_gamebryo/src/gamebryo/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -add_library(game_gamebryo STATIC) -mo2_configure_library(game_gamebryo - WARNINGS OFF - TRANSLATIONS ON - AUTOMOC ON - PUBLIC_DEPENDS uibase - PRIVATE_DEPENDS zlib lz4) -mo2_install_target(game_gamebryo) diff --git a/libs/game_gamebryo/src/gamebryo/dummybsa.cpp b/libs/game_gamebryo/src/gamebryo/dummybsa.cpp deleted file mode 100644 index ba6f766..0000000 --- a/libs/game_gamebryo/src/gamebryo/dummybsa.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* -Copyright (C) 2012 Sebastian Herbord. All rights reserved. - -This file is part of Mod Organizer. - -Mod Organizer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Mod Organizer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. -*/ - -#include "dummybsa.h" -#include <QFile> -#define WIN32_LEAN_AND_MEAN -#include <Windows.h> - -static void writeUlong(unsigned char* buffer, int offset, unsigned long value) -{ - union - { - unsigned long ulValue; - unsigned char cValue[4]; - }; - ulValue = value; - memcpy(buffer + offset, cValue, 4); -} - -static void writeUlonglong(unsigned char* buffer, int offset, unsigned long long value) -{ - union - { - unsigned long long ullValue; - unsigned char cValue[8]; - }; - ullValue = value; - memcpy(buffer + offset, cValue, 8); -} - -static unsigned long genHashInt(const unsigned char* pos, const unsigned char* end) -{ - unsigned long hash = 0; - for (; pos < end; ++pos) { - hash *= 0x1003f; - hash += *pos; - } - return hash; -} - -static unsigned long long genHash(const char* fileName) -{ - char fileNameLower[MAX_PATH + 1]; - int i = 0; - for (; i < MAX_PATH && fileName[i] != '\0'; ++i) { - fileNameLower[i] = static_cast<char>(tolower(fileName[i])); - if (fileNameLower[i] == '\\') { - fileNameLower[i] = '/'; - } - } - fileNameLower[i] = '\0'; - - unsigned char* fileNameLowerU = reinterpret_cast<unsigned char*>(fileNameLower); - - char* ext = strrchr(fileNameLower, '.'); - if (ext == nullptr) { - ext = fileNameLower + strlen(fileNameLower); - } - unsigned char* extU = reinterpret_cast<unsigned char*>(ext); - - int length = ext - fileNameLower; - - unsigned long long hash = 0ULL; - - if (length > 0) { - hash = *(extU - 1) | ((length > 2 ? *(ext - 2) : 0) << 8) | (length << 16) | - (fileNameLowerU[0] << 24); - } - - if (strlen(ext) > 0) { - if (strcmp(ext + 1, "kf") == 0) { - hash |= 0x80; - } else if (strcmp(ext + 1, "nif") == 0) { - hash |= 0x8000; - } else if (strcmp(ext + 1, "dds") == 0) { - hash |= 0x8080; - } else if (strcmp(ext + 1, "wav") == 0) { - hash |= 0x80000000; - } - - unsigned long long temp = - static_cast<unsigned long long>(genHashInt(fileNameLowerU + 1, extU - 2)); - temp += static_cast<unsigned long long>(genHashInt(extU, extU + strlen(ext))); - - hash |= (temp & 0xFFFFFFFF) << 32; - } - return hash; -} - -DummyBSA::DummyBSA(unsigned long bsaVersion) - : m_Version(bsaVersion), m_FolderName(""), m_FileName("dummy.dds"), - m_TotalFileNameLength(0) -{} - -void DummyBSA::writeHeader(QFile& file) -{ - unsigned char header[] = { - 'B', 'S', 'A', '\0', // magic string - 0xDE, 0xAD, 0xBE, 0xEF, // version - insert later - 0x24, 0x00, 0x00, 0x00, // offset to folder recors. header size is static - 0xDE, 0xAD, 0xBE, 0xEF, // archive flags - insert later - 0x01, 0x00, 0x00, 0x00, // folder count - 0x01, 0x00, 0x00, 0x00, // file count - 0xDE, 0xAD, 0xBE, 0xEF, // total folder names length - insert later - 0xDE, 0xAD, 0xBE, 0xEF, // total file names length - insert later - 0xDE, 0xAD, 0xBE, 0xEF // file flags - insert later - }; - - writeUlong(header, 4, m_Version); - writeUlong(header, 12, 0x01 | 0x02); // has directories and has files. - writeUlong(header, 24, - static_cast<unsigned long>(m_FolderName.length()) + - 1); // empty folder name - writeUlong(header, 28, m_TotalFileNameLength); // single character file name - - writeUlong(header, 32, 2); // has dds - - file.write(reinterpret_cast<char*>(header), sizeof(header)); -} - -void DummyBSA::writeFolderRecord(QFile& file, const std::string& folderName) -{ - unsigned char folderRecord[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, // folder hash - 0x01, 0x00, 0x00, 0x00, // file count - 0xDE, 0xAD, 0xBE, 0xEF, // offset to folder name - }; - // we'd usually have to sort folders be the hash value generated here - writeUlonglong(folderRecord, 0, genHash(folderName.c_str())); - writeUlong(folderRecord, 12, - 0x34 + m_TotalFileNameLength); // TODO: this should be calculated properly - - file.write(reinterpret_cast<char*>(folderRecord), sizeof(folderRecord)); -} - -void DummyBSA::writeFileRecord(QFile& file, const std::string& fileName) -{ - unsigned char fileRecord[] = { - 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, // file name hash - 0xDE, 0xAD, 0xBE, 0xEF, // size - 0xDE, 0xAD, 0xBE, 0xEF, // offset to file data - }; - - // we'd usually have to sort files by the value generated here - writeUlonglong(fileRecord, 0, genHash(fileName.c_str())); - writeUlong(fileRecord, 8, 0); - writeUlong( - fileRecord, 12, - 0x44 + static_cast<unsigned long>(fileName.length() + 1) + - 4); // after this record we expect the filename and 4 bytes of file size - - file.write(reinterpret_cast<char*>(fileRecord), sizeof(fileRecord)); -} - -void DummyBSA::writeFileRecordBlocks(QFile& file, const std::string& folderName) -{ - file.write(folderName.c_str(), folderName.length() + 1); - - writeFileRecord(file, m_FileName); -} - -void DummyBSA::write(const QString& fileName) -{ - QFile file(fileName); - file.open(QIODevice::WriteOnly); - - m_TotalFileNameLength = static_cast<unsigned long>(m_FileName.length() + 1); - - writeHeader(file); - writeFolderRecord(file, m_FolderName); - writeFileRecordBlocks(file, m_FolderName); - file.write(m_FileName.c_str(), m_FileName.length() + 1); - char fileSize[] = {0x00, 0x00, 0x00, 0x00}; - file.write(fileSize, sizeof(fileSize)); - file.close(); -} diff --git a/libs/game_gamebryo/src/gamebryo/dummybsa.h b/libs/game_gamebryo/src/gamebryo/dummybsa.h deleted file mode 100644 index 8ea071b..0000000 --- a/libs/game_gamebryo/src/gamebryo/dummybsa.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright (C) 2012 Sebastian Herbord. All rights reserved. - -This file is part of Mod Organizer. - -Mod Organizer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Mod Organizer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. -*/ - -#ifndef DUMMYBSA_H -#define DUMMYBSA_H - -#include <QFile> -#include <QString> - -/** - * @brief Class for creating a dummy bsa used for archive invalidation - **/ -class DummyBSA -{ - -public: - /** - * @brief constructor - * - **/ - DummyBSA(unsigned long bsaVersion); - - /** - * @brief write to the specified file - * - * @param fileName name of the file to write to - **/ - void write(const QString& fileName); - -private: - void writeHeader(QFile& file); - void writeFolderRecord(QFile& file, const std::string& folderName); - void writeFileRecord(QFile& file, const std::string& fileName); - void writeFileRecordBlocks(QFile& file, const std::string& folderName); - -private: - unsigned long m_Version; - std::string m_FolderName; - std::string m_FileName; - unsigned long m_TotalFileNameLength; -}; - -#endif // DUMMYBSA_H diff --git a/libs/game_gamebryo/src/gamebryo/game_gamebryo_en.ts b/libs/game_gamebryo/src/gamebryo/game_gamebryo_en.ts deleted file mode 100644 index f924131..0000000 --- a/libs/game_gamebryo/src/gamebryo/game_gamebryo_en.ts +++ /dev/null @@ -1,170 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!DOCTYPE TS> -<TS version="2.1" language="en_US"> -<context> - <name>GamebryoModDataContent</name> - <message> - <location filename="gamebryomoddatacontent.cpp" line="15"/> - <source>Plugins (ESP/ESM/ESL)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="16"/> - <source>Optional Plugins</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="17"/> - <source>Interface</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="18"/> - <source>Meshes</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="19"/> - <source>Bethesda Archive</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="20"/> - <source>Scripts (Papyrus)</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="21"/> - <source>Script Extender Plugin</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="22"/> - <source>Script Extender Files</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="23"/> - <source>SkyProc Patcher</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="24"/> - <source>Sound or Music</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="25"/> - <source>Textures</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="26"/> - <source>MCM Configuration</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="27"/> - <source>INI Files</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="28"/> - <source>FaceGen Data</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryomoddatacontent.cpp" line="29"/> - <source>ModGroup Files</source> - <translation type="unfinished"></translation> - </message> -</context> -<context> - <name>GamebryoSaveGameInfoWidget</name> - <message> - <location filename="gamebryosavegameinfowidget.ui" line="39"/> - <source>Save #</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegameinfowidget.ui" line="51"/> - <source>Character</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegameinfowidget.ui" line="63"/> - <source>Level</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegameinfowidget.ui" line="75"/> - <source>Location</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegameinfowidget.ui" line="87"/> - <source>Date</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegameinfowidget.cpp" line="78"/> - <source>Has Script Extender Data</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegameinfowidget.cpp" line="83"/> - <source>Missing ESPs</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegameinfowidget.cpp" line="116"/> - <location filename="gamebryosavegameinfowidget.cpp" line="154"/> - <location filename="gamebryosavegameinfowidget.cpp" line="193"/> - <source>None</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegameinfowidget.cpp" line="122"/> - <source>Missing ESHs</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegameinfowidget.cpp" line="161"/> - <source>Missing ESLs</source> - <translation type="unfinished"></translation> - </message> -</context> -<context> - <name>QObject</name> - <message> - <location filename="gamebryogameplugins.cpp" line="130"/> - <source>Some of your plugins have invalid names! These plugins can not be loaded by the game. Please see mo_interface.log for a list of affected plugins and rename them.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegame.cpp" line="48"/> - <source>%1, #%2, Level %3, %4</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegame.cpp" line="102"/> - <source>failed to open %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamebryosavegame.cpp" line="112"/> - <source>wrong file format - expected %1 got '%2' for %3</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamegamebryo.cpp" line="318"/> - <source>failed to query registry path (preflight): %1</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="gamegamebryo.cpp" line="326"/> - <source>failed to query registry path (read): %1</source> - <translation type="unfinished"></translation> - </message> -</context> -</TS> diff --git a/libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.cpp b/libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.cpp deleted file mode 100644 index 1b7144b..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.cpp +++ /dev/null @@ -1,133 +0,0 @@ -#include "gamebryobsainvalidation.h" - -#include "dummybsa.h" -#include "iplugingame.h" -#include "iprofile.h" -#include "registry.h" -#include <imoinfo.h> -#include <utility.h> - -#include <QDir> -#include <QStringList> - -#include <Windows.h> - -GamebryoBSAInvalidation::GamebryoBSAInvalidation(MOBase::DataArchives* dataArchives, - const QString& iniFilename, - MOBase::IPluginGame const* game) - : m_DataArchives(dataArchives), m_IniFileName(iniFilename), m_Game(game) -{} - -bool GamebryoBSAInvalidation::isInvalidationBSA(const QString& bsaName) -{ - static QStringList invalidation{invalidationBSAName()}; - - for (const QString& file : invalidation) { - if (file.compare(bsaName, Qt::CaseInsensitive) == 0) { - return true; - } - } - return false; -} - -void GamebryoBSAInvalidation::deactivate(MOBase::IProfile* profile) -{ - prepareProfile(profile); -} - -void GamebryoBSAInvalidation::activate(MOBase::IProfile* profile) -{ - prepareProfile(profile); -} - -bool GamebryoBSAInvalidation::prepareProfile(MOBase::IProfile* profile) -{ - bool dirty = false; - QString basePath = profile->localSettingsEnabled() - ? profile->absolutePath() - : m_Game->documentsDirectory().absolutePath(); - QString iniFilePath = basePath + "/" + m_IniFileName; - WCHAR setting[MAX_PATH]; - - // write bInvalidateOlderFiles = 1, if needed - if (!::GetPrivateProfileStringW(L"Archive", L"bInvalidateOlderFiles", L"0", setting, - MAX_PATH, iniFilePath.toStdWString().c_str()) || - wcstol(setting, nullptr, 10) != 1) { - dirty = true; - if (!MOBase::WriteRegistryValue(L"Archive", L"bInvalidateOlderFiles", L"1", - iniFilePath.toStdWString().c_str())) { - qWarning("failed to activate BSA invalidation in \"%s\"", - qUtf8Printable(m_IniFileName)); - } - } - - if (profile->invalidationActive(nullptr)) { - - // add the dummy bsa to the archive string, if needed - QStringList archives = m_DataArchives->archives(profile); - bool bsaInstalled = false; - for (const QString& archive : archives) { - if (isInvalidationBSA(archive)) { - bsaInstalled = true; - break; - } - } - if (!bsaInstalled) { - m_DataArchives->addArchive(profile, 0, invalidationBSAName()); - dirty = true; - } - - // create the dummy bsa if necessary - QString bsaFile = m_Game->dataDirectory().absoluteFilePath(invalidationBSAName()); - if (!QFile::exists(bsaFile)) { - DummyBSA bsa(bsaVersion()); - bsa.write(bsaFile); - dirty = true; - } - - // write SInvalidationFile = "", if needed - if (::GetPrivateProfileStringW(L"Archive", L"SInvalidationFile", - L"ArchiveInvalidation.txt", setting, MAX_PATH, - iniFilePath.toStdWString().c_str()) || - wcscmp(setting, L"") != 0) { - dirty = true; - if (!MOBase::WriteRegistryValue(L"Archive", L"SInvalidationFile", L"", - iniFilePath.toStdWString().c_str())) { - qWarning("failed to activate BSA invalidation in \"%s\"", - qUtf8Printable(m_IniFileName)); - } - } - } else { - - // remove the dummy bsa from the archive string, if needed - QStringList archivesBefore = m_DataArchives->archives(profile); - for (const QString& archive : archivesBefore) { - if (isInvalidationBSA(archive)) { - m_DataArchives->removeArchive(profile, archive); - dirty = true; - } - } - - // delete the dummy bsa, if needed - QString bsaFile = m_Game->dataDirectory().absoluteFilePath(invalidationBSAName()); - if (QFile::exists(bsaFile)) { - MOBase::shellDeleteQuiet(bsaFile); - dirty = true; - } - - // write SInvalidationFile = "ArchiveInvalidation.txt", if needed - if (!::GetPrivateProfileStringW(L"Archive", L"SInvalidationFile", L"", setting, - MAX_PATH, iniFilePath.toStdWString().c_str()) || - wcscmp(setting, L"ArchiveInvalidation.txt") != 0) { - dirty = true; - if (!MOBase::WriteRegistryValue(L"Archive", L"SInvalidationFile", - L"ArchiveInvalidation.txt", - iniFilePath.toStdWString().c_str())) { - qWarning("failed to activate BSA invalidation in \"%s\"", - qUtf8Printable(m_IniFileName)); - } - } - } - - return dirty; -} diff --git a/libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.h b/libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.h deleted file mode 100644 index efd3d7b..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryobsainvalidation.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef GAMEBRYOBSAINVALIDATION_H -#define GAMEBRYOBSAINVALIDATION_H - -#include <QString> -#include <bsainvalidation.h> -#include <dataarchives.h> -#include <memory> - -namespace MOBase -{ -class IPluginGame; -} - -class GamebryoBSAInvalidation : public MOBase::BSAInvalidation -{ -public: - GamebryoBSAInvalidation(MOBase::DataArchives* dataArchives, - const QString& iniFilename, MOBase::IPluginGame const* game); - - virtual bool isInvalidationBSA(const QString& bsaName) override; - virtual void deactivate(MOBase::IProfile* profile) override; - virtual void activate(MOBase::IProfile* profile) override; - virtual bool prepareProfile(MOBase::IProfile* profile) override; - -private: - virtual QString invalidationBSAName() const = 0; - virtual unsigned long - bsaVersion() const = 0; // 0x67 for oblivion, 0x68 for everything else - -private: - MOBase::DataArchives* m_DataArchives; - QString m_IniFileName; - MOBase::IPluginGame const* m_Game; -}; - -#endif // GAMEBRYOBSAINVALIDATION_H diff --git a/libs/game_gamebryo/src/gamebryo/gamebryodataarchives.cpp b/libs/game_gamebryo/src/gamebryo/gamebryodataarchives.cpp deleted file mode 100644 index 3dcba8a..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryodataarchives.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include "gamebryodataarchives.h" - -#include <Windows.h> - -#include <registry.h> -#include <utility.h> - -#include "gamegamebryo.h" - -GamebryoDataArchives::GamebryoDataArchives(const GameGamebryo* game) : m_Game{game} {} - -QDir GamebryoDataArchives::gameDirectory() const -{ - return QDir(m_Game->gameDirectory()).absolutePath(); -} - -QDir GamebryoDataArchives::localGameDirectory() const -{ - return QDir(m_Game->myGamesPath()).absolutePath(); -} - -QStringList GamebryoDataArchives::getArchivesFromKey(const QString& iniFile, - const QString& key, - const int size) const -{ - wchar_t* buffer = new wchar_t[size]; - QStringList result; - std::wstring iniFileW = QDir::toNativeSeparators(iniFile).toStdWString(); - - // epic ms fail: GetPrivateProfileString uses errno (for whatever reason) to signal a - // fail since the return value has a different meaning (number of bytes copied). - // HOWEVER, it will not set errno to 0 if NO error occured - errno = 0; - - if (::GetPrivateProfileStringW(L"Archive", key.toStdWString().c_str(), L"", buffer, - size, iniFileW.c_str()) != 0) { - result.append(QString::fromStdWString(buffer).split(',')); - } - - for (int i = 0; i < result.count(); ++i) { - result[i] = result[i].trimmed(); - } - delete[] buffer; - return result; -} - -void GamebryoDataArchives::setArchivesToKey(const QString& iniFile, const QString& key, - const QString& value) -{ - if (!MOBase::WriteRegistryValue(L"Archive", key.toStdWString().c_str(), - value.toStdWString().c_str(), - iniFile.toStdWString().c_str())) { - qWarning("failed to set archives in \"%s\"", qUtf8Printable(iniFile)); - } -} - -void GamebryoDataArchives::addArchive(MOBase::IProfile* profile, int index, - const QString& archiveName) -{ - QStringList current = archives(profile); - if (current.contains(archiveName, Qt::CaseInsensitive)) { - return; - } - - current.insert(index != INT_MAX ? index : current.size(), archiveName); - - writeArchiveList(profile, current); -} - -void GamebryoDataArchives::removeArchive(MOBase::IProfile* profile, - const QString& archiveName) -{ - QStringList current = archives(profile); - if (!current.contains(archiveName, Qt::CaseInsensitive)) { - return; - } - current.removeAll(archiveName); - - writeArchiveList(profile, current); -} diff --git a/libs/game_gamebryo/src/gamebryo/gamebryodataarchives.h b/libs/game_gamebryo/src/gamebryo/gamebryodataarchives.h deleted file mode 100644 index 13f4130..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryodataarchives.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef GAMEBRYODATAARCHIVES_H -#define GAMEBRYODATAARCHIVES_H - -#include <QDir> - -#include "dataarchives.h" - -class GameGamebryo; - -class GamebryoDataArchives : public MOBase::DataArchives -{ - -public: - GamebryoDataArchives(const GameGamebryo* game); - - virtual void addArchive(MOBase::IProfile* profile, int index, - const QString& archiveName) override; - virtual void removeArchive(MOBase::IProfile* profile, - const QString& archiveName) override; - -protected: - QDir gameDirectory() const; - QDir localGameDirectory() const; - - QStringList getArchivesFromKey(const QString& iniFile, const QString& key, - int size = 256) const; - void setArchivesToKey(const QString& iniFile, const QString& key, - const QString& value); - -private: - const GameGamebryo* m_Game; - - virtual void writeArchiveList(MOBase::IProfile* profile, - const QStringList& before) = 0; -}; - -#endif // GAMEBRYODATAARCHIVES_H diff --git a/libs/game_gamebryo/src/gamebryo/gamebryogameplugins.cpp b/libs/game_gamebryo/src/gamebryo/gamebryogameplugins.cpp deleted file mode 100644 index 83ad50f..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryogameplugins.cpp +++ /dev/null @@ -1,248 +0,0 @@ -#include "gamebryogameplugins.h" -#include <imodinterface.h> -#include <iplugingame.h> -#include <ipluginlist.h> -#include <report.h> -#include <safewritefile.h> -#include <scopeguard.h> -#include <utility.h> - -#include <QDateTime> -#include <QDir> -#include <QString> -#include <QStringEncoder> -#include <QStringList> - -using MOBase::IOrganizer; -using MOBase::IPluginList; -using MOBase::reportError; -using MOBase::SafeWriteFile; - -GamebryoGamePlugins::GamebryoGamePlugins(IOrganizer* organizer) : m_Organizer(organizer) -{} - -void GamebryoGamePlugins::writePluginLists(const IPluginList* pluginList) -{ - if (!m_LastRead.isValid()) { - // attempt to write uninitialized plugin lists - return; - } - - writePluginList(pluginList, m_Organizer->profile()->absolutePath() + "/plugins.txt"); - writeLoadOrderList(pluginList, - m_Organizer->profile()->absolutePath() + "/loadorder.txt"); - - m_LastRead = QDateTime::currentDateTime(); -} - -void GamebryoGamePlugins::readPluginLists(MOBase::IPluginList* pluginList) -{ - QString loadOrderPath = organizer()->profile()->absolutePath() + "/loadorder.txt"; - QString pluginsPath = organizer()->profile()->absolutePath() + "/plugins.txt"; - - bool loadOrderIsNew = !m_LastRead.isValid() || !QFileInfo(loadOrderPath).exists() || - QFileInfo(loadOrderPath).lastModified() > m_LastRead; - bool pluginsIsNew = - !m_LastRead.isValid() || QFileInfo(pluginsPath).lastModified() > m_LastRead; - - if (loadOrderIsNew || !pluginsIsNew) { - // read both files if they are both new or both older than the last read - QStringList loadOrder = readLoadOrderList(pluginList, loadOrderPath); - pluginList->setLoadOrder(loadOrder); - readPluginList(pluginList); - } else { - // If the plugins is new but not loadorder, we must reparse the load order from the - // plugin files - QStringList loadOrder = readPluginList(pluginList); - pluginList->setLoadOrder(loadOrder); - } - - m_LastRead = QDateTime::currentDateTime(); -} - -QStringList GamebryoGamePlugins::getLoadOrder() -{ - QString loadOrderPath = organizer()->profile()->absolutePath() + "/loadorder.txt"; - QString pluginsPath = organizer()->profile()->absolutePath() + "/plugins.txt"; - - bool loadOrderIsNew = !m_LastRead.isValid() || !QFileInfo(loadOrderPath).exists() || - QFileInfo(loadOrderPath).lastModified() > m_LastRead; - bool pluginsIsNew = - !m_LastRead.isValid() || QFileInfo(pluginsPath).lastModified() > m_LastRead; - - if (loadOrderIsNew || !pluginsIsNew) { - return readLoadOrderList(m_Organizer->pluginList(), loadOrderPath); - } else { - return readPluginList(m_Organizer->pluginList()); - } -} - -void GamebryoGamePlugins::writePluginList(const MOBase::IPluginList* pluginList, - const QString& filePath) -{ - return writeList(pluginList, filePath, false); -} - -void GamebryoGamePlugins::writeLoadOrderList(const MOBase::IPluginList* pluginList, - const QString& filePath) -{ - return writeList(pluginList, filePath, true); -} - -void GamebryoGamePlugins::writeList(const IPluginList* pluginList, - const QString& filePath, bool loadOrder) -{ - SafeWriteFile file(filePath); - - QStringEncoder encoder = loadOrder - ? QStringEncoder(QStringConverter::Encoding::Utf8) - : QStringEncoder(QStringConverter::Encoding::System); - - file->resize(0); - - file->write( - encoder.encode("# This file was automatically generated by Mod Organizer.\r\n")); - - bool invalidFileNames = false; - int writtenCount = 0; - - QStringList plugins = pluginList->pluginNames(); - std::sort(plugins.begin(), plugins.end(), - [pluginList](const QString& lhs, const QString& rhs) { - return pluginList->priority(lhs) < pluginList->priority(rhs); - }); - - for (const QString& pluginName : plugins) { - if (loadOrder || (pluginList->state(pluginName) == IPluginList::STATE_ACTIVE)) { - auto result = encoder.encode(pluginName); - if (encoder.hasError()) { - invalidFileNames = true; - qCritical("invalid plugin name %s", qUtf8Printable(pluginName)); - } else { - file->write(result); - } - file->write("\r\n"); - ++writtenCount; - } - } - - if (invalidFileNames) { - reportError(QObject::tr("Some of your plugins have invalid names! These " - "plugins can not be loaded by the game. Please see " - "mo_interface.log for a list of affected plugins " - "and rename them.")); - } - - if (writtenCount == 0) { - qWarning("plugin list would be empty, this is almost certainly wrong. Not " - "saving."); - } else { - file->commit(); - } -} - -QStringList GamebryoGamePlugins::readLoadOrderList(MOBase::IPluginList* pluginList, - const QString& filePath) -{ - QStringList pluginNames = organizer()->managedGame()->primaryPlugins(); - - std::set<QString> pluginLookup; - for (auto&& name : pluginNames) { - pluginLookup.insert(name.toLower()); - } - - const auto b = MOBase::forEachLineInFile(filePath, [&](QString s) { - if (!pluginLookup.contains(s.toLower())) { - pluginLookup.insert(s); - pluginNames.push_back(std::move(s)); - } - }); - - if (!b) { - return readPluginList(pluginList); - } - - return pluginNames; -} - -QStringList GamebryoGamePlugins::readPluginList(MOBase::IPluginList* pluginList) -{ - QStringList primary = organizer()->managedGame()->primaryPlugins(); - for (const QString& pluginName : primary) { - if (pluginList->state(pluginName) != IPluginList::STATE_MISSING) { - pluginList->setState(pluginName, IPluginList::STATE_ACTIVE); - } - } - QStringList plugins = pluginList->pluginNames(); - QStringList pluginsClone(plugins); - // Do not sort the primary plugins. Their load order should be locked as defined in - // "primaryPlugins". - for (const auto& plugin : pluginsClone) { - if (primary.contains(plugin, Qt::CaseInsensitive)) - plugins.removeAll(plugin); - } - - // Always use filetime loadorder to get the actual load order - std::sort(plugins.begin(), plugins.end(), - [&](const QString& lhs, const QString& rhs) { - MOBase::IModInterface* lhm = - organizer()->modList()->getMod(pluginList->origin(lhs)); - MOBase::IModInterface* rhm = - organizer()->modList()->getMod(pluginList->origin(rhs)); - QDir lhd = organizer()->managedGame()->dataDirectory(); - QDir rhd = organizer()->managedGame()->dataDirectory(); - if (lhm != nullptr) - lhd = lhm->absolutePath(); - if (rhm != nullptr) - rhd = rhm->absolutePath(); - QString lhp = lhd.absoluteFilePath(lhs); - QString rhp = rhd.absoluteFilePath(rhs); - return QFileInfo(lhp).lastModified() < QFileInfo(rhp).lastModified(); - }); - - // Determine plugin active state by the plugins.txt file. - bool pluginsTxtExists = true; - QString filePath = organizer()->profile()->absolutePath() + "/plugins.txt"; - QFile file(filePath); - if (!file.open(QIODevice::ReadOnly)) { - pluginsTxtExists = false; - } - ON_BLOCK_EXIT([&]() { - file.close(); - }); - - if (file.size() == 0) { - // MO stores at least a header in the file. if it's completely empty the - // file is broken - pluginsTxtExists = false; - } - - QStringList activePlugins; - QStringList inactivePlugins; - if (pluginsTxtExists) { - while (!file.atEnd()) { - QByteArray line = file.readLine(); - QString pluginName; - if ((line.size() > 0) && (line.at(0) != '#')) { - QStringEncoder encoder(QStringConverter::Encoding::System); - pluginName = encoder.encode(line.trimmed().constData()); - } - if (pluginName.size() > 0) { - pluginList->setState(pluginName, IPluginList::STATE_ACTIVE); - activePlugins.push_back(pluginName); - } - } - - for (const auto& pluginName : plugins) { - if (!activePlugins.contains(pluginName, Qt::CaseInsensitive)) { - pluginList->setState(pluginName, IPluginList::STATE_INACTIVE); - } - } - } else { - for (const QString& pluginName : plugins) { - pluginList->setState(pluginName, IPluginList::STATE_INACTIVE); - } - } - - return primary + plugins; -} diff --git a/libs/game_gamebryo/src/gamebryo/gamebryogameplugins.h b/libs/game_gamebryo/src/gamebryo/gamebryogameplugins.h deleted file mode 100644 index ca70c75..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryogameplugins.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef GAMEBRYOGAMEPLUGINS_H -#define GAMEBRYOGAMEPLUGINS_H - -#include <QDateTime> -#include <QStringList> -#include <gameplugins.h> -#include <imoinfo.h> - -class GamebryoGamePlugins : public MOBase::GamePlugins -{ -public: - GamebryoGamePlugins(MOBase::IOrganizer* organizer); - - virtual void writePluginLists(const MOBase::IPluginList* pluginList) override; - virtual void readPluginLists(MOBase::IPluginList* pluginList) override; - virtual QStringList getLoadOrder() override; - -protected: - MOBase::IOrganizer* organizer() const { return m_Organizer; } - - virtual void writePluginList(const MOBase::IPluginList* pluginList, - const QString& filePath); - virtual void writeLoadOrderList(const MOBase::IPluginList* pluginList, - const QString& filePath); - virtual QStringList readLoadOrderList(MOBase::IPluginList* pluginList, - const QString& filePath); - virtual QStringList readPluginList(MOBase::IPluginList* pluginList); - -protected: - MOBase::IOrganizer* m_Organizer; - QDateTime m_LastRead; - -private: - void writeList(const MOBase::IPluginList* pluginList, const QString& filePath, - bool loadOrder); -}; - -#endif // GAMEBRYOGAMEPLUGINS_H diff --git a/libs/game_gamebryo/src/gamebryo/gamebryolocalsavegames.cpp b/libs/game_gamebryo/src/gamebryo/gamebryolocalsavegames.cpp deleted file mode 100644 index d0cc2ef..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryolocalsavegames.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 3 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "gamebryolocalsavegames.h" -#include "registry.h" -#include <QtDebug> -#include <iprofile.h> -#include <stddef.h> -#include <string> -#include <windows.h> - -#include "gamegamebryo.h" - -GamebryoLocalSavegames::GamebryoLocalSavegames(const GameGamebryo* game, - const QString& iniFileName) - : m_Game{game}, m_IniFileName(iniFileName) -{} - -MappingType GamebryoLocalSavegames::mappings(const QDir& profileSaveDir) const -{ - return {{profileSaveDir.absolutePath(), localSavesDirectory().absolutePath(), true, - true}}; -} - -QString GamebryoLocalSavegames::localSavesDummy() const -{ - return "__MO_Saves\\"; -} - -QDir GamebryoLocalSavegames::localSavesDirectory() const -{ - QString dummy = localSavesDummy(); - dummy.replace("\\", "/"); - return QDir(m_Game->myGamesPath()).absoluteFilePath(dummy); -} - -QDir GamebryoLocalSavegames::localGameDirectory() const -{ - return QDir(m_Game->myGamesPath()).absolutePath(); -} - -bool GamebryoLocalSavegames::prepareProfile(MOBase::IProfile* profile) -{ - bool enable = profile->localSavesEnabled(); - - QString basePath = profile->localSettingsEnabled() - ? profile->absolutePath() - : localGameDirectory().absolutePath(); - QString iniFilePath = basePath + "/" + m_IniFileName; - QString saveIni = profile->absolutePath() + "/" + "savepath.ini"; - - // Get the current sLocalSavePath - WCHAR currentPath[MAX_PATH]; - GetPrivateProfileStringW(L"General", L"sLocalSavePath", L"SKIP_ME", currentPath, - MAX_PATH, iniFilePath.toStdWString().c_str()); - bool alreadyEnabled = - wcscmp(currentPath, localSavesDummy().toStdWString().c_str()) == 0; - - // Get the current bUseMyGamesDirectory - WCHAR currentMyGames[MAX_PATH]; - GetPrivateProfileStringW(L"General", L"bUseMyGamesDirectory", L"SKIP_ME", - currentMyGames, MAX_PATH, - iniFilePath.toStdWString().c_str()); - - // Create the __MO_Saves directory if local saves are enabled and it doesn't exist - if (enable) { - QDir saves = localSavesDirectory(); - if (!saves.exists()) { - saves.mkdir("."); - } - } - - // Set the path to __MO_Saves if it's not already - if (enable && !alreadyEnabled) { - // If the path is not blank, save it to savepath.ini - if (wcscmp(currentPath, L"SKIP_ME") != 0) { - MOBase::WriteRegistryValue(L"General", L"sLocalSavePath", currentPath, - saveIni.toStdWString().c_str()); - } - if (wcscmp(currentMyGames, L"SKIP_ME") != 0) { - MOBase::WriteRegistryValue(L"General", L"bUseMyGamesDirectory", currentMyGames, - saveIni.toStdWString().c_str()); - } - MOBase::WriteRegistryValue(L"General", L"sLocalSavePath", - localSavesDummy().toStdWString().c_str(), - iniFilePath.toStdWString().c_str()); - MOBase::WriteRegistryValue(L"General", L"bUseMyGamesDirectory", L"1", - iniFilePath.toStdWString().c_str()); - } - - // Get rid of the local saves setting if it's still there - if (!enable && alreadyEnabled) { - // If savepath.ini exists, use it and delete it - if (QFile::exists(saveIni)) { - WCHAR savedPath[MAX_PATH]; - WCHAR savedMyGames[MAX_PATH]; - GetPrivateProfileStringW(L"General", L"sLocalSavePath", L"DELETE_ME", savedPath, - MAX_PATH, saveIni.toStdWString().c_str()); - GetPrivateProfileStringW(L"General", L"bUseMyGamesDirectory", L"DELETE_ME", - savedMyGames, MAX_PATH, saveIni.toStdWString().c_str()); - if (wcscmp(savedPath, L"DELETE_ME") != 0) { - MOBase::WriteRegistryValue(L"General", L"sLocalSavePath", savedPath, - iniFilePath.toStdWString().c_str()); - } else { - MOBase::WriteRegistryValue(L"General", L"sLocalSavePath", NULL, - iniFilePath.toStdWString().c_str()); - } - if (wcscmp(savedMyGames, L"DELETE_ME") != 0) { - MOBase::WriteRegistryValue(L"General", L"bUseMyGamesDirectory", savedMyGames, - iniFilePath.toStdWString().c_str()); - } else { - MOBase::WriteRegistryValue(L"General", L"bUseMyGamesDirectory", NULL, - iniFilePath.toStdWString().c_str()); - } - QFile::remove(saveIni); - } - // Otherwise just delete the setting - else { - MOBase::WriteRegistryValue(L"General", L"sLocalSavePath", NULL, - iniFilePath.toStdWString().c_str()); - MOBase::WriteRegistryValue(L"General", L"bUseMyGamesDirectory", NULL, - iniFilePath.toStdWString().c_str()); - } - } - - return enable != alreadyEnabled; -} diff --git a/libs/game_gamebryo/src/gamebryo/gamebryolocalsavegames.h b/libs/game_gamebryo/src/gamebryo/gamebryolocalsavegames.h deleted file mode 100644 index e5f2a92..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryolocalsavegames.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright (C) 2015 Sebastian Herbord. All rights reserved. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 3 of the License, or (at your option) any later version. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef GAMEBRYOLOCALSAVEGAMES_H -#define GAMEBRYOLOCALSAVEGAMES_H - -#include <localsavegames.h> - -#include <QDir> -#include <QString> - -class GameGamebryo; - -class GamebryoLocalSavegames : public MOBase::LocalSavegames -{ - -public: - GamebryoLocalSavegames(const GameGamebryo* game, const QString& iniFileName); - - virtual MappingType mappings(const QDir& profileSaveDir) const override; - virtual bool prepareProfile(MOBase::IProfile* profile) override; - -protected: - // return the path from the local game directory to the local saves folder - // - // this is virtual so game plugins for complete game overhauld (Enderal, Nehrim, etc.) - // can override it properly - // - virtual QString localSavesDummy() const; - - QDir localSavesDirectory() const; - QDir localGameDirectory() const; - -private: - const GameGamebryo* m_Game; - QString m_IniFileName; -}; - -#endif // GAMEBRYOLOCALSAVEGAMES_H diff --git a/libs/game_gamebryo/src/gamebryo/gamebryomoddatachecker.cpp b/libs/game_gamebryo/src/gamebryo/gamebryomoddatachecker.cpp deleted file mode 100644 index b5bace6..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryomoddatachecker.cpp +++ /dev/null @@ -1,76 +0,0 @@ -#include <ifiletree.h> - -#include "gamebryomoddatachecker.h" - -/** - * @return the list of possible folder names in data. - */ -auto GamebryoModDataChecker::possibleFolderNames() const -> const FileNameSet& -{ - static FileNameSet result{"fonts", - "interface", - "menus", - "meshes", - "music", - "scripts", - "shaders", - "sound", - "strings", - "textures", - "trees", - "video", - "facegen", - "materials", - "skse", - "obse", - "mwse", - "nvse", - "fose", - "f4se", - "distantlod", - "asi", - "SkyProc Patchers", - "Tools", - "MCM", - "icons", - "bookart", - "distantland", - "mits", - "splash", - "dllplugins", - "CalienteTools", - "NetScriptFramework", - "shadersfx"}; - return result; -} - -/** - * @return the extensions of possible files in data. - */ -auto GamebryoModDataChecker::possibleFileExtensions() const -> const FileNameSet& -{ - static FileNameSet result{"esp", "esm", "esl", "bsa", "ba2", "modgroups", "ini"}; - return result; -} - -GamebryoModDataChecker::GamebryoModDataChecker(const GameGamebryo* game) : m_Game(game) -{} - -GamebryoModDataChecker::CheckReturn GamebryoModDataChecker::dataLooksValid( - std::shared_ptr<const MOBase::IFileTree> fileTree) const -{ - auto& folders = possibleFolderNames(); - auto& suffixes = possibleFileExtensions(); - for (auto entry : *fileTree) { - if (entry->isDir()) { - if (folders.count(entry->name()) > 0) { - return CheckReturn::VALID; - } - } else { - if (suffixes.count(entry->suffix()) > 0) { - return CheckReturn::VALID; - } - } - } - return CheckReturn::INVALID; -} diff --git a/libs/game_gamebryo/src/gamebryo/gamebryomoddatachecker.h b/libs/game_gamebryo/src/gamebryo/gamebryomoddatachecker.h deleted file mode 100644 index e0b0733..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryomoddatachecker.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef GAMEBRYO_MODATACHECKER_H -#define GAMEBRYO_MODATACHECKER_H - -#include <ifiletree.h> -#include <moddatachecker.h> - -class GameGamebryo; - -/** - * @brief ModDataChecker for GameBryo games that look at folder and files in the "data" - * directory. - * - * The default implementation is game-agnostic and uses the list of folders and file - * extensions that were used before the ModDataChecker feature was added. It is possible - * to inherit the class to provide custom list of folders or filenames. - */ -class GamebryoModDataChecker : public MOBase::ModDataChecker -{ -public: - /** - * @brief Construct a new mod-data checker for GameBryo games. - */ - GamebryoModDataChecker(const GameGamebryo* game); - - virtual CheckReturn - dataLooksValid(std::shared_ptr<const MOBase::IFileTree> fileTree) const override; - -protected: - GameGamebryo const* const m_Game; - - using FileNameSet = std::set<QString, MOBase::FileNameComparator>; - - const GameGamebryo* game() const { return m_Game; } - - /** - * @return the list of possible folder names in data. - */ - virtual const FileNameSet& possibleFolderNames() const; - - /** - * @return the extensions of possible files in data. - */ - virtual const FileNameSet& possibleFileExtensions() const; -}; - -#endif // GAMEBRYO_MODATACHECKER_H diff --git a/libs/game_gamebryo/src/gamebryo/gamebryomoddatacontent.cpp b/libs/game_gamebryo/src/gamebryo/gamebryomoddatacontent.cpp deleted file mode 100644 index 85b66b0..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryomoddatacontent.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "gamebryomoddatacontent.h" - -#include <igamefeatures.h> -#include <scriptextender.h> - -GamebryoModDataContent::GamebryoModDataContent( - MOBase::IGameFeatures const* gameFeatures) - : m_GameFeatures(gameFeatures), m_Enabled(CONTENT_MODGROUP + 1, true) -{} - -std::vector<GamebryoModDataContent::Content> -GamebryoModDataContent::getAllContents() const -{ - static std::vector<Content> GAMEBRYO_CONTENTS{ - {CONTENT_PLUGIN, QT_TR_NOOP("Plugins (ESP/ESM/ESL)"), ":/MO/gui/content/plugin"}, - {CONTENT_OPTIONAL, QT_TR_NOOP("Optional Plugins"), "", true}, - {CONTENT_INTERFACE, QT_TR_NOOP("Interface"), ":/MO/gui/content/interface"}, - {CONTENT_MESH, QT_TR_NOOP("Meshes"), ":/MO/gui/content/mesh"}, - {CONTENT_BSA, QT_TR_NOOP("Bethesda Archive"), ":/MO/gui/content/bsa"}, - {CONTENT_SCRIPT, QT_TR_NOOP("Scripts (Papyrus)"), ":/MO/gui/content/script"}, - {CONTENT_SKSE, QT_TR_NOOP("Script Extender Plugin"), ":/MO/gui/content/skse"}, - {CONTENT_SKSE_FILES, QT_TR_NOOP("Script Extender Files"), "", true}, - {CONTENT_SKYPROC, QT_TR_NOOP("SkyProc Patcher"), ":/MO/gui/content/skyproc"}, - {CONTENT_SOUND, QT_TR_NOOP("Sound or Music"), ":/MO/gui/content/sound"}, - {CONTENT_TEXTURE, QT_TR_NOOP("Textures"), ":/MO/gui/content/texture"}, - {CONTENT_MCM, QT_TR_NOOP("MCM Configuration"), ":/MO/gui/content/menu"}, - {CONTENT_INI, QT_TR_NOOP("INI Files"), ":/MO/gui/content/inifile"}, - {CONTENT_FACEGEN, QT_TR_NOOP("FaceGen Data"), ":/MO/gui/content/facegen"}, - {CONTENT_MODGROUP, QT_TR_NOOP("ModGroup Files"), ":/MO/gui/content/modgroup"}}; - - // Copy the list of enabled contents: - std::vector<Content> contents; - std::copy_if(std::begin(GAMEBRYO_CONTENTS), std::end(GAMEBRYO_CONTENTS), - std::back_inserter(contents), [this](auto e) { - return m_Enabled[e.id()]; - }); - return contents; -} - -std::vector<int> GamebryoModDataContent::getContentsFor( - std::shared_ptr<const MOBase::IFileTree> fileTree) const -{ - std::vector<int> contents; - - for (auto e : *fileTree) { - if (e->isFile()) { - auto suffix = e->suffix().toLower(); - if (m_Enabled[CONTENT_PLUGIN] && - (suffix == "esp" || suffix == "esm" || suffix == "esl")) { - contents.push_back(CONTENT_PLUGIN); - } else if (m_Enabled[CONTENT_BSA] && (suffix == "bsa" || suffix == "ba2")) { - contents.push_back(CONTENT_BSA); - } else if (m_Enabled[CONTENT_INI] && suffix == "ini" && - e->compare("meta.ini") != 0) { - contents.push_back(CONTENT_INI); - } else if (m_Enabled[CONTENT_MODGROUP] && suffix == "modgroups") { - contents.push_back(CONTENT_MODGROUP); - } - } else { - if (m_Enabled[CONTENT_TEXTURE] && - (e->compare("textures") == 0 || e->compare("icons") == 0 || - e->compare("bookart") == 0)) { - contents.push_back(CONTENT_TEXTURE); - } else if (m_Enabled[CONTENT_MESH] && e->compare("meshes") == 0) { - contents.push_back(CONTENT_MESH); - } else if (m_Enabled[CONTENT_INTERFACE] && - (e->compare("interface") == 0 || e->compare("menus") == 0)) { - contents.push_back(CONTENT_INTERFACE); - } else if (m_Enabled[CONTENT_SOUND] && e->compare("music") == 0 || - e->compare("sound") == 0) { - contents.push_back(CONTENT_SOUND); - } else if (m_Enabled[CONTENT_SCRIPT] && e->compare("scripts") == 0) { - contents.push_back(CONTENT_SCRIPT); - } else if (m_Enabled[CONTENT_SKYPROC] && e->compare("SkyProc Patchers") == 0) { - contents.push_back(CONTENT_SKYPROC); - } else if (m_Enabled[CONTENT_MCM] && e->compare("MCM") == 0) { - contents.push_back(CONTENT_MCM); - } else if (m_Enabled[CONTENT_OPTIONAL] && e->compare("Optional") == 0 && - e->astree()->size() > 0) { - contents.push_back(CONTENT_OPTIONAL); - } - } - } - - if (m_Enabled[CONTENT_FACEGEN]) { - auto e1 = fileTree->findDirectory("meshes/actors/character/facegendata"); - if (e1) { - contents.push_back(CONTENT_FACEGEN); - } else { - auto e2 = fileTree->findDirectory("textures/actors/character/facegendata"); - if (e2) { - contents.push_back(CONTENT_FACEGEN); - } - } - } - - auto extender = m_GameFeatures->gameFeature<MOBase::ScriptExtender>(); - if (extender != nullptr) { - auto e = fileTree->findDirectory(extender->PluginPath()); - if (e) { - if (m_Enabled[CONTENT_SKSE_FILES]) { - contents.push_back(CONTENT_SKSE_FILES); - } - if (m_Enabled[CONTENT_SKSE]) { - for (auto f : *e) { - if (f->hasSuffix("dll")) { - contents.push_back(CONTENT_SKSE); - break; - } - } - } - } - } - - return contents; -} diff --git a/libs/game_gamebryo/src/gamebryo/gamebryomoddatacontent.h b/libs/game_gamebryo/src/gamebryo/gamebryomoddatacontent.h deleted file mode 100644 index be02331..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryomoddatacontent.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef GAMEBRYO_MODDATACONTENT_H -#define GAMEBRYO_MODDATACONTENT_H - -#include <ifiletree.h> -#include <moddatacontent.h> - -namespace MOBase -{ -class IGameFeatures; -} - -/** - * @brief ModDataContent for GameBryo games. - * - */ -class GamebryoModDataContent : public MOBase::ModDataContent -{ -protected: - /** - * Note: These are used to index m_Enabled so should have standard - * enum values, not custom ones. - */ - enum EContent - { - CONTENT_PLUGIN, - CONTENT_OPTIONAL, - CONTENT_TEXTURE, - CONTENT_MESH, - CONTENT_BSA, - CONTENT_INTERFACE, - CONTENT_SOUND, - CONTENT_SCRIPT, - CONTENT_SKSE, - CONTENT_SKSE_FILES, - CONTENT_SKYPROC, - CONTENT_MCM, - CONTENT_INI, - CONTENT_FACEGEN, - CONTENT_MODGROUP - }; - - /** - * This is the first value that can be used for game-specific contents. - */ - constexpr static auto CONTENT_NEXT_VALUE = CONTENT_MODGROUP + 1; - -public: - /** - * - */ - GamebryoModDataContent(const MOBase::IGameFeatures* gameFeatures); - - /** - * @return the list of all possible contents for the corresponding game. - */ - virtual std::vector<Content> getAllContents() const override; - - /** - * @brief Retrieve the list of contents in the given tree. - * - * @param fileTree The tree corresponding to the mod to retrieve contents for. - * - * @return the IDs of the content in the given tree. - */ - virtual std::vector<int> - getContentsFor(std::shared_ptr<const MOBase::IFileTree> fileTree) const override; - -protected: - MOBase::IGameFeatures const* const m_GameFeatures; - - // List of enabled contents: - std::vector<bool> m_Enabled; -}; - -#endif // GAMEBRYO_MODDATACONTENT_H diff --git a/libs/game_gamebryo/src/gamebryo/gamebryosavegame.cpp b/libs/game_gamebryo/src/gamebryo/gamebryosavegame.cpp deleted file mode 100644 index 596b19b..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryosavegame.cpp +++ /dev/null @@ -1,606 +0,0 @@ -#include "gamebryosavegame.h" - -#include "iplugingame.h" -#include "log.h" -#include "scriptextender.h" - -#include <QDate> -#include <QFile> -#include <QFileInfo> -#include <QScopedArrayPointer> -#include <QTime> - -#include <Windows.h> -#include <lz4.h> -#include <zlib.h> - -#include <stdexcept> -#include <vector> - -#include "gamegamebryo.h" -#include "imoinfo.h" - -#define CHUNK 16384 - -GamebryoSaveGame::GamebryoSaveGame(QString const& file, GameGamebryo const* game, - bool const lightEnabled, bool const mediumEnabled) - : m_FileName(file), m_CreationTime(QFileInfo(file).lastModified()), m_Game(game), - m_MediumEnabled(mediumEnabled), m_LightEnabled(lightEnabled), - m_DataFields([this]() { - return fetchDataFields(); - }) -{} - -GamebryoSaveGame::~GamebryoSaveGame() {} - -QString GamebryoSaveGame::getFilepath() const -{ - return m_FileName; -} - -QDateTime GamebryoSaveGame::getCreationTime() const -{ - return m_CreationTime; -} - -QString GamebryoSaveGame::getName() const -{ - return QObject::tr("%1, #%2, Level %3, %4") - .arg(m_PCName) - .arg(m_SaveNumber) - .arg(m_PCLevel) - .arg(m_PCLocation); -} - -QString GamebryoSaveGame::getSaveGroupIdentifier() const -{ - return m_PCName; -} - -QStringList GamebryoSaveGame::allFiles() const -{ - // This returns all valid files associated with this game - QStringList res = {m_FileName}; - auto e = m_Game->m_Organizer->gameFeatures()->gameFeature<MOBase::ScriptExtender>(); - if (e != nullptr) { - QFileInfo file(m_FileName); - QFileInfo SEfile(file.absolutePath() + "/" + file.completeBaseName() + "." + - m_Game->savegameSEExtension()); - if (SEfile.exists()) { - res.push_back(SEfile.absoluteFilePath()); - } - } - return res; -} - -bool GamebryoSaveGame::hasScriptExtenderFile() const -{ - QFileInfo file(m_FileName); - QFileInfo SEfile(file.absolutePath() + "/" + file.completeBaseName() + "." + - m_Game->savegameSEExtension()); - return SEfile.exists(); -} - -void GamebryoSaveGame::setCreationTime(_SYSTEMTIME const& ctime) -{ - QDate date; - date.setDate(ctime.wYear, ctime.wMonth, ctime.wDay); - QTime time; - time.setHMS(ctime.wHour, ctime.wMinute, ctime.wSecond, ctime.wMilliseconds); - - m_CreationTime = QDateTime(date, time, Qt::UTC); -} - -GamebryoSaveGame::FileWrapper::FileWrapper(QString const& filepath, - QString const& expected) - : m_File(filepath), m_HasFieldMarkers(false), - m_PluginString(StringType::TYPE_WSTRING), - m_PluginStringFormat(StringFormat::UTF8), m_NextChunk(0) -{ - if (!m_File.open(QIODevice::ReadOnly)) { - throw std::runtime_error( - QObject::tr("failed to open %1").arg(filepath).toUtf8().constData()); - } - - std::vector<char> fileID(expected.length() + 1); - m_File.read(fileID.data(), expected.length()); - fileID[expected.length()] = '\0'; - - QString id(fileID.data()); - if (expected != id) { - throw std::runtime_error( - QObject::tr("wrong file format - expected %1 got \'%2\' for %3") - .arg(expected) - .arg(id) - .arg(filepath) - .toUtf8() - .constData()); - } -} - -void GamebryoSaveGame::FileWrapper::setHasFieldMarkers(bool state) -{ - m_HasFieldMarkers = state; -} - -void GamebryoSaveGame::FileWrapper::setPluginString(StringType type) -{ - m_PluginString = type; -} - -void GamebryoSaveGame::FileWrapper::setPluginStringFormat(StringFormat type) -{ - m_PluginStringFormat = type; -} - -void GamebryoSaveGame::FileWrapper::readQDataStream(QDataStream& data, void* buff, - std::size_t length) -{ - int read = data.readRawData(static_cast<char*>(buff), static_cast<int>(length)); - bool result = true; - if (read != length && m_CompressionType == 1) { - bool result = readNextChunk(); - if (result) { - read += data.readRawData(static_cast<char*>(buff) + read, - static_cast<int>(length - read)); - } - } - if (read != length || !result) { - throw std::runtime_error("unexpected end of file"); - } -} - -template <typename T> -void GamebryoSaveGame::FileWrapper::readQDataStream(QDataStream& data, T& value) -{ - static_assert(std::is_trivial_v<T> && std::is_standard_layout_v<T>); - readQDataStream(data, &value, sizeof(T)); -} - -void GamebryoSaveGame::FileWrapper::skipQDataStream(QDataStream& data, - std::size_t length) -{ - int skip = data.skipRawData(static_cast<int>(length)); - bool result = true; - if (skip != length && m_CompressionType == 1) { - result = readNextChunk(); - if (result) { - skip += data.skipRawData(static_cast<int>(length - skip)); - } - } - if (skip != length || !result) { - throw std::runtime_error("unexpected end of file"); - } -} - -template <> -void GamebryoSaveGame::FileWrapper::read<QString>(QString& value) -{ - if (m_CompressionType == 0) { - unsigned short length; - if (m_PluginString == StringType::TYPE_BSTRING || - m_PluginString == StringType::TYPE_BZSTRING) { - unsigned char len; - read(len); - length = m_PluginString == StringType::TYPE_BZSTRING ? len + 1 : len; - } else { - read(length); - } - - if (m_HasFieldMarkers) { - skip<char>(); - } - - QByteArray buffer; - buffer.resize(length); - - read(buffer.data(), - m_PluginString == StringType::TYPE_BZSTRING ? length - 1 : length); - - if (m_PluginString == StringType::TYPE_BZSTRING) - buffer[length - 1] = '\0'; - - if (m_HasFieldMarkers) { - skip<char>(); - } - - if (m_PluginStringFormat == StringFormat::UTF8) - value = QString::fromUtf8(buffer.constData()); - else - value = QString::fromLocal8Bit(buffer.constData()); - } else if (m_CompressionType == 1 || m_CompressionType == 2) { - unsigned short length; - if (m_PluginString == StringType::TYPE_BSTRING || - m_PluginString == StringType::TYPE_BZSTRING) { - unsigned char len; - readQDataStream(*m_Data, len); - length = m_PluginString == StringType::TYPE_BZSTRING ? len + 1 : len; - } else { - readQDataStream(*m_Data, length); - } - - if (m_HasFieldMarkers) { - skip<char>(); - } - - QByteArray buffer; - buffer.resize(length); - - readQDataStream(*m_Data, buffer.data(), - m_PluginString == StringType::TYPE_BZSTRING ? length - 1 : length); - - if (m_PluginString == StringType::TYPE_BZSTRING) - buffer[length - 1] = '\0'; - - if (m_HasFieldMarkers) { - m_Data->skipRawData(1); - } - - if (m_PluginStringFormat == StringFormat::UTF8) - value = QString::fromUtf8(buffer.constData()); - else - value = QString::fromLocal8Bit(buffer.constData()); - } else { - MOBase::log::warn("Please create an issue on the MO github labeled \"Found unknown " - "Compressed\" with your savefile attached"); - } -} - -void GamebryoSaveGame::FileWrapper::read(void* buff, std::size_t length) -{ - int read = m_File.read(static_cast<char*>(buff), length); - if (read != length) { - throw std::runtime_error("unexpected end of file"); - } -} - -QImage GamebryoSaveGame::FileWrapper::readImage(int scale, bool alpha) -{ - unsigned long width; - read(width); - unsigned long height; - read(height); - return readImage(width, height, scale, alpha); -} - -QImage GamebryoSaveGame::FileWrapper::readImage(unsigned long width, - unsigned long height, int scale, - bool alpha) -{ - int bpp = alpha ? 4 : 3; - QScopedArrayPointer<unsigned char> buffer(new unsigned char[width * height * bpp]); - read(buffer.data(), width * height * bpp); - QImage image(buffer.data(), width, height, - alpha ? QImage::Format_RGBA8888_Premultiplied : QImage::Format_RGB888); - - // We need to copy the image here because QImage does not make a copy of the - // buffer when constructed. - if (scale != 0) { - return image.copy().scaledToWidth(scale); - } else { - return image.copy(); - } -} - -void GamebryoSaveGame::FileWrapper::setCompressionType(uint16_t compressionType) -{ - m_CompressionType = compressionType; -} - -void GamebryoSaveGame::FileWrapper::closeCompressedData() -{ - if (m_CompressionType == 0) { - } else if (m_CompressionType == 1 || m_CompressionType == 2) { - m_NextChunk = 0; - m_UncompressedSize = 0; - m_Data->device()->close(); - delete m_Data; - } else - MOBase::log::warn("Please create an issue on the MO github labeled \"Found unknown " - "Compressed\" with your savefile attached"); -} - -bool GamebryoSaveGame::FileWrapper::openCompressedData(int bytesToIgnore) -{ - if (m_CompressionType == 0) { - if (bytesToIgnore > 0) // Just to make certain - skip<char>(bytesToIgnore); - return false; - } else if (m_CompressionType == 1) { - read(m_NextChunk); - read(m_UncompressedSize); - QByteArray placeholder; - m_Data = new QDataStream(placeholder); - bool result = readNextChunk(); - if (result) - skipQDataStream(*m_Data, bytesToIgnore); - return result; - } else if (m_CompressionType == 2) { - uint32_t uncompressedSize; - read(uncompressedSize); - uint32_t compressedSize; - read(compressedSize); - QByteArray compressed; - compressed.resize(compressedSize); - read(compressed.data(), compressedSize); - QByteArray decompressed; - decompressed.resize(uncompressedSize); - LZ4_decompress_safe_partial(compressed.data(), decompressed.data(), compressedSize, - uncompressedSize, uncompressedSize); - compressed.clear(); - - m_Data = new QDataStream(decompressed); - skipQDataStream(*m_Data, bytesToIgnore); - - return true; - } else { - MOBase::log::warn("Please create an issue on the MO github labeled \"Found unknown " - "Compressed\" with your savefile attached"); - return false; - } -} - -bool GamebryoSaveGame::FileWrapper::readNextChunk() -{ - uint32_t have; - uint64_t read = 0; - std::unique_ptr<char[]> inBuffer = std::make_unique<char[]>(CHUNK); - std::unique_ptr<char[]> outBuffer = std::make_unique<char[]>(CHUNK); - QByteArray finalData; - m_Data->device()->close(); - delete m_Data; - z_stream stream{}; - try { - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - stream.avail_in = 0; - stream.next_in = Z_NULL; - if (m_NextChunk >= m_File.size() || finalData.size() == m_UncompressedSize) - return false; - m_File.seek(m_NextChunk); - int zlibRet = inflateInit2(&stream, 15 + 32); - if (zlibRet != Z_OK) { - return false; - } - do { - stream.avail_in = m_File.read(inBuffer.get(), CHUNK); - read += stream.avail_in; - if (!m_File.isReadable()) { - (void)inflateEnd(&stream); - return false; - } - if (stream.avail_in == 0) - break; - stream.next_in = reinterpret_cast<Bytef*>(inBuffer.get()); - do { - stream.avail_out = CHUNK; - stream.next_out = reinterpret_cast<Bytef*>(outBuffer.get()); - zlibRet = inflate(&stream, Z_NO_FLUSH); - if ((zlibRet != Z_OK) && (zlibRet != Z_STREAM_END) && - (zlibRet != Z_BUF_ERROR)) { - return false; - } - have = CHUNK - stream.avail_out; - finalData += QByteArray::fromRawData(outBuffer.get(), have); - } while (stream.avail_out == 0); - read -= stream.avail_in; - } while (zlibRet != Z_STREAM_END); - inflateEnd(&stream); - uint64_t remainder = (m_NextChunk + read) % 16; - uint64_t next = m_NextChunk + read + 16 - (remainder == 0 ? 16 : remainder); - m_NextChunk = next; - } catch (const std::exception&) { - inflateEnd(&stream); - return false; - } - m_Data = new QDataStream(finalData); - return true; -} - -uint8_t GamebryoSaveGame::FileWrapper::readChar(int bytesToIgnore) -{ - if (m_CompressionType == 0) { - if (bytesToIgnore > 0) // Just to make certain - skip<char>(bytesToIgnore); - uint8_t version; - read(version); - return version; - } else if (m_CompressionType == 1 || m_CompressionType == 2) { - // decompression already done by readSaveGameVersion - skipQDataStream(*m_Data, bytesToIgnore); - - uint8_t version; - readQDataStream(*m_Data, version); - return version; - - } else { - MOBase::log::warn("Please create an issue on the MO github labeled \"Found unknown " - "Compressed\" with your savefile attached"); - return 0; - } -} - -uint16_t GamebryoSaveGame::FileWrapper::readShort(int bytesToIgnore) -{ - if (m_CompressionType == 0) { - if (bytesToIgnore > 0) // Just to make certain - skip<char>(bytesToIgnore); - uint16_t size; - read(size); - return size; - } else if (m_CompressionType == 1 || m_CompressionType == 2) { - // decompression already done by readSaveGameVersion - skipQDataStream(*m_Data, bytesToIgnore); - - uint16_t size; - readQDataStream(*m_Data, size); - return size; - } else { - MOBase::log::warn("Please create an issue on the MO github labeled \"Found unknown " - "Compressed\" with your savefile attached"); - return 0; - } -} - -uint32_t GamebryoSaveGame::FileWrapper::readInt(int bytesToIgnore) -{ - if (m_CompressionType == 0) { - if (bytesToIgnore > 0) // Just to make certain - skip<char>(bytesToIgnore); - uint32_t size; - read(size); - return size; - } else if (m_CompressionType == 1 || m_CompressionType == 2) { - // decompression already done by readSaveGameVersion - skipQDataStream(*m_Data, bytesToIgnore); - - uint32_t size; - readQDataStream(*m_Data, size); - return size; - } else { - MOBase::log::warn("Please create an issue on the MO github labeled \"Found unknown " - "Compressed\" with your savefile attached"); - return 0; - } -} - -uint64_t GamebryoSaveGame::FileWrapper::readLong(int bytesToIgnore) -{ - if (m_CompressionType == 0) { - if (bytesToIgnore > 0) // Just to make certain - skip<char>(bytesToIgnore); - uint64_t size; - read(size); - return size; - } else if (m_CompressionType == 1 || m_CompressionType == 2) { - // decompression already done by readSaveGameVersion - skipQDataStream(*m_Data, bytesToIgnore); - - uint64_t size; - readQDataStream(*m_Data, size); - return size; - } else { - MOBase::log::warn("Please create an issue on the MO github labeled \"Found unknown " - "Compressed\" with your savefile attached"); - return 0; - } -} - -float_t GamebryoSaveGame::FileWrapper::readFloat(int bytesToIgnore) -{ - if (m_CompressionType == 0) { - if (bytesToIgnore > 0) // Just to make certain - skip<char>(bytesToIgnore); - float_t value; - read(value); - return value; - } else if (m_CompressionType == 1 || m_CompressionType == 2) { - // decompression already done by readSaveGameVersion - skipQDataStream(*m_Data, bytesToIgnore); - - float_t value; - readQDataStream(*m_Data, value); - return value; - } else { - MOBase::log::warn("Please create an issue on the MO github labeled \"Found unknown " - "Compressed\" with your savefile attached"); - return 0; - } -} - -QStringList GamebryoSaveGame::FileWrapper::readPlugins(int bytesToIgnore, int extraData, - const QStringList& corePlugins) -{ - if (m_CompressionType == 0) { - if (bytesToIgnore > 0) // Just to make certain - skip<char>(bytesToIgnore); - uint8_t count; - read(count); - return readPluginData(count, extraData, corePlugins); - } else if (m_CompressionType == 1 || m_CompressionType == 2) { - skipQDataStream(*m_Data, bytesToIgnore); - uint8_t count; - readQDataStream(*m_Data, count); - return readPluginData(count, extraData, corePlugins); - } - return {}; -} - -QStringList -GamebryoSaveGame::FileWrapper::readLightPlugins(int bytesToIgnore, int extraData, - const QStringList& corePlugins) -{ - if (m_CompressionType == 0) { - if (bytesToIgnore > 0) // Just to make certain - skip<char>(bytesToIgnore); - uint16_t count; - read(count); - return readPluginData(count, extraData, corePlugins); - } else if (m_CompressionType == 1 || m_CompressionType == 2) { - skipQDataStream(*m_Data, bytesToIgnore); - uint16_t count; - readQDataStream(*m_Data, count); - return readPluginData(count, extraData, corePlugins); - } - return {}; -} - -QStringList -GamebryoSaveGame::FileWrapper::readMediumPlugins(int bytesToIgnore, int extraData, - const QStringList& corePlugins) -{ - if (m_CompressionType != 1) { - return {}; - } else { - skipQDataStream(*m_Data, bytesToIgnore); - uint32_t count; - readQDataStream(*m_Data, count); - return readPluginData(count, extraData, corePlugins); - } -} - -QStringList GamebryoSaveGame::FileWrapper::readPluginData(uint32_t count, int extraData, - const QStringList corePlugins) -{ - QStringList plugins; - plugins.reserve(count); - if (m_CompressionType == 0) { - for (std::size_t i = 0; i < count; ++i) { - QString name; - read(name); - plugins.push_back(name); - } - } else { - for (std::size_t i = 0; i < count; ++i) { - QString name; - read(name); - plugins.push_back(name); - bool isCustomPlugin; - if (extraData) { - if (extraData > 1) { - readQDataStream(*m_Data, isCustomPlugin); - } else { - isCustomPlugin = !corePlugins.contains(name); - } - if (isCustomPlugin) { - QString creationName; - QString creationId; - uint16_t flagsSize; - uint8_t isCreation; - read(creationName); - read(creationId); - readQDataStream(*m_Data, flagsSize); - skipQDataStream(*m_Data, flagsSize); - readQDataStream(*m_Data, isCreation); - } - } - } - } - return plugins; -} - -void GamebryoSaveGame::FileWrapper::close() -{ - m_File.close(); -} diff --git a/libs/game_gamebryo/src/gamebryo/gamebryosavegame.h b/libs/game_gamebryo/src/gamebryo/gamebryosavegame.h deleted file mode 100644 index 44d0584..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryosavegame.h +++ /dev/null @@ -1,240 +0,0 @@ -#ifndef GAMEBRYOSAVEGAME_H -#define GAMEBRYOSAVEGAME_H - -#include "isavegame.h" -#include "memoizedlock.h" - -#include <QDateTime> -#include <QFile> -#include <QImage> -#include <QString> -#include <QStringList> - -#include <stddef.h> -#include <stdexcept> - -struct _SYSTEMTIME; - -namespace MOBase -{ -class IPluginGame; -} // namespace MOBase - -class GameGamebryo; - -class GamebryoSaveGame : public MOBase::ISaveGame -{ -public: - GamebryoSaveGame(QString const& file, GameGamebryo const* game, - bool const lightEnabled = false, bool const mediumEnabled = false); - - virtual ~GamebryoSaveGame(); - -public: // ISaveGame interface - virtual QString getFilepath() const override; - virtual QDateTime getCreationTime() const override; - virtual QString getName() const override; - virtual QString getSaveGroupIdentifier() const override; - virtual QStringList allFiles() const override; - -public: - bool hasScriptExtenderFile() const; - - // Simple getters - virtual QString getPCName() const { return m_PCName; } - virtual unsigned short getPCLevel() const { return m_PCLevel; } - virtual QString getPCLocation() const { return m_PCLocation; } - virtual unsigned long getSaveNumber() const { return m_SaveNumber; } - - QStringList const& getPlugins() const { return m_DataFields.value()->Plugins; } - QStringList const& getMediumPlugins() const - { - return m_DataFields.value()->MediumPlugins; - } - QStringList const& getLightPlugins() const - { - return m_DataFields.value()->LightPlugins; - } - QImage const& getScreenshot() const { return m_DataFields.value()->Screenshot; } - - bool isMediumEnabled() const { return m_MediumEnabled; } - - bool isLightEnabled() const { return m_LightEnabled; } - - enum class StringType - { - TYPE_BZSTRING, - TYPE_BSTRING, - TYPE_WSTRING - }; - - enum class StringFormat - { - UTF8, - LOCAL8BIT - }; - -protected: - friend class FileWrapper; - - class FileWrapper - { - public: - /** - * @brief Construct the save file information. - * - * @param filepath The path to the save file. - * @params expected Expecte bytes at start of file. - * - **/ - FileWrapper(QString const& filepath, QString const& expected); - - /** Set this for save games that have a marker at the end of each - * field. Specifically fallout - **/ - void setHasFieldMarkers(bool); - - /** Set bz string mode (1 byte length, null terminated) - **/ - void setPluginString(StringType); - - /** Set string format (utf-8, windows local 8 bit strings) - **/ - void setPluginStringFormat(StringFormat); - - template <typename T> - void skip(int count = 1) - { - if (!m_File.seek(m_File.pos() + count * sizeof(T))) { - throw std::runtime_error("unexpected end of file"); - } - } - - template <typename T> - void read(T& value) - { - int read = m_File.read(reinterpret_cast<char*>(&value), sizeof(T)); - if (read != sizeof(T)) { - throw std::runtime_error("unexpected end of file"); - } - if (m_HasFieldMarkers) { - skip<char>(); - } - } - - template <> - void read<QString>(QString& value); - - void seek(unsigned long pos) - { - if (!m_File.seek(pos)) { - throw std::runtime_error("unexpected end of file"); - } - } - - void read(void* buff, std::size_t length); - - /* Reads RGB image from save - * Assumes picture dimentions come immediately before the save - */ - QImage readImage(int scale = 0, bool alpha = false); - - /* Reads RGB image from save */ - QImage readImage(unsigned long width, unsigned long height, int scale = 0, - bool alpha = false); - - /* Sets the compression type. */ - void setCompressionType(uint16_t type); - - /* uncompress the begining of the compressed block */ - bool openCompressedData(int bytesToIgnore = 0); - - /* read the next compressed block */ - bool readNextChunk(); - - /* frees the uncompressed block */ - void closeCompressedData(); - - /* Read the save game version in the compressed block */ - uint8_t readChar(int bytesToIgnore = 0); - - uint16_t readShort(int bytesToIgnore = 0); - - uint32_t readInt(int bytesToIgnore = 0); - - uint64_t readLong(int bytesToIgnore = 0); - - float_t readFloat(int bytesToIgnore = 0); - - /* Read the plugin list */ - QStringList readPlugins(int bytesToIgnore = 0, int extraData = 0, - const QStringList& corePlugins = {}); - - /* Read the light plugin list */ - QStringList readLightPlugins(int bytesToIgnore = 0, int extraData = 0, - const QStringList& corePlugins = {}); - - /* Read the medium plugin list */ - QStringList readMediumPlugins(int bytesToIgnore = 0, int extraData = 0, - const QStringList& corePlugins = {}); - - void close(); - - private: - QFile m_File; - uint64_t m_NextChunk; - uint64_t m_UncompressedSize; - bool m_HasFieldMarkers; - StringType m_PluginString; - StringFormat m_PluginStringFormat; - QDataStream* m_Data; - uint16_t m_CompressionType = 0; - - private: - template <typename T> - void readQDataStream(QDataStream& data, T& value); - - void readQDataStream(QDataStream& data, void* buff, std::size_t length); - - void skipQDataStream(QDataStream& data, std::size_t length); - - QStringList readPluginData(uint32_t count, int extraData, - const QStringList corePlugins); - }; - - void setCreationTime(_SYSTEMTIME const& time); - - GameGamebryo const* m_Game; - bool m_MediumEnabled; - bool m_LightEnabled; - - QString m_FileName; - QString m_PCName; - unsigned short m_PCLevel; - QString m_PCLocation; - unsigned long m_SaveNumber; - QDateTime m_CreationTime; - - // Those three fields are usually much slower to fetch than - // the other, so we do not fetch them if not needed. - // - // This is virtual so child class can add fields if those are - // hard to access. - struct DataFields - { - QStringList Plugins; - QStringList LightPlugins; - QStringList MediumPlugins; - QImage Screenshot; - - // We need this constructor. - DataFields() {} - virtual ~DataFields() {} - }; - MOBase::MemoizedLocked<std::unique_ptr<DataFields>> m_DataFields; - - // Fetch the field. - virtual std::unique_ptr<DataFields> fetchDataFields() const = 0; -}; - -#endif // GAMEBRYOSAVEGAME_H diff --git a/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfo.cpp b/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfo.cpp deleted file mode 100644 index 6d1289a..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfo.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "gamebryosavegameinfo.h" - -#include "gamebryosavegame.h" -#include "gamebryosavegameinfowidget.h" -#include "gamegamebryo.h" -#include "imodinterface.h" -#include "imoinfo.h" -#include "iplugingame.h" -#include "ipluginlist.h" - -#include <QDir> -#include <QString> -#include <QStringList> - -GamebryoSaveGameInfo::GamebryoSaveGameInfo(GameGamebryo const* game) : m_Game(game) {} - -GamebryoSaveGameInfo::~GamebryoSaveGameInfo() {} - -GamebryoSaveGameInfo::MissingAssets -GamebryoSaveGameInfo::getMissingAssets(MOBase::ISaveGame const& save) const -{ - GamebryoSaveGame const& gamebryoSave = dynamic_cast<GamebryoSaveGame const&>(save); - MOBase::IOrganizer* organizerCore = m_Game->m_Organizer; - - // collect the list of missing plugins - MissingAssets missingAssets; - - for (QString const& pluginName : gamebryoSave.getPlugins()) { - switch (organizerCore->pluginList()->state(pluginName)) { - case MOBase::IPluginList::STATE_INACTIVE: - missingAssets[pluginName] = - ProvidingModules{organizerCore->pluginList()->origin(pluginName)}; - break; - case MOBase::IPluginList::STATE_MISSING: - missingAssets[pluginName] = ProvidingModules(); - break; - } - } - - for (QString const& pluginName : gamebryoSave.getLightPlugins()) { - switch (organizerCore->pluginList()->state(pluginName)) { - case MOBase::IPluginList::STATE_INACTIVE: - missingAssets[pluginName] = - ProvidingModules{organizerCore->pluginList()->origin(pluginName)}; - break; - case MOBase::IPluginList::STATE_MISSING: - missingAssets[pluginName] = ProvidingModules(); - break; - } - } - - // Find out any other mods that might contain the esp/esm - QStringList espFilter({"*.esp", "*.esl", "*.esm"}); - - QString dataDir(organizerCore->managedGame()->dataDirectory().absolutePath()); - - // Search normal mods. A note: This will also find mods in data. - for (QString const& mod : organizerCore->modList()->allModsByProfilePriority()) { - MOBase::IModInterface* modInfo = organizerCore->modList()->getMod(mod); - QStringList esps = QDir(modInfo->absolutePath()).entryList(espFilter); - for (QString const& esp : esps) { - MissingAssets::iterator iter = missingAssets.find(esp); - if (modInfo->absolutePath() == dataDir) { - // We have to prune esps that reside in the data directory, otherwise - // you get all the unmanaged mods listed as potential candidates for - // enabling - if (modInfo->name() != organizerCore->pluginList()->origin(esp)) { - continue; - } - } - if (iter != missingAssets.end()) { - if (!iter->contains(modInfo->name())) { - iter->push_back(modInfo->name()); - } - } - } - } - - // search in overwrite - { - QDir overwriteDir(organizerCore->overwritePath()); - QStringList esps = overwriteDir.entryList(espFilter); - for (const QString& esp : esps) { - MissingAssets::iterator iter = missingAssets.find(esp); - if (iter != missingAssets.end()) { - if (!iter->contains("<overwrite>")) { - iter->push_back("<overwrite>"); - } - } - } - } - - return missingAssets; -} - -MOBase::ISaveGameInfoWidget* -GamebryoSaveGameInfo::getSaveGameWidget(QWidget* parent) const -{ - return new GamebryoSaveGameInfoWidget(this, parent); -} diff --git a/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfo.h b/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfo.h deleted file mode 100644 index e214293..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfo.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef GAMEBRYOSAVEGAMEINFO_H -#define GAMEBRYOSAVEGAMEINFO_H - -#include "savegameinfo.h" - -class GameGamebryo; - -class GamebryoSaveGameInfo : public MOBase::SaveGameInfo -{ -public: - GamebryoSaveGameInfo(GameGamebryo const* game); - ~GamebryoSaveGameInfo(); - - virtual MissingAssets getMissingAssets(MOBase::ISaveGame const& save) const override; - - virtual MOBase::ISaveGameInfoWidget* getSaveGameWidget(QWidget*) const override; - -protected: - friend class GamebryoSaveGameInfoWidget; - GameGamebryo const* m_Game; -}; - -#endif // GAMEBRYOSAVEGAMEINFO_H diff --git a/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfowidget.cpp b/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfowidget.cpp deleted file mode 100644 index 8c95dad..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfowidget.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "gamebryosavegameinfowidget.h" -#include "ui_gamebryosavegameinfowidget.h" - -#include "gamebryosavegame.h" -#include "gamebryosavegameinfo.h" -#include "gamegamebryo.h" -#include "imoinfo.h" -#include "ipluginlist.h" - -#include <QDate> -#include <QDateTime> -#include <QFont> -#include <QFrame> -#include <QLabel> -#include <QLayout> -#include <QLayoutItem> -#include <QPixmap> -#include <QString> -#include <QStyle> -#include <QTime> -#include <QVBoxLayout> - -#include <Qt> -#include <QtGlobal> - -#include <memory> - -GamebryoSaveGameInfoWidget::GamebryoSaveGameInfoWidget(GamebryoSaveGameInfo const* info, - QWidget* parent) - : MOBase::ISaveGameInfoWidget(parent), ui(new Ui::GamebryoSaveGameInfoWidget), - m_Info(info) -{ - ui->setupUi(this); - this->setWindowFlags(Qt::ToolTip | Qt::BypassGraphicsProxyWidget); - setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0, this) / - qreal(255.0)); - ui->gameFrame->setStyleSheet("background-color: transparent;"); - - QVBoxLayout* gameLayout = new QVBoxLayout(); - gameLayout->setContentsMargins(0, 0, 0, 0); - gameLayout->setSpacing(2); - ui->gameFrame->setLayout(gameLayout); -} - -GamebryoSaveGameInfoWidget::~GamebryoSaveGameInfoWidget() -{ - delete ui; -} - -void GamebryoSaveGameInfoWidget::setSave(MOBase::ISaveGame const& save) -{ - auto& gamebryoSave = dynamic_cast<GamebryoSaveGame const&>(save); - ui->saveNumLabel->setText(QString("%1").arg(gamebryoSave.getSaveNumber())); - ui->characterLabel->setText(gamebryoSave.getPCName()); - ui->locationLabel->setText(gamebryoSave.getPCLocation()); - ui->levelLabel->setText(QString("%1").arg(gamebryoSave.getPCLevel())); - // This somewhat contorted code is because on my system at least, the - // old way of doing this appears to give short date and long time. - QDateTime t = gamebryoSave.getCreationTime().toLocalTime(); - ui->dateLabel->setText( - QLocale::system().toString(t.date(), QLocale::FormatType::ShortFormat) + " " + - QLocale::system().toString(t.time())); - ui->screenshotLabel->setPixmap(QPixmap::fromImage(gamebryoSave.getScreenshot())); - if (ui->gameFrame->layout() != nullptr) { - QLayoutItem* item = nullptr; - while ((item = ui->gameFrame->layout()->takeAt(0)) != nullptr) { - delete item->widget(); - delete item; - } - ui->gameFrame->layout()->setSizeConstraint(QLayout::SetFixedSize); - } - - // Resize box to new content - this->resize(0, 0); - - QLayout* layout = ui->gameFrame->layout(); - if (gamebryoSave.hasScriptExtenderFile()) { - QLabel* scriptExtender = new QLabel(tr("Has Script Extender Data")); - QFont headerFont = scriptExtender->font(); - headerFont.setBold(true); - layout->addWidget(scriptExtender); - } - QLabel* header = new QLabel(tr("Missing ESPs")); - QFont headerFont = header->font(); - QFont contentFont = headerFont; - headerFont.setItalic(true); - contentFont.setBold(true); - contentFont.setPointSize(7); - header->setFont(headerFont); - layout->addWidget(header); - int count = 0; - MOBase::IPluginList* pluginList = m_Info->m_Game->m_Organizer->pluginList(); - for (QString const& pluginName : gamebryoSave.getPlugins()) { - if (pluginList->state(pluginName) == MOBase::IPluginList::STATE_ACTIVE) { - continue; - } - - ++count; - - if (count > 7) { - break; - } - - QLabel* pluginLabel = new QLabel(pluginName); - pluginLabel->setIndent(10); - pluginLabel->setFont(contentFont); - layout->addWidget(pluginLabel); - } - if (count > 7) { - QLabel* dotDotLabel = new QLabel("..."); - dotDotLabel->setIndent(10); - dotDotLabel->setFont(contentFont); - layout->addWidget(dotDotLabel); - } - if (count == 0) { - QLabel* dotDotLabel = new QLabel(tr("None")); - dotDotLabel->setIndent(10); - dotDotLabel->setFont(contentFont); - layout->addWidget(dotDotLabel); - } - if (gamebryoSave.isMediumEnabled()) { - QLabel* headerEsh = new QLabel(tr("Missing ESHs")); - QFont headerEshFont = headerEsh->font(); - QFont contentEshFont = headerEshFont; - headerEshFont.setItalic(true); - contentEshFont.setBold(true); - contentEshFont.setPointSize(7); - headerEsh->setFont(headerEshFont); - layout->addWidget(headerEsh); - int countEsh = 0; - for (QString const& pluginName : gamebryoSave.getMediumPlugins()) { - if (pluginList->state(pluginName) == MOBase::IPluginList::STATE_ACTIVE) { - continue; - } - - ++countEsh; - - if (countEsh > 7) { - break; - } - - QLabel* pluginLabel = new QLabel(pluginName); - pluginLabel->setIndent(10); - pluginLabel->setFont(contentFont); - layout->addWidget(pluginLabel); - } - if (countEsh > 7) { - QLabel* dotDotLabel = new QLabel("..."); - dotDotLabel->setIndent(10); - dotDotLabel->setFont(contentFont); - layout->addWidget(dotDotLabel); - } - if (countEsh == 0) { - QLabel* dotDotLabel = new QLabel(tr("None")); - dotDotLabel->setIndent(10); - dotDotLabel->setFont(contentFont); - layout->addWidget(dotDotLabel); - } - } - if (gamebryoSave.isLightEnabled()) { - QLabel* headerEsl = new QLabel(tr("Missing ESLs")); - QFont headerEslFont = headerEsl->font(); - QFont contentEslFont = headerEslFont; - headerEslFont.setItalic(true); - contentEslFont.setBold(true); - contentEslFont.setPointSize(7); - headerEsl->setFont(headerEslFont); - layout->addWidget(headerEsl); - int countEsl = 0; - for (QString const& pluginName : gamebryoSave.getLightPlugins()) { - if (pluginList->state(pluginName) == MOBase::IPluginList::STATE_ACTIVE) { - continue; - } - - ++countEsl; - - if (countEsl > 7) { - break; - } - - QLabel* pluginLabel = new QLabel(pluginName); - pluginLabel->setIndent(10); - pluginLabel->setFont(contentFont); - layout->addWidget(pluginLabel); - } - if (countEsl > 7) { - QLabel* dotDotLabel = new QLabel("..."); - dotDotLabel->setIndent(10); - dotDotLabel->setFont(contentFont); - layout->addWidget(dotDotLabel); - } - if (countEsl == 0) { - QLabel* dotDotLabel = new QLabel(tr("None")); - dotDotLabel->setIndent(10); - dotDotLabel->setFont(contentFont); - layout->addWidget(dotDotLabel); - } - } -} diff --git a/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfowidget.h b/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfowidget.h deleted file mode 100644 index 6642863..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfowidget.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef GAMEBRYOSAVEGAMEINFOWIDGET_H -#define GAMEBRYOSAVEGAMEINFOWIDGET_H - -#include "isavegameinfowidget.h" - -#include <QObject> - -class GamebryoSaveGameInfo; - -namespace Ui -{ -class GamebryoSaveGameInfoWidget; -} - -class GamebryoSaveGameInfoWidget : public MOBase::ISaveGameInfoWidget -{ - Q_OBJECT - -public: - GamebryoSaveGameInfoWidget(GamebryoSaveGameInfo const* info, QWidget* parent); - ~GamebryoSaveGameInfoWidget(); - - virtual void setSave(MOBase::ISaveGame const&) override; - -private: - Ui::GamebryoSaveGameInfoWidget* ui; - GamebryoSaveGameInfo const* m_Info; -}; - -#endif // GAMEBRYOSAVEGAMEINFOWIDGET_H diff --git a/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfowidget.ui b/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfowidget.ui deleted file mode 100644 index ea45d10..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryosavegameinfowidget.ui +++ /dev/null @@ -1,209 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>GamebryoSaveGameInfoWidget</class> - <widget class="QWidget" name="GamebryoSaveGameInfoWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>400</width> - <height>300</height> - </rect> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="windowTitle"> - <string/> - </property> - <property name="toolTip"> - <string notr="true"/> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QFormLayout" name="formLayout"> - <property name="fieldGrowthPolicy"> - <enum>QFormLayout::AllNonFixedFieldsGrow</enum> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="font"> - <font> - <italic>true</italic> - </font> - </property> - <property name="text"> - <string>Save #</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_2"> - <property name="font"> - <font> - <italic>true</italic> - </font> - </property> - <property name="text"> - <string>Character</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_4"> - <property name="font"> - <font> - <italic>true</italic> - </font> - </property> - <property name="text"> - <string>Level</string> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_3"> - <property name="font"> - <font> - <italic>true</italic> - </font> - </property> - <property name="text"> - <string>Location</string> - </property> - </widget> - </item> - <item row="4" column="0"> - <widget class="QLabel" name="label_5"> - <property name="font"> - <font> - <italic>true</italic> - </font> - </property> - <property name="text"> - <string>Date</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="saveNumLabel"> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string notr="true"/> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLabel" name="characterLabel"> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string notr="true"/> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QLabel" name="levelLabel"> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QLabel" name="locationLabel"> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string notr="true"/> - </property> - </widget> - </item> - <item row="4" column="1"> - <widget class="QLabel" name="dateLabel"> - <property name="font"> - <font> - <weight>75</weight> - <bold>true</bold> - </font> - </property> - <property name="text"> - <string/> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QFrame" name="gameFrame"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>0</height> - </size> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="screenshotLabel"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>16777215</height> - </size> - </property> - <property name="autoFillBackground"> - <bool>false</bool> - </property> - <property name="text"> - <string notr="true"/> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/libs/game_gamebryo/src/gamebryo/gamebryoscriptextender.cpp b/libs/game_gamebryo/src/gamebryo/gamebryoscriptextender.cpp deleted file mode 100644 index e3f709a..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryoscriptextender.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "gamebryoscriptextender.h" - -#include "gamegamebryo.h" - -#include "utility.h" - -#include <QDir> -#include <QString> - -GamebryoScriptExtender::GamebryoScriptExtender(const GameGamebryo* game) : m_Game(game) -{} - -GamebryoScriptExtender::~GamebryoScriptExtender() {} - -QString GamebryoScriptExtender::loaderName() const -{ - return BinaryName(); -} - -QString GamebryoScriptExtender::loaderPath() const -{ - return m_Game->gameDirectory().absoluteFilePath(loaderName()); -} - -QString GamebryoScriptExtender::savegameExtension() const -{ - return m_Game->savegameSEExtension(); -} - -bool GamebryoScriptExtender::isInstalled() const -{ - // A note: It is possibly also OK if xxse_steam_loader.dll exists, but it's - // not clear why that would exist and the exe not if you'd installed it per - // instructions, and it'd mess up NCC installs a treat. - return m_Game->gameDirectory().exists(loaderName()); -} - -QString GamebryoScriptExtender::getExtenderVersion() const -{ - return MOBase::getFileVersion(m_Game->gameDirectory().absoluteFilePath(loaderName())); -} - -WORD GamebryoScriptExtender::getArch() const -{ - return m_Game->getArch(loaderName()); -} diff --git a/libs/game_gamebryo/src/gamebryo/gamebryoscriptextender.h b/libs/game_gamebryo/src/gamebryo/gamebryoscriptextender.h deleted file mode 100644 index 7ab4f1d..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryoscriptextender.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef GAMEBRYOSCRIPTEXTENDER_H -#define GAMEBRYOSCRIPTEXTENDER_H - -#include "scriptextender.h" - -class GameGamebryo; - -class GamebryoScriptExtender : public MOBase::ScriptExtender -{ -public: - GamebryoScriptExtender(GameGamebryo const* game); - - virtual ~GamebryoScriptExtender(); - - virtual QString loaderName() const override; - - virtual QString loaderPath() const override; - - virtual QString savegameExtension() const override; - - virtual bool isInstalled() const override; - - virtual QString getExtenderVersion() const override; - - virtual WORD getArch() const override; - -protected: - GameGamebryo const* const m_Game; -}; - -#endif // GAMEBRYOSCRIPTEXTENDER_H diff --git a/libs/game_gamebryo/src/gamebryo/gamebryounmanagedmods.cpp b/libs/game_gamebryo/src/gamebryo/gamebryounmanagedmods.cpp deleted file mode 100644 index e5c7608..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryounmanagedmods.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "gamebryounmanagedmods.h" -#include "gamegamebryo.h" -#include <pluginsetting.h> - -GamebryoUnmangedMods::GamebryoUnmangedMods(const GameGamebryo* game) : m_Game(game) {} - -GamebryoUnmangedMods::~GamebryoUnmangedMods() {} - -QStringList GamebryoUnmangedMods::mods(bool onlyOfficial) const -{ - QStringList result; - - QStringList dlcPlugins = m_Game->DLCPlugins(); - QStringList mainPlugins = m_Game->primaryPlugins(); - - QDir dataDir(m_Game->dataDirectory()); - for (const QString& fileName : dataDir.entryList({"*.esp", "*.esl", "*.esm"})) { - if (!mainPlugins.contains(fileName, Qt::CaseInsensitive) && - (!onlyOfficial || dlcPlugins.contains(fileName, Qt::CaseInsensitive))) { - result.append(fileName.chopped(4)); // trims the extension off - } - } - - return result; -} - -QString GamebryoUnmangedMods::displayName(const QString& modName) const -{ - return modName; -} - -QFileInfo GamebryoUnmangedMods::referenceFile(const QString& modName) const -{ - QFileInfoList files = - m_Game->dataDirectory().entryInfoList(QStringList() << modName + ".es*"); - if (files.size() > 0) { - return files.at(0); - } else { - return QFileInfo(); - } -} - -QStringList GamebryoUnmangedMods::secondaryFiles(const QString& modName) const -{ - QStringList archives; - QDir dataDir = m_Game->dataDirectory(); - for (const QString& archiveName : dataDir.entryList({modName + "*.bsa"})) { - archives.append(dataDir.absoluteFilePath(archiveName)); - } - return archives; -} diff --git a/libs/game_gamebryo/src/gamebryo/gamebryounmanagedmods.h b/libs/game_gamebryo/src/gamebryo/gamebryounmanagedmods.h deleted file mode 100644 index 38e2ba5..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamebryounmanagedmods.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef GAMEBRYOUNMANAGEDMODS_H -#define GAMEBRYOUNMANAGEDMODS_H - -#include <unmanagedmods.h> - -class GameGamebryo; - -class GamebryoUnmangedMods : public MOBase::UnmanagedMods -{ -public: - GamebryoUnmangedMods(const GameGamebryo* game); - ~GamebryoUnmangedMods(); - - virtual QStringList mods(bool onlyOfficial) const override; - virtual QString displayName(const QString& modName) const override; - virtual QFileInfo referenceFile(const QString& modName) const override; - virtual QStringList secondaryFiles(const QString& modName) const override; - -protected: - const GameGamebryo* game() const { return m_Game; } - -private: - const GameGamebryo* m_Game; -}; - -#endif // GAMEBRYOUNMANAGEDMODS_H diff --git a/libs/game_gamebryo/src/gamebryo/gamegamebryo.cpp b/libs/game_gamebryo/src/gamebryo/gamegamebryo.cpp deleted file mode 100644 index 347c2d8..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamegamebryo.cpp +++ /dev/null @@ -1,478 +0,0 @@ -#include "gamegamebryo.h" - -#include "bsainvalidation.h" -#include "dataarchives.h" -#include "gamebryomoddatacontent.h" -#include "gamebryosavegame.h" -#include "gameplugins.h" -#include "iprofile.h" -#include "log.h" -#include "registry.h" -#include "savegameinfo.h" -#include "scopeguard.h" -#include "scriptextender.h" -#include "utility.h" -#include "vdf_parser.h" - -#include <QDir> -#include <QDirIterator> -#include <QFile> -#include <QFileInfo> -#include <QIcon> -#include <QJsonDocument> -#include <QJsonValue> - -#include <QtDebug> -#include <QtGlobal> - -#include <Knownfolders.h> -#include <Shlobj.h> -#include <Windows.h> -#include <winreg.h> -#include <winver.h> - -#include <optional> -#include <string> -#include <vector> - -GameGamebryo::GameGamebryo() {} - -void GameGamebryo::detectGame() -{ - m_GamePath = identifyGamePath(); - m_MyGamesPath = determineMyGamesPath(gameName()); -} - -bool GameGamebryo::init(MOBase::IOrganizer* moInfo) -{ - m_Organizer = moInfo; - m_Organizer->onAboutToRun([this](const auto& binary) { - return prepareIni(binary); - }); - return true; -} - -bool GameGamebryo::isInstalled() const -{ - return !m_GamePath.isEmpty(); -} - -QIcon GameGamebryo::gameIcon() const -{ - return MOBase::iconForExecutable(gameDirectory().absoluteFilePath(binaryName())); -} - -QDir GameGamebryo::gameDirectory() const -{ - return QDir(m_GamePath); -} - -QDir GameGamebryo::dataDirectory() const -{ - return gameDirectory().absoluteFilePath("data"); -} - -void GameGamebryo::setGamePath(const QString& path) -{ - m_GamePath = path; -} - -QDir GameGamebryo::documentsDirectory() const -{ - return m_MyGamesPath; -} - -QDir GameGamebryo::savesDirectory() const -{ - return QDir(myGamesPath() + "/Saves"); -} - -std::vector<std::shared_ptr<const MOBase::ISaveGame>> -GameGamebryo::listSaves(QDir folder) const -{ - QStringList filters; - filters << QString("*.") + savegameExtension(); - - std::vector<std::shared_ptr<const MOBase::ISaveGame>> saves; - for (auto info : folder.entryInfoList(filters, QDir::Files)) { - try { - saves.push_back(makeSaveGame(info.filePath())); - } catch (std::exception& e) { - MOBase::log::error("{}", e.what()); - continue; - } - } - - return saves; -} - -void GameGamebryo::setGameVariant(const QString& variant) -{ - m_GameVariant = variant; -} - -QString GameGamebryo::binaryName() const -{ - return gameShortName() + ".exe"; -} - -MOBase::IPluginGame::LoadOrderMechanism GameGamebryo::loadOrderMechanism() const -{ - return LoadOrderMechanism::FileTime; -} - -MOBase::IPluginGame::SortMechanism GameGamebryo::sortMechanism() const -{ - return SortMechanism::LOOT; -} - -bool GameGamebryo::looksValid(QDir const& path) const -{ - // Check for <prog>.exe for now. - return path.exists(binaryName()); -} - -QString GameGamebryo::gameVersion() const -{ - // We try the file version, but if it looks invalid (starts with the fallback - // version), we look the product version instead. If the product version is - // not empty, we use it. - QString binaryAbsPath = gameDirectory().absoluteFilePath(binaryName()); - QString version = MOBase::getFileVersion(binaryAbsPath); - if (version.startsWith(FALLBACK_GAME_VERSION)) { - QString pversion = MOBase::getProductVersion(binaryAbsPath); - if (!pversion.isEmpty()) { - version = pversion; - } - } - return version; -} - -QString GameGamebryo::getLauncherName() const -{ - return gameShortName() + "Launcher.exe"; -} - -WORD GameGamebryo::getArch(QString const& program) const -{ - WORD arch = 0; - // This *really* needs to be factored out - std::wstring app_name = - L"\\\\?\\" + - QDir::toNativeSeparators(this->gameDirectory().absoluteFilePath(program)) - .toStdWString(); - - WIN32_FIND_DATAW FindFileData; - HANDLE hFind = ::FindFirstFileW(app_name.c_str(), &FindFileData); - - // exit if the binary was not found - if (hFind == INVALID_HANDLE_VALUE) - return arch; - - HANDLE hFile = INVALID_HANDLE_VALUE; - HANDLE hMapping = INVALID_HANDLE_VALUE; - LPVOID addrHeader = nullptr; - PIMAGE_NT_HEADERS peHdr = nullptr; - - hFile = CreateFileW(app_name.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); - if (hFile == INVALID_HANDLE_VALUE) - goto cleanup; - - hMapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY | SEC_IMAGE, 0, 0, - program.toStdWString().c_str()); - if (hMapping == INVALID_HANDLE_VALUE) - goto cleanup; - - addrHeader = MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0); - if (addrHeader == NULL) - goto cleanup; // couldn't memory map the file - - peHdr = ImageNtHeader(addrHeader); - if (peHdr == NULL) - goto cleanup; // couldn't read the header - - arch = peHdr->FileHeader.Machine; - -cleanup: // release all of our handles - FindClose(hFind); - if (hFile != INVALID_HANDLE_VALUE) - CloseHandle(hFile); - if (hMapping != INVALID_HANDLE_VALUE) - CloseHandle(hMapping); - return arch; -} - -QFileInfo GameGamebryo::findInGameFolder(const QString& relativePath) const -{ - return QFileInfo(m_GamePath + "/" + relativePath); -} - -QString GameGamebryo::identifyGamePath() const -{ - QString path = "Software\\Bethesda Softworks\\" + gameShortName(); - return findInRegistry(HKEY_LOCAL_MACHINE, path.toStdWString().c_str(), - L"Installed Path"); -} - -bool GameGamebryo::prepareIni(const QString& exec) -{ - MOBase::IProfile* profile = m_Organizer->profile(); - - QString basePath = profile->localSettingsEnabled() - ? profile->absolutePath() - : documentsDirectory().absolutePath(); - - if (!iniFiles().isEmpty()) { - - QString profileIni = basePath + "/" + iniFiles()[0]; - - WCHAR setting[512]; - if (!GetPrivateProfileStringW(L"Launcher", L"bEnableFileSelection", L"0", setting, - 512, profileIni.toStdWString().c_str()) || - wcstol(setting, nullptr, 10) != 1) { - MOBase::WriteRegistryValue(L"Launcher", L"bEnableFileSelection", L"1", - profileIni.toStdWString().c_str()); - } - } - - return true; -} - -QString GameGamebryo::selectedVariant() const -{ - return m_GameVariant; -} - -QString GameGamebryo::myGamesPath() const -{ - return m_MyGamesPath; -} - -/*static*/ QString GameGamebryo::getLootPath() -{ - return findInRegistry(HKEY_LOCAL_MACHINE, L"Software\\LOOT", L"Installed Path") + - "/Loot.exe"; -} - -QString GameGamebryo::localAppFolder() -{ - QString result = getKnownFolderPath(FOLDERID_LocalAppData, false); - if (result.isEmpty()) { - // fallback: try the registry - result = getSpecialPath("Local AppData"); - } - return result; -} - -void GameGamebryo::copyToProfile(QString const& sourcePath, - QDir const& destinationDirectory, - QString const& sourceFileName) -{ - copyToProfile(sourcePath, destinationDirectory, sourceFileName, sourceFileName); -} - -void GameGamebryo::copyToProfile(QString const& sourcePath, - QDir const& destinationDirectory, - QString const& sourceFileName, - QString const& destinationFileName) -{ - QString filePath = destinationDirectory.absoluteFilePath(destinationFileName); - if (!QFileInfo(filePath).exists()) { - if (!MOBase::shellCopy(sourcePath + "/" + sourceFileName, filePath)) { - // if copy file fails, create the file empty - QFile(filePath).open(QIODevice::WriteOnly); - } - } -} - -MappingType GameGamebryo::mappings() const -{ - MappingType result; - - for (const QString& profileFile : {"plugins.txt", "loadorder.txt"}) { - result.push_back({m_Organizer->profilePath() + "/" + profileFile, - localAppFolder() + "/" + gameShortName() + "/" + profileFile, - false}); - } - - return result; -} - -std::unique_ptr<BYTE[]> GameGamebryo::getRegValue(HKEY key, LPCWSTR path, LPCWSTR value, - DWORD flags, LPDWORD type = nullptr) -{ - DWORD size = 0; - HKEY subKey; - LONG res = ::RegOpenKeyExW(key, path, 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &subKey); - if (res != ERROR_SUCCESS) { - res = ::RegOpenKeyExW(key, path, 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &subKey); - if (res != ERROR_SUCCESS) - return std::unique_ptr<BYTE[]>(); - } - res = ::RegGetValueW(subKey, L"", value, flags, type, nullptr, &size); - if (res == ERROR_FILE_NOT_FOUND || res == ERROR_UNSUPPORTED_TYPE) { - return std::unique_ptr<BYTE[]>(); - } - if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { - throw MOBase::MyException( - QObject::tr("failed to query registry path (preflight): %1").arg(res, 0, 16)); - } - - std::unique_ptr<BYTE[]> result(new BYTE[size]); - res = ::RegGetValueW(subKey, L"", value, flags, type, result.get(), &size); - - if (res != ERROR_SUCCESS) { - throw MOBase::MyException( - QObject::tr("failed to query registry path (read): %1").arg(res, 0, 16)); - } - - return result; -} - -QString GameGamebryo::findInRegistry(HKEY baseKey, LPCWSTR path, LPCWSTR value) -{ - std::unique_ptr<BYTE[]> buffer = - getRegValue(baseKey, path, value, RRF_RT_REG_SZ | RRF_NOEXPAND); - - return QString::fromUtf16(reinterpret_cast<const ushort*>(buffer.get())); -} - -QString GameGamebryo::getKnownFolderPath(REFKNOWNFOLDERID folderId, bool useDefault) -{ - PWSTR path = nullptr; - ON_BLOCK_EXIT([&]() { - if (path != nullptr) - ::CoTaskMemFree(path); - }); - - if (::SHGetKnownFolderPath(folderId, useDefault ? KF_FLAG_DEFAULT_PATH : 0, NULL, - &path) == S_OK) { - return QDir::fromNativeSeparators(QString::fromWCharArray(path)); - } else { - return QString(); - } -} - -QString GameGamebryo::getSpecialPath(const QString& name) -{ - QString base = findInRegistry( - HKEY_CURRENT_USER, - L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders", - name.toStdWString().c_str()); - - WCHAR temp[MAX_PATH]; - if (::ExpandEnvironmentStringsW(base.toStdWString().c_str(), temp, MAX_PATH) != 0) { - return QString::fromWCharArray(temp); - } else { - return base; - } -} - -QString GameGamebryo::determineMyGamesPath(const QString& gameName) -{ - const QString pattern = "%1/My Games/" + gameName; - - auto tryDir = [&](const QString& dir) -> std::optional<QString> { - if (dir.isEmpty()) { - return {}; - } - - const auto path = pattern.arg(dir); - if (!QFileInfo(path).exists()) { - return {}; - } - - return path; - }; - - // a) this is the way it should work. get the configured My Documents directory - if (auto d = tryDir(getKnownFolderPath(FOLDERID_Documents, false))) { - return *d; - } - - // b) if there is no <game> directory there, look in the default directory - if (auto d = tryDir(getKnownFolderPath(FOLDERID_Documents, true))) { - return *d; - } - - // c) finally, look in the registry. This is discouraged - if (auto d = tryDir(getSpecialPath("Personal"))) { - return *d; - } - - return {}; -} - -QString GameGamebryo::parseEpicGamesLocation(const QStringList& manifests) -{ - // Use the registry entry to find the EGL Data dir first, just in case something - // changes - QString manifestDir = findInRegistry( - HKEY_LOCAL_MACHINE, L"Software\\Epic Games\\EpicGamesLauncher", L"AppDataPath"); - if (manifestDir.isEmpty()) - manifestDir = getKnownFolderPath(FOLDERID_ProgramData, false) + - "\\Epic\\EpicGamesLauncher\\Data\\"; - manifestDir += "Manifests"; - QDir epicManifests(manifestDir, "*.item", - QDir::SortFlags(QDir::Name | QDir::IgnoreCase), QDir::Files); - if (epicManifests.exists()) { - QDirIterator it(epicManifests); - while (it.hasNext()) { - QString manifestFile = it.next(); - QFile manifest(manifestFile); - - if (!manifest.open(QIODevice::ReadOnly)) { - qWarning("Couldn't open Epic Games manifest file."); - continue; - } - - QByteArray manifestData = manifest.readAll(); - - QJsonDocument manifestJson(QJsonDocument::fromJson(manifestData)); - - if (manifests.contains(manifestJson["AppName"].toString())) { - return manifestJson["InstallLocation"].toString(); - } - } - } - return ""; -} - -QString GameGamebryo::parseSteamLocation(const QString& appid, - const QString& directoryName) -{ - QString path = "Software\\Valve\\Steam"; - QString steamLocation = - findInRegistry(HKEY_CURRENT_USER, path.toStdWString().c_str(), L"SteamPath"); - if (!steamLocation.isEmpty()) { - QString steamLibraryLocation; - QString steamLibraries(steamLocation + "\\" + "config" + "\\" + - "libraryfolders.vdf"); - if (QFile(steamLibraries).exists()) { - std::ifstream file(steamLibraries.toStdString()); - auto root = tyti::vdf::read(file); - for (auto child : root.childs) { - tyti::vdf::object* library = child.second.get(); - auto apps = library->childs["apps"]; - if (apps->attribs.contains(appid.toStdString())) { - steamLibraryLocation = QString::fromStdString(library->attribs["path"]); - break; - } - } - } - if (!steamLibraryLocation.isEmpty()) { - QString gameLocation = steamLibraryLocation + "\\" + "steamapps" + "\\" + - "common" + "\\" + directoryName; - if (QDir(gameLocation).exists()) - return gameLocation; - } - } - return ""; -} - -void GameGamebryo::registerFeature(std::shared_ptr<MOBase::GameFeature> feature) -{ - // priority does not matter, this is a game plugin so will get lowest priority in MO2 - m_Organizer->gameFeatures()->registerFeature(this, feature, 0, true); -} diff --git a/libs/game_gamebryo/src/gamebryo/gamegamebryo.h b/libs/game_gamebryo/src/gamebryo/gamegamebryo.h deleted file mode 100644 index 2ff07db..0000000 --- a/libs/game_gamebryo/src/gamebryo/gamegamebryo.h +++ /dev/null @@ -1,151 +0,0 @@ -#ifndef GAMEGAMEBRYO_H -#define GAMEGAMEBRYO_H - -#include "iplugingame.h" - -class BSAInvalidation; -class DataArchives; -class LocalSavegames; -class SaveGameInfo; -class BSAInvalidation; -class LocalSavegames; -class ScriptExtender; -class GamePlugins; -class UnmanagedMods; - -#include <QObject> -#include <QString> -#include <ShlObj.h> -#include <dbghelp.h> -#include <ipluginfilemapper.h> -#include <iplugingame.h> -#include <memory> - -#include "gamebryosavegame.h" -#include "igamefeatures.h" - -class GameGamebryo : public MOBase::IPluginGame, public MOBase::IPluginFileMapper -{ - Q_OBJECT - Q_INTERFACES(MOBase::IPlugin MOBase::IPluginGame MOBase::IPluginFileMapper) - - friend class GamebryoScriptExtender; - friend class GamebryoSaveGameInfo; - friend class GamebryoSaveGameInfoWidget; - friend class GamebryoSaveGame; - - /** - * Some Bethesda games do not have a valid file version but a valid product - * version. If the file version starts with FALLBACK_GAME_VERSION, the product - * version will be tried. - */ - static constexpr const char* FALLBACK_GAME_VERSION = "1.0.0"; - -public: - GameGamebryo(); - - void detectGame() override; - bool init(MOBase::IOrganizer* moInfo) override; - -public: // IPluginGame interface - // getName - // initializeProfile - virtual std::vector<std::shared_ptr<const MOBase::ISaveGame>> - listSaves(QDir folder) const override; - - virtual bool isInstalled() const override; - virtual QIcon gameIcon() const override; - virtual QDir gameDirectory() const override; - virtual QDir dataDirectory() const override; - // secondaryDataDirectories - virtual void setGamePath(const QString& path) override; - virtual QDir documentsDirectory() const override; - virtual QDir savesDirectory() const override; - // executables - // steamAPPId - // primaryPlugins - // enabledPlugins - // gameVariants - virtual void setGameVariant(const QString& variant) override; - virtual QString binaryName() const override; - // gameShortName - // primarySources - // validShortNames - // iniFiles - // DLCPlugins - // CCPlugins - virtual LoadOrderMechanism loadOrderMechanism() const override; - virtual SortMechanism sortMechanism() const override; - // nexusModOrganizerID - // nexusGameID - virtual bool looksValid(QDir const&) const override; - virtual QString gameVersion() const override; - virtual QString getLauncherName() const override; - -public: // IPluginFileMapper interface - virtual MappingType mappings() const; - -public: // Other (e.g. for game features) - QString myGamesPath() const; - -protected: - // Retrieve the saves extension for the game. - virtual QString savegameExtension() const = 0; - virtual QString savegameSEExtension() const = 0; - - // Create a save game. - virtual std::shared_ptr<const GamebryoSaveGame> - makeSaveGame(QString filepath) const = 0; - - QFileInfo findInGameFolder(const QString& relativePath) const; - QString selectedVariant() const; - WORD getArch(QString const& program) const; - - static QString localAppFolder(); - // Arguably this shouldn't really be here but every gamebryo program seems to - // use it - static QString getLootPath(); - - // This function is not terribly well named as it copies exactly where it's told - // to, irrespective of whether it's in the profile... - static void copyToProfile(const QString& sourcePath, const QDir& destinationDirectory, - const QString& sourceFileName); - - static void copyToProfile(const QString& sourcePath, const QDir& destinationDirectory, - const QString& sourceFileName, - const QString& destinationFileName); - - virtual QString identifyGamePath() const; - - virtual bool prepareIni(const QString& exec); - - static std::unique_ptr<BYTE[]> getRegValue(HKEY key, LPCWSTR path, LPCWSTR value, - DWORD flags, LPDWORD type); - - static QString findInRegistry(HKEY baseKey, LPCWSTR path, LPCWSTR value); - - static QString getKnownFolderPath(REFKNOWNFOLDERID folderId, bool useDefault); - - static QString getSpecialPath(const QString& name); - - static QString determineMyGamesPath(const QString& gameName); - - static QString parseEpicGamesLocation(const QStringList& manifests); - - static QString parseSteamLocation(const QString& appid, const QString& directoryName); - -protected: - void registerFeature(std::shared_ptr<MOBase::GameFeature> feature); - -protected: - // to access organizer for game features, avoid having to pass it to all saves since - // we already pass the game - friend class GamebryoSaveGame; - - QString m_GamePath; - QString m_MyGamesPath; - QString m_GameVariant; - MOBase::IOrganizer* m_Organizer; -}; - -#endif // GAMEGAMEBRYO_H diff --git a/libs/game_gamebryo/src/gamebryo/vdf_parser.h b/libs/game_gamebryo/src/gamebryo/vdf_parser.h deleted file mode 100644 index 32d4d27..0000000 --- a/libs/game_gamebryo/src/gamebryo/vdf_parser.h +++ /dev/null @@ -1,739 +0,0 @@ -// MIT License -// -// Copyright(c) 2016 Matthias Moeller -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#ifndef __TYTI_STEAM_VDF_PARSER_H__ -#define __TYTI_STEAM_VDF_PARSER_H__ - -#include <algorithm> -#include <fstream> -#include <functional> -#include <iterator> -#include <map> -#include <memory> -#include <unordered_map> -#include <unordered_set> -#include <utility> -#include <vector> - -#include <exception> -#include <system_error> - -// for wstring support -#include <locale> -#include <string> - -// internal -#include <stack> - -// VS < 2015 has only partial C++11 support -#if defined(_MSC_VER) && _MSC_VER < 1900 -#ifndef CONSTEXPR -#define CONSTEXPR -#endif - -#ifndef NOEXCEPT -#define NOEXCEPT -#endif -#else -#ifndef CONSTEXPR -#define CONSTEXPR constexpr -#define TYTI_UNDEF_CONSTEXPR -#endif - -#ifndef NOEXCEPT -#define NOEXCEPT noexcept -#define TYTI_UNDEF_NOEXCEPT -#endif - -#endif - -namespace tyti -{ -namespace vdf -{ - namespace detail - { - /////////////////////////////////////////////////////////////////////////// - // Helper functions selecting the right encoding (char/wchar_T) - /////////////////////////////////////////////////////////////////////////// - - template <typename T> - struct literal_macro_help - { - static CONSTEXPR const char* result(const char* c, const wchar_t*) NOEXCEPT - { - return c; - } - static CONSTEXPR const char result(const char c, const wchar_t) NOEXCEPT - { - return c; - } - }; - - template <> - struct literal_macro_help<wchar_t> - { - static CONSTEXPR const wchar_t* result(const char*, const wchar_t* wc) NOEXCEPT - { - return wc; - } - static CONSTEXPR const wchar_t result(const char, const wchar_t wc) NOEXCEPT - { - return wc; - } - }; -#define TYTI_L(type, text) vdf::detail::literal_macro_help<type>::result(text, L##text) - - inline std::string string_converter(const std::string& w) NOEXCEPT - { - return w; - } - - // utility wrapper to adapt locale-bound facets for wstring/wbuffer convert - // from cppreference - template <class Facet> - struct deletable_facet : Facet - { - template <class... Args> - deletable_facet(Args&&... args) : Facet(std::forward<Args>(args)...) - {} - ~deletable_facet() {} - }; - - inline std::string string_converter(const std::wstring& w) // todo: use us-locale - { - std::wstring_convert<deletable_facet<std::codecvt<wchar_t, char, std::mbstate_t>>> - conv1; - return conv1.to_bytes(w); - } - - /////////////////////////////////////////////////////////////////////////// - // Writer helper functions - /////////////////////////////////////////////////////////////////////////// - - template <typename charT> - class tabs - { - const size_t t; - - public: - explicit CONSTEXPR tabs(size_t i) NOEXCEPT : t(i) {} - std::basic_string<charT> print() const - { - return std::basic_string<charT>(t, TYTI_L(charT, '\t')); - } - inline CONSTEXPR tabs operator+(size_t i) const NOEXCEPT { return tabs(t + i); } - }; - - template <typename oStreamT> - oStreamT& operator<<(oStreamT& s, const tabs<typename oStreamT::char_type> t) - { - s << t.print(); - return s; - } - } // end namespace detail - - /////////////////////////////////////////////////////////////////////////// - // Interface - /////////////////////////////////////////////////////////////////////////// - - /// custom objects and their corresponding write functions - - /// basic object node. Every object has a name and can contains attributes saved as - /// key_value pairs or childrens - template <typename CharT> - struct basic_object - { - typedef CharT char_type; - std::basic_string<char_type> name; - std::unordered_map<std::basic_string<char_type>, std::basic_string<char_type>> - attribs; - std::unordered_map<std::basic_string<char_type>, - std::shared_ptr<basic_object<char_type>>> - childs; - - void add_attribute(std::basic_string<char_type> key, - std::basic_string<char_type> value) - { - attribs.emplace(std::move(key), std::move(value)); - } - void add_child(std::unique_ptr<basic_object<char_type>> child) - { - std::shared_ptr<basic_object<char_type>> obj{child.release()}; - childs.emplace(obj->name, obj); - } - void set_name(std::basic_string<char_type> n) { name = std::move(n); } - }; - - template <typename CharT> - struct basic_multikey_object - { - typedef CharT char_type; - std::basic_string<char_type> name; - std::unordered_multimap<std::basic_string<char_type>, std::basic_string<char_type>> - attribs; - std::unordered_multimap<std::basic_string<char_type>, - std::shared_ptr<basic_multikey_object<char_type>>> - childs; - - void add_attribute(std::basic_string<char_type> key, - std::basic_string<char_type> value) - { - attribs.emplace(std::move(key), std::move(value)); - } - void add_child(std::unique_ptr<basic_multikey_object<char_type>> child) - { - std::shared_ptr<basic_multikey_object<char_type>> obj{child.release()}; - childs.emplace(obj->name, obj); - } - void set_name(std::basic_string<char_type> n) { name = std::move(n); } - }; - - typedef basic_object<char> object; - typedef basic_object<wchar_t> wobject; - typedef basic_multikey_object<char> multikey_object; - typedef basic_multikey_object<wchar_t> wmultikey_object; - - struct Options - { - bool strip_escape_symbols; - bool ignore_all_platform_conditionals; - bool ignore_includes; - - Options() - : strip_escape_symbols(true), ignore_all_platform_conditionals(false), - ignore_includes(false) - {} - }; - - // forward decls - // forward decl - template <typename OutputT, typename iStreamT> - OutputT read(iStreamT& inStream, const Options& opt = Options{}); - - /** \brief writes given object tree in vdf format to given stream. - Output is prettyfied, using tabs - */ - template <typename oStreamT, typename T> - void write(oStreamT& s, const T& r, - const detail::tabs<typename oStreamT::char_type> tab = - detail::tabs<typename oStreamT::char_type>(0)) - { - typedef typename oStreamT::char_type charT; - using namespace detail; - s << tab << TYTI_L(charT, '"') << r.name << TYTI_L(charT, "\"\n") << tab - << TYTI_L(charT, "{\n"); - for (const auto& i : r.attribs) - s << tab + 1 << TYTI_L(charT, '"') << i.first << TYTI_L(charT, "\"\t\t\"") - << i.second << TYTI_L(charT, "\"\n"); - for (const auto& i : r.childs) - if (i.second) - write(s, *i.second, tab + 1); - s << tab << TYTI_L(charT, "}\n"); - } - - namespace detail - { - template <typename iStreamT> - std::basic_string<typename iStreamT::char_type> read_file(iStreamT& inStream) - { - // cache the file - typedef typename iStreamT::char_type charT; - std::basic_string<charT> str; - inStream.seekg(0, std::ios::end); - str.resize(static_cast<size_t>(inStream.tellg())); - if (str.empty()) - return str; - - inStream.seekg(0, std::ios::beg); - inStream.read(&str[0], str.size()); - return str; - } - - /** \brief Read VDF formatted sequences defined by the range [first, last). - If the file is mailformatted, parser will try to read it until it can. - @param first begin iterator - @param end end iterator - @param exclude_files list of files which cant be included anymore. - prevents circular includes - - can thow: - - "std::runtime_error" if a parsing error occured - - "std::bad_alloc" if not enough memory coup be allocated - */ - template <typename OutputT, typename IterT> - std::vector<std::unique_ptr<OutputT>> - read_internal(IterT first, const IterT last, - std::unordered_set<std::basic_string< - typename std::iterator_traits<IterT>::value_type>>& exclude_files, - const Options& opt) - { - static_assert(std::is_default_constructible<OutputT>::value, - "Output Type must be default constructible (provide constructor " - "without arguments)"); - static_assert(std::is_move_constructible<OutputT>::value, - "Output Type must be move constructible"); - - typedef typename std::iterator_traits<IterT>::value_type charT; - - const std::basic_string<charT> comment_end_str = TYTI_L(charT, "*/"); - const std::basic_string<charT> whitespaces = TYTI_L(charT, " \n\v\f\r\t"); - -#ifdef WIN32 - std::function<bool(const std::basic_string<charT>&)> is_platform_str = - [](const std::basic_string<charT>& in) { - return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$WINDOWS"); - }; -#elif __APPLE__ - // WIN32 stands for pc in general - std::function<bool(const std::basic_string<charT>&)> is_platform_str = - [](const std::basic_string<charT>& in) { - return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") || - in == TYTI_L(charT, "$OSX"); - }; - -#elif __linux__ - // WIN32 stands for pc in general - std::function<bool(const std::basic_string<charT>&)> is_platform_str = - [](const std::basic_string<charT>& in) { - return in == TYTI_L(charT, "$WIN32") || in == TYTI_L(charT, "$POSIX") || - in == TYTI_L(charT, "$LINUX"); - }; -#else - std::function<bool(const std::basic_string<charT>&)> is_platform_str = - [](const std::basic_string<charT>& in) { - return false; - }; -#endif - - if (opt.ignore_all_platform_conditionals) - is_platform_str = [](const std::basic_string<charT>&) { - return false; - }; - - // function for skipping a comment block - // iter: iterator poition to the position after a '/' - auto skip_comments = [&comment_end_str](IterT iter, const IterT& last) -> IterT { - ++iter; - if (iter != last) { - if (*iter == TYTI_L(charT, '/')) { - // line comment, skip whole line - iter = std::find(iter + 1, last, TYTI_L(charT, '\n')); - } - - if (*iter == '*') { - // block comment, skip until next occurance of "*\" - iter = std::search(iter + 1, last, std::begin(comment_end_str), - std::end(comment_end_str)); - iter += 2; - } - } - return iter; - }; - - auto end_quote = [](IterT iter, const IterT& last) -> IterT { - const auto begin = iter; - auto last_esc = iter; - do { - ++iter; - iter = std::find(iter, last, TYTI_L(charT, '\"')); - if (iter == last) - break; - - last_esc = std::prev(iter); - while (last_esc != begin && *last_esc == '\\') - --last_esc; - } while (!(std::distance(last_esc, iter) % 2)); - if (iter == last) - throw std::runtime_error{"quote was opened but not closed."}; - return iter; - }; - - auto end_word = [&whitespaces](IterT iter, const IterT& last) -> IterT { - const auto begin = iter; - auto last_esc = iter; - do { - ++iter; - iter = std::find_first_of(iter, last, std::begin(whitespaces), - std::end(whitespaces)); - if (iter == last) - break; - - last_esc = std::prev(iter); - while (last_esc != begin && *last_esc == '\\') - --last_esc; - } while (!(std::distance(last_esc, iter) % 2)); - // if (iter == last) - // throw std::runtime_error{ "word wasnt properly ended" }; - return iter; - }; - - auto skip_whitespaces = [&whitespaces](IterT iter, const IterT& last) -> IterT { - iter = std::find_if_not(iter, last, [&whitespaces](charT c) { - // return true if whitespace - return std::any_of(std::begin(whitespaces), std::end(whitespaces), - [c](charT pc) { - return pc == c; - }); - }); - return iter; - }; - - std::function<void(std::basic_string<charT>&)> strip_escape_symbols = - [](std::basic_string<charT>& s) { - auto quote_searcher = [&s](size_t pos) { - return s.find(TYTI_L(charT, "\\\""), pos); - }; - auto p = quote_searcher(0); - while (p != s.npos) { - s.replace(p, 2, TYTI_L(charT, "\"")); - p = quote_searcher(p); - } - auto searcher = [&s](size_t pos) { - return s.find(TYTI_L(charT, "\\\\"), pos); - }; - p = searcher(0); - while (p != s.npos) { - s.replace(p, 2, TYTI_L(charT, "\\")); - p = searcher(p); - } - }; - - if (!opt.strip_escape_symbols) - strip_escape_symbols = [](std::basic_string<charT>&) {}; - - auto conditional_fullfilled = [&skip_whitespaces, - &is_platform_str](IterT& iter, const IterT& last) { - iter = skip_whitespaces(iter, last); - if (*iter == '[') { - ++iter; - const auto end = std::find(iter, last, ']'); - const bool negate = *iter == '!'; - if (negate) - ++iter; - auto conditional = std::basic_string<charT>(iter, end); - - const bool is_platform = is_platform_str(conditional); - iter = end + 1; - - return static_cast<bool>(is_platform ^ negate); - } - return true; - }; - - // read header - // first, quoted name - std::unique_ptr<OutputT> curObj = nullptr; - std::vector<std::unique_ptr<OutputT>> roots; - std::stack<std::unique_ptr<OutputT>> lvls; - auto curIter = first; - - while (curIter != last && *curIter != '\0') { - // find first starting attrib/child, or ending - curIter = skip_whitespaces(curIter, last); - if (curIter == last || *curIter == '\0') - break; - if (*curIter == TYTI_L(charT, '/')) { - curIter = skip_comments(curIter, last); - } else if (*curIter != TYTI_L(charT, '}')) { - - // get key - const auto keyEnd = (*curIter == TYTI_L(charT, '\"')) - ? end_quote(curIter, last) - : end_word(curIter, last); - if (*curIter == TYTI_L(charT, '\"')) - ++curIter; - std::basic_string<charT> key(curIter, keyEnd); - strip_escape_symbols(key); - curIter = keyEnd + ((*keyEnd == TYTI_L(charT, '\"')) ? 1 : 0); - - curIter = skip_whitespaces(curIter, last); - - auto conditional = conditional_fullfilled(curIter, last); - if (!conditional) - continue; - - while (*curIter == TYTI_L(charT, '/')) { - - curIter = skip_comments(curIter, last); - if (curIter == last || *curIter == '}') - throw std::runtime_error{"key declared, but no value"}; - curIter = skip_whitespaces(curIter, last); - if (curIter == last || *curIter == '}') - throw std::runtime_error{"key declared, but no value"}; - } - // get value - if (*curIter != '{') { - const auto valueEnd = (*curIter == TYTI_L(charT, '\"')) - ? end_quote(curIter, last) - : end_word(curIter, last); - if (*curIter == TYTI_L(charT, '\"')) - ++curIter; - - auto value = std::basic_string<charT>(curIter, valueEnd); - strip_escape_symbols(value); - curIter = valueEnd + ((*valueEnd == TYTI_L(charT, '\"')) ? 1 : 0); - - auto conditional = conditional_fullfilled(curIter, last); - if (!conditional) - continue; - - // process value - if (key != TYTI_L(charT, "#include") && key != TYTI_L(charT, "#base")) { - if (curObj) { - curObj->add_attribute(std::move(key), std::move(value)); - } else { - throw std::runtime_error{"unexpected key without object"}; - } - } else { - if (!opt.ignore_includes && - exclude_files.find(value) == exclude_files.end()) { - exclude_files.insert(value); - std::basic_ifstream<charT> i(detail::string_converter(value)); - auto str = read_file(i); - auto file_objs = - read_internal<OutputT>(str.begin(), str.end(), exclude_files, opt); - for (auto& n : file_objs) { - if (curObj) - curObj->add_child(std::move(n)); - else - roots.push_back(std::move(n)); - } - exclude_files.erase(value); - } - } - } else if (*curIter == '{') { - if (curObj) - lvls.push(std::move(curObj)); - curObj = std::make_unique<OutputT>(); - curObj->set_name(std::move(key)); - ++curIter; - } - } - // end of new object - else if (curObj && *curIter == TYTI_L(charT, '}')) { - if (!lvls.empty()) { - // get object before - std::unique_ptr<OutputT> prev{std::move(lvls.top())}; - lvls.pop(); - - // add finished obj to obj before and release it from processing - prev->add_child(std::move(curObj)); - curObj = std::move(prev); - } else { - roots.push_back(std::move(curObj)); - curObj.reset(); - } - ++curIter; - } else { - throw std::runtime_error{"unexpected '}'"}; - } - } - if (curObj != nullptr || !lvls.empty()) { - throw std::runtime_error{"object is not closed with '}'"}; - } - - return roots; - } - - } // namespace detail - - /** \brief Read VDF formatted sequences defined by the range [first, last). - If the file is mailformatted, parser will try to read it until it can. - @param first begin iterator - @param end end iterator - - can thow: - - "std::runtime_error" if a parsing error occured - - "std::bad_alloc" if not enough memory coup be allocated - */ - template <typename OutputT, typename IterT> - OutputT read(IterT first, const IterT last, const Options& opt = Options{}) - { - auto exclude_files = std::unordered_set< - std::basic_string<typename std::iterator_traits<IterT>::value_type>>{}; - auto roots = detail::read_internal<OutputT>(first, last, exclude_files, opt); - - OutputT result; - if (roots.size() > 1) { - for (auto& i : roots) - result.add_child(std::move(i)); - } else if (roots.size() == 1) - result = std::move(*roots[0]); - - return result; - } - - /** \brief Read VDF formatted sequences defined by the range [first, last). - If the file is mailformatted, parser will try to read it until it can. - @param first begin iterator - @param end end iterator - @param ec output bool. 0 if ok, otherwise, holds an system error code - - Possible error codes: - std::errc::protocol_error: file is mailformatted - std::errc::not_enough_memory: not enough space - std::errc::invalid_argument: iterators throws e.g. out of range - */ - template <typename OutputT, typename IterT> - OutputT read(IterT first, IterT last, std::error_code& ec, - const Options& opt = Options{}) NOEXCEPT - - { - ec.clear(); - OutputT r{}; - try { - r = read<OutputT>(first, last, opt); - } catch (std::runtime_error&) { - ec = std::make_error_code(std::errc::protocol_error); - } catch (std::bad_alloc&) { - ec = std::make_error_code(std::errc::not_enough_memory); - } catch (...) { - ec = std::make_error_code(std::errc::invalid_argument); - } - return r; - } - - /** \brief Read VDF formatted sequences defined by the range [first, last). - If the file is mailformatted, parser will try to read it until it can. - @param first begin iterator - @param end end iterator - @param ok output bool. true, if parser successed, false, if parser failed - */ - template <typename OutputT, typename IterT> - OutputT read(IterT first, const IterT last, bool* ok, - const Options& opt = Options{}) NOEXCEPT - { - std::error_code ec; - auto r = read<OutputT>(first, last, ec, opt); - if (ok) - *ok = !ec; - return r; - } - - template <typename IterT> - inline auto read(IterT first, const IterT last, bool* ok, - const Options& opt = Options{}) NOEXCEPT - ->basic_object<typename std::iterator_traits<IterT>::value_type> - { - return read<basic_object<typename std::iterator_traits<IterT>::value_type>>( - first, last, ok, opt); - } - - template <typename IterT> - inline auto read(IterT first, IterT last, std::error_code& ec, - const Options& opt = Options{}) NOEXCEPT - ->basic_object<typename std::iterator_traits<IterT>::value_type> - { - return read<basic_object<typename std::iterator_traits<IterT>::value_type>>( - first, last, ec, opt); - } - - template <typename IterT> - inline auto read(IterT first, const IterT last, const Options& opt = Options{}) - -> basic_object<typename std::iterator_traits<IterT>::value_type> - { - return read<basic_object<typename std::iterator_traits<IterT>::value_type>>( - first, last, opt); - } - - /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf - formatted data. throws "std::bad_alloc" if file buffer could not be allocated - */ - template <typename OutputT, typename iStreamT> - OutputT read(iStreamT& inStream, std::error_code& ec, const Options& opt = Options{}) - { - // cache the file - typedef typename iStreamT::char_type charT; - std::basic_string<charT> str = detail::read_file(inStream); - - // parse it - return read<OutputT>(str.begin(), str.end(), ec, opt); - } - - template <typename iStreamT> - inline basic_object<typename iStreamT::char_type> - read(iStreamT& inStream, std::error_code& ec, const Options& opt = Options{}) - { - return read<basic_object<typename iStreamT::char_type>>(inStream, ec, opt); - } - - /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf - formatted data. throws "std::bad_alloc" if file buffer could not be allocated ok == - false, if a parsing error occured - */ - template <typename OutputT, typename iStreamT> - OutputT read(iStreamT& inStream, bool* ok, const Options& opt = Options{}) - { - std::error_code ec; - const auto r = read<OutputT>(inStream, ec, opt); - if (ok) - *ok = !ec; - return r; - } - - template <typename iStreamT> - inline basic_object<typename iStreamT::char_type> read(iStreamT& inStream, bool* ok, - const Options& opt = Options{}) - { - return read<basic_object<typename iStreamT::char_type>>(inStream, ok, opt); - } - - /** \brief Loads a stream (e.g. filestream) into the memory and parses the vdf - formatted data. throws "std::bad_alloc" if file buffer could not be allocated - throws "std::runtime_error" if a parsing error occured - */ - template <typename OutputT, typename iStreamT> - OutputT read(iStreamT& inStream, const Options& opt) - { - - // cache the file - typedef typename iStreamT::char_type charT; - std::basic_string<charT> str = detail::read_file(inStream); - // parse it - return read<OutputT>(str.begin(), str.end(), opt); - } - - template <typename iStreamT> - inline basic_object<typename iStreamT::char_type> read(iStreamT& inStream, - const Options& opt = Options{}) - { - return read<basic_object<typename iStreamT::char_type>>(inStream, opt); - } - -} // namespace vdf -} // namespace tyti -#ifndef TYTI_NO_L_UNDEF -#undef TYTI_L -#endif - -#ifdef TYTI_UNDEF_CONSTEXPR -#undef CONSTEXPR -#undef TYTI_NO_L_UNDEF -#endif - -#ifdef TYTI_UNDEF_NOTHROW -#undef NOTHROW -#undef TYTI_UNDEF_NOTHROW -#endif - -#endif //__TYTI_STEAM_VDF_PARSER_H__ |
