From 5c98a340844229ad37e6ca9ca15cd9b56a344889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dar=C3=ADo?= Date: Thu, 16 Jan 2025 12:13:14 -0300 Subject: [PATCH] Improve error message behavior on installer for invalid sources. (#77) --- .../install/directory_file_system.h | 7 +++++++ UnleashedRecomp/install/installer.cpp | 20 +++++++++---------- UnleashedRecomp/install/iso_file_system.cpp | 7 +++++++ UnleashedRecomp/install/iso_file_system.h | 2 ++ UnleashedRecomp/install/virtual_file_system.h | 1 + .../install/xcontent_file_system.cpp | 7 +++++++ .../install/xcontent_file_system.h | 2 ++ UnleashedRecomp/ui/installer_wizard.cpp | 20 ++++++++++++++----- 8 files changed, 51 insertions(+), 15 deletions(-) diff --git a/UnleashedRecomp/install/directory_file_system.h b/UnleashedRecomp/install/directory_file_system.h index 3dadca6..a246351 100644 --- a/UnleashedRecomp/install/directory_file_system.h +++ b/UnleashedRecomp/install/directory_file_system.h @@ -7,10 +7,12 @@ struct DirectoryFileSystem : VirtualFileSystem { std::filesystem::path directoryPath; + std::string name; DirectoryFileSystem(const std::filesystem::path &directoryPath) { this->directoryPath = directoryPath; + name = (const char *)(directoryPath.filename().u8string().data()); } bool load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const override @@ -51,6 +53,11 @@ struct DirectoryFileSystem : VirtualFileSystem return std::filesystem::exists(directoryPath / std::filesystem::path(std::u8string_view((const char8_t *)(path.c_str())))); } + const std::string &getName() const override + { + return name; + } + static std::unique_ptr create(const std::filesystem::path &directoryPath) { if (std::filesystem::exists(directoryPath)) diff --git a/UnleashedRecomp/install/installer.cpp b/UnleashedRecomp/install/installer.cpp index b271b97..923abbf 100644 --- a/UnleashedRecomp/install/installer.cpp +++ b/UnleashedRecomp/install/installer.cpp @@ -73,14 +73,14 @@ static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFi if (!sourceVfs.exists(filename)) { journal.lastResult = Journal::Result::FileMissing; - journal.lastErrorMessage = fmt::format("File {} does not exist in the file system.", filename); + journal.lastErrorMessage = fmt::format("File {} does not exist in {}.", filename, sourceVfs.getName()); return false; } if (!sourceVfs.load(filename, fileData)) { journal.lastResult = Journal::Result::FileReadFailed; - journal.lastErrorMessage = fmt::format("Failed to read file {} from the file system.", filename); + journal.lastErrorMessage = fmt::format("Failed to read file {} from {}.", filename, sourceVfs.getName()); return false; } @@ -96,7 +96,7 @@ static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFi if (!fileHashFound) { journal.lastResult = Journal::Result::FileHashFailed; - journal.lastErrorMessage = fmt::format("File {} from the file system did not match any of the known hashes.", filename); + journal.lastErrorMessage = fmt::format("File {} from {} did not match any of the known hashes.", filename, sourceVfs.getName()); return false; } } @@ -150,7 +150,7 @@ static DLC detectDLC(const std::filesystem::path &sourcePath, VirtualFileSystem if (!sourceVfs.load(DLCValidationFile, dlcXmlBytes)) { journal.lastResult = Journal::Result::FileMissing; - journal.lastErrorMessage = fmt::format("File {} does not exist in the file system.", DLCValidationFile); + journal.lastErrorMessage = fmt::format("File {} does not exist in {}.", DLCValidationFile, sourceVfs.getName()); return DLC::Unknown; } @@ -164,7 +164,7 @@ static DLC detectDLC(const std::filesystem::path &sourcePath, VirtualFileSystem if (typeStartLocation == nullptr || typeEndLocation == nullptr) { journal.lastResult = Journal::Result::DLCParsingFailed; - journal.lastErrorMessage = "Failed to find DLC type for " + fromPath(sourcePath) + "."; + journal.lastErrorMessage = fmt::format("Failed to find DLC type for {}.", sourceVfs.getName()); return DLC::Unknown; } @@ -173,7 +173,7 @@ static DLC detectDLC(const std::filesystem::path &sourcePath, VirtualFileSystem if (typeNumberCount != 1) { journal.lastResult = Journal::Result::UnknownDLCType; - journal.lastErrorMessage = "DLC type for " + fromPath(sourcePath) + " is unknown."; + journal.lastErrorMessage = fmt::format("DLC type for {} is unknown.", sourceVfs.getName()); return DLC::Unknown; } @@ -193,7 +193,7 @@ static DLC detectDLC(const std::filesystem::path &sourcePath, VirtualFileSystem return DLC::EmpireCityAdabat; default: journal.lastResult = Journal::Result::UnknownDLCType; - journal.lastErrorMessage = "DLC type for " + fromPath(sourcePath) + " is unknown."; + journal.lastErrorMessage = fmt::format("DLC type for {} is unknown.", sourceVfs.getName()); return DLC::Unknown; } } @@ -246,7 +246,7 @@ bool Installer::computeTotalSize(std::span filePairs, const uint if (!sourceVfs.exists(filename)) { journal.lastResult = Journal::Result::FileMissing; - journal.lastErrorMessage = fmt::format("File {} does not exist in the file system.", filename); + journal.lastErrorMessage = fmt::format("File {} does not exist in {}.", filename, sourceVfs.getName()); return false; } @@ -300,7 +300,7 @@ bool Installer::copyFiles(std::span filePairs, const uint64_t *f else { journal.lastResult = Journal::Result::ValidationFileMissing; - journal.lastErrorMessage = fmt::format("Unable to find validation file {} in file system.", validationFile); + journal.lastErrorMessage = fmt::format("Unable to find validation file {} in {}.", validationFile, sourceVfs.getName()); return false; } @@ -317,7 +317,7 @@ bool Installer::parseContent(const std::filesystem::path &sourcePath, std::uniqu else { journal.lastResult = Journal::Result::VirtualFileSystemFailed; - journal.lastErrorMessage = "Unable to open file system at " + fromPath(sourcePath); + journal.lastErrorMessage = "Unable to open " + fromPath(sourcePath); return false; } } diff --git a/UnleashedRecomp/install/iso_file_system.cpp b/UnleashedRecomp/install/iso_file_system.cpp index 0348bbe..b0a89ef 100644 --- a/UnleashedRecomp/install/iso_file_system.cpp +++ b/UnleashedRecomp/install/iso_file_system.cpp @@ -21,6 +21,8 @@ ISOFileSystem::ISOFileSystem(const std::filesystem::path &isoPath) return; } + name = (const char *)(isoPath.filename().u8string().data()); + // Find root sector. const uint8_t *mappedFileData = mappedFile.data(); uint32_t gameOffset = 0; @@ -173,6 +175,11 @@ bool ISOFileSystem::exists(const std::string &path) const return fileMap.find(path) != fileMap.end(); } +const std::string &ISOFileSystem::getName() const +{ + return name; +} + bool ISOFileSystem::empty() const { return !mappedFile.isOpen(); diff --git a/UnleashedRecomp/install/iso_file_system.h b/UnleashedRecomp/install/iso_file_system.h index b7bac45..9e62870 100644 --- a/UnleashedRecomp/install/iso_file_system.h +++ b/UnleashedRecomp/install/iso_file_system.h @@ -22,11 +22,13 @@ struct ISOFileSystem : VirtualFileSystem { MemoryMappedFile mappedFile; std::map> fileMap; + std::string name; ISOFileSystem(const std::filesystem::path &isoPath); bool load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const override; size_t getSize(const std::string &path) const override; bool exists(const std::string &path) const override; + const std::string &getName() const override; bool empty() const; static std::unique_ptr create(const std::filesystem::path &isoPath); diff --git a/UnleashedRecomp/install/virtual_file_system.h b/UnleashedRecomp/install/virtual_file_system.h index 3b92608..079f16e 100644 --- a/UnleashedRecomp/install/virtual_file_system.h +++ b/UnleashedRecomp/install/virtual_file_system.h @@ -8,6 +8,7 @@ struct VirtualFileSystem { virtual bool load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const = 0; virtual size_t getSize(const std::string &path) const = 0; virtual bool exists(const std::string &path) const = 0; + virtual const std::string &getName() const = 0; // Concrete implementation shortcut. bool load(const std::string &path, std::vector &fileData) diff --git a/UnleashedRecomp/install/xcontent_file_system.cpp b/UnleashedRecomp/install/xcontent_file_system.cpp index 25e8187..68605fb 100644 --- a/UnleashedRecomp/install/xcontent_file_system.cpp +++ b/UnleashedRecomp/install/xcontent_file_system.cpp @@ -269,6 +269,8 @@ XContentFileSystem::XContentFileSystem(const std::filesystem::path &contentPath) return; } + name = (const char *)(contentPath.filename().u8string().data()); + const uint8_t *rootMappedFileData = rootMappedFile.data(); if (sizeof(XContentContainerHeader) > rootMappedFile.size()) { @@ -607,6 +609,11 @@ bool XContentFileSystem::exists(const std::string &path) const return fileMap.find(path) != fileMap.end(); } +const std::string &XContentFileSystem::getName() const +{ + return name; +} + bool XContentFileSystem::empty() const { return mappedFiles.empty(); diff --git a/UnleashedRecomp/install/xcontent_file_system.h b/UnleashedRecomp/install/xcontent_file_system.h index 4247cd5..dc36a2c 100644 --- a/UnleashedRecomp/install/xcontent_file_system.h +++ b/UnleashedRecomp/install/xcontent_file_system.h @@ -49,11 +49,13 @@ struct XContentFileSystem : VirtualFileSystem std::vector mappedFiles; uint64_t baseOffset = 0; std::map fileMap; + std::string name; XContentFileSystem(const std::filesystem::path &contentPath); bool load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const override; size_t getSize(const std::string &path) const override; bool exists(const std::string &path) const override; + const std::string &getName() const override; bool empty() const; static std::unique_ptr create(const std::filesystem::path &contentPath); diff --git a/UnleashedRecomp/ui/installer_wizard.cpp b/UnleashedRecomp/ui/installer_wizard.cpp index 40a0d0a..4c356a7 100644 --- a/UnleashedRecomp/ui/installer_wizard.cpp +++ b/UnleashedRecomp/ui/installer_wizard.cpp @@ -1123,7 +1123,7 @@ static void InstallerStart() g_installerThread = std::make_unique(InstallerThread); } -static bool InstallerParseSources() +static bool InstallerParseSources(std::string &errorMessage) { std::error_code spaceErrorCode; std::filesystem::space_info spaceInfo = std::filesystem::space(g_installPath, spaceErrorCode); @@ -1136,14 +1136,17 @@ static bool InstallerParseSources() installerInput.gameSource = g_gameSourcePath; installerInput.updateSource = g_updateSourcePath; - for (std::filesystem::path &path : g_dlcSourcePaths) { + for (std::filesystem::path &path : g_dlcSourcePaths) + { if (!path.empty()) { installerInput.dlcSources.push_back(path); } } - return Installer::parseSources(installerInput, g_installerJournal, g_installerSources); + bool sourcesParsed = Installer::parseSources(installerInput, g_installerJournal, g_installerSources); + errorMessage = g_installerJournal.lastErrorMessage; + return sourcesParsed; } static void DrawNextButton() @@ -1195,10 +1198,17 @@ static void DrawNextButton() } bool dlcInstallerMode = g_gameSourcePath.empty(); - if (!InstallerParseSources()) + std::string sourcesErrorMessage; + if (!InstallerParseSources(sourcesErrorMessage)) { // Some of the sources that were provided to the installer are not valid. Restart the file selection process. - g_currentMessagePrompt = Localise("Installer_Message_InvalidFiles"); + std::stringstream stringStream; + stringStream << Localise("Installer_Message_InvalidFiles"); + if (!sourcesErrorMessage.empty()) { + stringStream << std::endl << std::endl << sourcesErrorMessage; + } + + g_currentMessagePrompt = stringStream.str(); g_currentMessagePromptConfirmation = false; g_currentPage = dlcInstallerMode ? WizardPage::SelectDLC : WizardPage::SelectGameAndUpdate; }