diff --git a/SporeModManager/SporeModManager.cpp b/SporeModManager/SporeModManager.cpp index dd23fab..7810ba2 100644 --- a/SporeModManager/SporeModManager.cpp +++ b/SporeModManager/SporeModManager.cpp @@ -22,6 +22,8 @@ using namespace SporeModManagerHelpers; static bool l_HasInstalledSporeMods = false; static std::vector l_InstalledSporeMods; static bool l_SaveInstalledSporeMods = true; +static std::vector l_SporeModInfos; +static std::vector l_ZipFiles; // // Helper Functions @@ -54,11 +56,10 @@ static bool SaveInstalledSporeModList(void) return true; } -static bool GetUniqueName(const std::filesystem::path& path, const std::string& extension, std::string& uniqueName) +static bool GetSporeModInfo(const std::filesystem::path& path, const std::string& extension, SporeMod::Xml::SporeModInfo& sporeModInfo) { - Zip::ZipFile zipFile; + Zip::ZipFile zipFile = {}; std::vector modInfoFileBuffer; - SporeMod::Xml::SporeModInfo sporeModInfo; if (extension == ".sporemod") { @@ -88,18 +89,25 @@ static bool GetUniqueName(const std::filesystem::path& path, const std::string& Zip::CloseFile(zipFile); return false; } - - uniqueName = sporeModInfo.UniqueName; - Zip::CloseFile(zipFile); } else if (extension == ".package") { - uniqueName = path.stem().string(); + sporeModInfo.UniqueName = path.stem().string(); } + l_SporeModInfos.push_back(sporeModInfo); + l_ZipFiles.push_back(zipFile); return true; } +static void CloseZipFiles(void) +{ + for (const Zip::ZipFile& zipFile : l_ZipFiles) + { + Zip::CloseFile(zipFile); + } +} + // // Exported Functions // @@ -129,11 +137,11 @@ bool SporeModManager::ListInstalledMods(void) bool SporeModManager::InstallMods(std::vector paths, bool skipValidation) { - std::string uniqueName; std::vector uniqueNames; std::string extension; bool returnValue = true; SporeMod::Xml::InstalledSporeMod installedSporeMod; + SporeMod::Xml::SporeModInfo sporeModInfo; // do some basic validation before attempting // to install the given mods @@ -146,32 +154,36 @@ bool SporeModManager::InstallMods(std::vector paths, bool if (!std::filesystem::is_regular_file(path)) { std::cerr << "\"" << path.string() << "\" is not a regular file or doesn't exist!" << std::endl; + CloseZipFiles(); return false; } + sporeModInfo = {}; extension = String::Lowercase(path.extension().string()); if (extension == ".sporemod" || extension == ".package") { - if (!GetUniqueName(path, extension, uniqueName)) + if (!GetSporeModInfo(path, extension, sporeModInfo)) { + CloseZipFiles(); return false; } } else { std::cerr << "\"" << extension << "\" is an invalid extension!" << std::endl; + CloseZipFiles(); return false; } // ensure we only have unique mod names - if (std::find(uniqueNames.begin(), uniqueNames.end(), uniqueName) != uniqueNames.end()) + if (std::find(uniqueNames.begin(), uniqueNames.end(), sporeModInfo.UniqueName) != uniqueNames.end()) { std::cerr << "Removing \"" << path.string() << "\" from the installation list due to another mod having the same unique name!" << std::endl; paths.erase(paths.begin() + i); i -= 1; continue; } - uniqueNames.push_back(uniqueName); + uniqueNames.push_back(sporeModInfo.UniqueName); } } @@ -181,18 +193,19 @@ bool SporeModManager::InstallMods(std::vector paths, bool } // install given mods - for (const auto& path : paths) + for (size_t i = 0; i < paths.size(); i++) { + const std::filesystem::path& path = paths.at(i); + installedSporeMod = {}; extension = String::Lowercase(path.extension().string()); if (extension == ".sporemod") { - if (!SporeMod::InstallSporeMod(path, installedSporeMod, l_InstalledSporeMods)) + if (!SporeMod::InstallSporeMod(l_ZipFiles.at(i), l_SporeModInfos.at(i), installedSporeMod, l_InstalledSporeMods)) { returnValue = false; break; } - l_InstalledSporeMods.push_back(installedSporeMod); } else if (extension == ".package") { @@ -201,8 +214,8 @@ bool SporeModManager::InstallMods(std::vector paths, bool returnValue = false; break; } - l_InstalledSporeMods.push_back(installedSporeMod); } + l_InstalledSporeMods.push_back(installedSporeMod); } if (!SaveInstalledSporeModList()) @@ -210,6 +223,7 @@ bool SporeModManager::InstallMods(std::vector paths, bool return false; } + CloseZipFiles(); return returnValue; } @@ -217,9 +231,9 @@ bool SporeModManager::UpdateMods(std::vector paths, bool { int installedSporeModId = 0; std::vector installedSporeModIds; - std::string uniqueName; std::vector uniqueNames; std::string extension; + SporeMod::Xml::SporeModInfo sporeModInfo; if (!GetInstalledSporeModList()) { @@ -238,10 +252,11 @@ bool SporeModManager::UpdateMods(std::vector paths, bool return false; } + sporeModInfo = {}; extension = String::Lowercase(path.extension().string()); if (extension == ".sporemod" || extension == ".package") { - if (!GetUniqueName(path, extension, uniqueName)) + if (!GetSporeModInfo(path, extension, sporeModInfo)) { return false; } @@ -253,7 +268,7 @@ bool SporeModManager::UpdateMods(std::vector paths, bool } // ensure we only have unique mod names - if (std::find(uniqueNames.begin(), uniqueNames.end(), uniqueName) != + if (std::find(uniqueNames.begin(), uniqueNames.end(), sporeModInfo.UniqueName) != uniqueNames.end()) { std::cerr << "Removing \"" << path.string() << "\" from the installation/update list due to another mod having the same unique name!" << std::endl; @@ -261,13 +276,13 @@ bool SporeModManager::UpdateMods(std::vector paths, bool i -= 1; continue; } - uniqueNames.push_back(uniqueName); + uniqueNames.push_back(sporeModInfo.UniqueName); - if (!SporeMod::FindInstalledMod(uniqueName, installedSporeModId, l_InstalledSporeMods)) + if (!SporeMod::FindInstalledMod(sporeModInfo.UniqueName, installedSporeModId, l_InstalledSporeMods)) { if (requiresInstalled) { - std::cerr << "No mod found with the same unique name (" << uniqueName << ")" << std::endl + std::cerr << "No mod found with the same unique name (" << sporeModInfo.UniqueName << ")" << std::endl << "Did you mean install?" << std::endl; return false; } diff --git a/SporeModManager/SporeModManagerHelpers.hpp b/SporeModManager/SporeModManagerHelpers.hpp index 517a347..98da78c 100644 --- a/SporeModManager/SporeModManagerHelpers.hpp +++ b/SporeModManager/SporeModManagerHelpers.hpp @@ -188,7 +188,7 @@ namespace SporeModManagerHelpers /// /// Installs sporemod file /// - bool InstallSporeMod(std::filesystem::path path, Xml::InstalledSporeMod& installedSporeMod, const std::vector& installedSporeMods); + bool InstallSporeMod(void* zipFile, const Xml::SporeModInfo& sporeModInfo, Xml::InstalledSporeMod& installedSporeMod, const std::vector& installedSporeMods); /// /// Installs package file diff --git a/SporeModManager/SporeModManagerHelpers/SporeMod.cpp b/SporeModManager/SporeModManagerHelpers/SporeMod.cpp index ad2a9a8..bba9863 100644 --- a/SporeModManager/SporeModManagerHelpers/SporeMod.cpp +++ b/SporeModManager/SporeModManagerHelpers/SporeMod.cpp @@ -45,7 +45,7 @@ static bool CheckIfOtherModContainsFiles(std::vector& installedSporeMods) +bool SporeMod::InstallSporeMod(void* zipFile, const Xml::SporeModInfo& sporeModInfo, Xml::InstalledSporeMod& installedSporeMod, const std::vector& installedSporeMods) { - Zip::ZipFile zipFile; - std::vector modInfoFileBuffer; - Xml::SporeModInfo sporeModInfo; Xml::SporeModInfoComponent component; size_t componentsSize; std::optional defaultComponentId; @@ -88,26 +85,6 @@ bool SporeMod::InstallSporeMod(std::filesystem::path path, Xml::InstalledSporeMo std::vector componentIds; std::string uiText; - if (!Zip::OpenFile(zipFile, path)) - { - std::cerr << "Zip::OpenFile() Failed!" << std::endl; - return false; - } - - if (!Zip::ExtractFile(zipFile, "modinfo.xml", modInfoFileBuffer)) - { - std::cerr << "Zip::ExtractFile() Failed!" << std::endl; - Zip::CloseFile(zipFile); - return false; - } - - if (!Xml::ParseSporeModInfo(modInfoFileBuffer, sporeModInfo)) - { - std::cerr << "Xml::ParseSporeModInfo() Failed!" << std::endl; - Zip::CloseFile(zipFile); - return false; - } - installedSporeMod.Name = sporeModInfo.Name; installedSporeMod.UniqueName = sporeModInfo.UniqueName; installedSporeMod.Description = sporeModInfo.Description; @@ -116,7 +93,6 @@ bool SporeMod::InstallSporeMod(std::filesystem::path path, Xml::InstalledSporeMo // already installed if (IsModAlreadyInstalled(sporeModInfo.UniqueName, installedSporeMods)) { - Zip::CloseFile(zipFile); return false; } @@ -141,7 +117,6 @@ bool SporeMod::InstallSporeMod(std::filesystem::path path, Xml::InstalledSporeMo UI::AskUserInput(inputText, userAnswer, false); if (!userAnswer) { - Zip::CloseFile(zipFile); return false; } } @@ -268,7 +243,6 @@ bool SporeMod::InstallSporeMod(std::filesystem::path path, Xml::InstalledSporeMo // file collision detection if (CheckIfOtherModContainsFiles(installedSporeMod.InstalledFiles, installedSporeMods)) { - Zip::CloseFile(zipFile); return false; } @@ -282,7 +256,6 @@ bool SporeMod::InstallSporeMod(std::filesystem::path path, Xml::InstalledSporeMo if (!Zip::ExtractFile(zipFile, sourcePath, installPath)) { std::cerr << "Zip::ExtractFile() Failed!" << std::endl; - Zip::CloseFile(zipFile); // cleanup installed files that were left over for (const auto& installedFileToRemove : installedSporeMod.InstalledFiles) { @@ -304,7 +277,6 @@ bool SporeMod::InstallSporeMod(std::filesystem::path path, Xml::InstalledSporeMo } } - Zip::CloseFile(zipFile); return true; } diff --git a/SporeModManager/SporeModManagerHelpers/Zip.cpp b/SporeModManager/SporeModManagerHelpers/Zip.cpp index 0466cf9..c66affa 100644 --- a/SporeModManager/SporeModManagerHelpers/Zip.cpp +++ b/SporeModManager/SporeModManagerHelpers/Zip.cpp @@ -11,6 +11,7 @@ #include #include +#include #include @@ -22,6 +23,12 @@ using namespace SporeModManagerHelpers; #define UNZIP_READ_SIZE 67108860 /* 64 MiB */ +// +// Local Variables +// + +static std::map l_ZipFileStreams; + // // Local Functions // @@ -30,17 +37,24 @@ static voidpf zlib_filefunc_open(voidpf /*opaque*/, const void* filename, int /* { std::filesystem::path path = *(std::filesystem::path*)filename; - // we need a static filestream - static std::ifstream fileStream; + // if the stream is cached, ensure it's closed + auto iter = l_ZipFileStreams.find(path); + if (iter != l_ZipFileStreams.end()) + { + if (iter->second.is_open()) + { + iter->second.close(); + } + } // attempt to open file - fileStream.open(path, std::ios::binary); - if (!fileStream.is_open()) + l_ZipFileStreams[path] = std::ifstream(path, std::ios::binary | std::ios::in); + if (!l_ZipFileStreams[path].is_open()) { return nullptr; } - return (voidpf)&fileStream; + return (voidpf)&l_ZipFileStreams[path]; } static uLong zlib_filefunc_read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) @@ -64,7 +78,7 @@ static long zlib_filefunc_seek(voidpf /*opaque*/, voidpf stream, ZPOS64_T offset switch (origin) { default: - return 0; + return -1; case ZLIB_FILEFUNC_SEEK_CUR: seekOrigin = std::ios::cur; break;