diff options
| -rw-r--r-- | CMakeLists.txt | 3 | ||||
| -rw-r--r-- | libs/installer_fomod/src/fomodinstallerdialog.cpp | 21 | ||||
| -rw-r--r-- | libs/installer_fomod/src/installerfomod.cpp | 15 | ||||
| -rw-r--r-- | src/src/prefixsetuprunner.cpp | 20 | ||||
| -rw-r--r-- | src/tests/test_vfs_file_ops.cpp | 26 |
5 files changed, 54 insertions, 31 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ec1a74..ebb415d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,7 @@ if(HAS_NO_DIRECT_EXTERN_ACCESS) endif() option(BUILD_TESTING "Build tests" OFF) +option(BUILD_FLUORINE_TESTING "Build Fluorine standalone tests" OFF) option(BUILD_BSA_FFI "Build Rust BSA/BA2 FFI library" ON) option(BUILD_DOTNET_PLUGINS "Build C++/CLI .NET plugins (Windows+MSVC only)" OFF) option(BUILD_PLUGIN_PYTHON "Build plugin_python bridge on Linux" ON) @@ -285,7 +286,7 @@ endif() # Main organizer executable add_subdirectory(src/src) -if (BUILD_TESTING) +if (BUILD_FLUORINE_TESTING) enable_testing() add_subdirectory(src/tests) endif() diff --git a/libs/installer_fomod/src/fomodinstallerdialog.cpp b/libs/installer_fomod/src/fomodinstallerdialog.cpp index 7c27726..9e3eaaa 100644 --- a/libs/installer_fomod/src/fomodinstallerdialog.cpp +++ b/libs/installer_fomod/src/fomodinstallerdialog.cpp @@ -166,6 +166,21 @@ static QString tempArchivePath(const QString& archivePath) return QDir(QDir::tempPath()).filePath(normalizeArchivePath(archivePath)); } +static QString fomodFilePath(const QString& fomodPath, const QString& fomodDirName, + const QString& fileName) +{ + const QString directory = tempArchivePath(joinArchivePath(fomodPath, fomodDirName)); + const QDir dir(directory); + + for (const QString& candidate : dir.entryList(QDir::Files | QDir::NoDotAndDotDot)) { + if (candidate.compare(fileName, Qt::CaseInsensitive) == 0) { + return dir.filePath(candidate); + } + } + + return dir.filePath(fileName); +} + QByteArray skipXmlHeader(QIODevice& file) { static const unsigned char UTF16LE_BOM[] = {0xFF, 0xFE}; @@ -265,8 +280,7 @@ void FomodInstallerDialog::readXml(QFile& file, void FomodInstallerDialog::readInfoXml() { - QFile file(tempArchivePath(joinArchivePath( - joinArchivePath(m_FomodPath, m_FomodDirName), "info.xml"))); + QFile file(fomodFilePath(m_FomodPath, m_FomodDirName, "info.xml")); // We don't need a info.xml file, so we just return if we cannot open it: if (!file.open(QIODevice::ReadOnly)) { @@ -277,8 +291,7 @@ void FomodInstallerDialog::readInfoXml() void FomodInstallerDialog::readModuleConfigXml() { - QFile file(tempArchivePath(joinArchivePath( - joinArchivePath(m_FomodPath, m_FomodDirName), "ModuleConfig.xml"))); + QFile file(fomodFilePath(m_FomodPath, m_FomodDirName, "ModuleConfig.xml")); if (!file.open(QIODevice::ReadOnly)) { throw Exception(tr("%1 missing.").arg(file.fileName())); } diff --git a/libs/installer_fomod/src/installerfomod.cpp b/libs/installer_fomod/src/installerfomod.cpp index e526610..9d9690a 100644 --- a/libs/installer_fomod/src/installerfomod.cpp +++ b/libs/installer_fomod/src/installerfomod.cpp @@ -1,5 +1,7 @@ #include "installerfomod.h" +#include <algorithm> + #include <QImageReader> #include <QStringList> #include <QtPlugin> @@ -115,10 +117,14 @@ InstallerFomod::findFomodDirectory(std::shared_ptr<const IFileTree> tree) const bool InstallerFomod::isArchiveSupported(std::shared_ptr<const IFileTree> tree) const { tree = findFomodDirectory(tree); - if (tree != nullptr) { - return tree->exists("ModuleConfig.xml", FileTreeEntry::FILE); + if (tree == nullptr) { + return false; } - return false; + + return std::any_of(tree->begin(), tree->end(), [](const auto& entry) { + return entry->isFile() && + entry->name().compare("ModuleConfig.xml", Qt::CaseInsensitive) == 0; + }); } void InstallerFomod::appendImageFiles( @@ -145,7 +151,8 @@ InstallerFomod::buildFomodTree(std::shared_ptr<const IFileTree> tree) const for (auto entry : *fomodTree) { if (entry->isFile() && - (entry->compare("info.xml") == 0 || entry->compare("ModuleConfig.xml") == 0)) { + (entry->name().compare("info.xml", Qt::CaseInsensitive) == 0 || + entry->name().compare("ModuleConfig.xml", Qt::CaseInsensitive) == 0)) { entries.push_back(entry); } } diff --git a/src/src/prefixsetuprunner.cpp b/src/src/prefixsetuprunner.cpp index f599a30..d6ce33e 100644 --- a/src/src/prefixsetuprunner.cpp +++ b/src/src/prefixsetuprunner.cpp @@ -220,19 +220,6 @@ static const char* DOTNET8_X64_URL = "https://download.visualstudio.microsoft.com/download/pr/136f4593-e3cd-4d52-bc25-579cdf46e80c/" "8b98c1347293b48c56c3a68d72f586a1/dotnet-runtime-8.0.12-win-x64.exe"; -static const char* DOTNET_DESKTOP6_X86_URL = - "https://download.visualstudio.microsoft.com/download/pr/cdc314df-4a4c-4709-868d-b974f336f77f/" - "acd5ab7637e456c8a3aa667661324f6d/windowsdesktop-runtime-6.0.36-win-x86.exe"; -static const char* DOTNET_DESKTOP6_X64_URL = - "https://download.visualstudio.microsoft.com/download/pr/f6b6c5dc-e02d-4738-9559-296e938dabcb/" - "b66d365729359df8e8ea131197715076/windowsdesktop-runtime-6.0.36-win-x64.exe"; - -static const QStringList DOTNET_DESKTOP6_X86_SHA256 = { - QStringLiteral("4e77bd970df0a06528ee88d33e4a8c9fb85beedbdd7219b017083acf0c3aa39e"), -}; -static const QStringList DOTNET_DESKTOP6_X64_SHA256 = { - QStringLiteral("0d20debb26fc8b2bc84f25fbd9d4596a6364af8517ebf012e8b871127b798941"), -}; static const QStringList DOTNET6_X86_SHA256 = { QStringLiteral("3b3cb4636251a582158f4b6b340f20b3861e6793eb9a3e64bda29cbf32da3604"), }; @@ -682,13 +669,6 @@ void PrefixSetupRunner::buildStepList() // Runtime installers (run via Wine). addStep("vcrun2022", "Visual C++ 2022", [this] { return stepVcrun2022(); }); - addStep("dotnetdesktop6", ".NET Desktop Runtime 6", - [this] { - return stepDotNetInstallPair( - DOTNET_DESKTOP6_X86_URL, DOTNET_DESKTOP6_X64_URL, - ".NET Desktop 6", DOTNET_DESKTOP6_X86_SHA256, - DOTNET_DESKTOP6_X64_SHA256); - }); addStep("dotnet_runtimes", ".NET Runtimes (6-9)", [this] { return stepDotNetRuntimes(); }); addStep("dotnet10_sdk", ".NET 10 SDK", diff --git a/src/tests/test_vfs_file_ops.cpp b/src/tests/test_vfs_file_ops.cpp index 9a37f52..56f516a 100644 --- a/src/tests/test_vfs_file_ops.cpp +++ b/src/tests/test_vfs_file_ops.cpp @@ -92,7 +92,7 @@ TEST(VfsFileOps, CreateFileReturnsWritableStagingHandle) OverwriteManager overwriteManager(staging.string(), overwrite.string()); std::string realPath; - const int fd = overwriteManager.createFile("ShaderCache/Lighting/test.pso", + const int fd = overwriteManager.createFile("Data/ShaderCache/Lighting/test.pso", 0600, &realPath); ASSERT_GE(fd, 0); @@ -100,10 +100,32 @@ TEST(VfsFileOps, CreateFileReturnsWritableStagingHandle) ASSERT_EQ(write(fd, payload, sizeof(payload) - 1), ssize_t(sizeof(payload) - 1)); close(fd); - EXPECT_EQ(fs::path(realPath), staging / "ShaderCache/Lighting/test.pso"); + EXPECT_EQ(fs::path(realPath), staging / "Data/ShaderCache/Lighting/test.pso"); EXPECT_EQ(readText(realPath), "shader"); } +TEST(VfsFileOps, CreateShaderCacheFileReusesExistingCaseVariant) +{ + TempRoot tmp; + ASSERT_FALSE(tmp.path().empty()); + + const fs::path staging = tmp.path() / "staging"; + const fs::path overwrite = tmp.path() / "overwrite"; + fs::create_directories(staging / "Data" / "ShaderCache" / "Lighting"); + + OverwriteManager overwriteManager(staging.string(), overwrite.string()); + std::error_code ec; + std::string realPath; + const int fd = overwriteManager.createFile("data/shadercache/lighting/test.pso", + 0600, &realPath, &ec); + ASSERT_GE(fd, 0); + ASSERT_FALSE(ec); + close(fd); + + EXPECT_EQ(fs::path(realPath), + staging / "Data" / "ShaderCache" / "Lighting" / "test.pso"); +} + TEST(VfsFileOps, CreateFileReusesExistingCaseVariant) { TempRoot tmp; |
