Skip to content

Commit

Permalink
SporeModManager: only open zip & parse ModInfo.xml once
Browse files Browse the repository at this point in the history
  • Loading branch information
Rosalie241 committed Nov 20, 2023
1 parent c99d883 commit 5da9e30
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 59 deletions.
63 changes: 41 additions & 22 deletions SporeModManager/SporeModManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ using namespace SporeModManagerHelpers;
static bool l_HasInstalledSporeMods = false;
static std::vector<SporeMod::Xml::InstalledSporeMod> l_InstalledSporeMods;
static bool l_SaveInstalledSporeMods = true;
static std::vector<SporeMod::Xml::SporeModInfo> l_SporeModInfos;
static std::vector<Zip::ZipFile> l_ZipFiles;

//
// Helper Functions
Expand Down Expand Up @@ -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<char> modInfoFileBuffer;
SporeMod::Xml::SporeModInfo sporeModInfo;

if (extension == ".sporemod")
{
Expand Down Expand Up @@ -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
//
Expand Down Expand Up @@ -129,11 +137,11 @@ bool SporeModManager::ListInstalledMods(void)

bool SporeModManager::InstallMods(std::vector<std::filesystem::path> paths, bool skipValidation)
{
std::string uniqueName;
std::vector<std::string> 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
Expand All @@ -146,53 +154,59 @@ bool SporeModManager::InstallMods(std::vector<std::filesystem::path> 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);
}
}

if (!GetInstalledSporeModList())
{
CloseZipFiles();
return false;
}

// 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")
{
Expand All @@ -201,25 +215,27 @@ bool SporeModManager::InstallMods(std::vector<std::filesystem::path> paths, bool
returnValue = false;
break;
}
l_InstalledSporeMods.push_back(installedSporeMod);
}
l_InstalledSporeMods.push_back(installedSporeMod);
}

if (!SaveInstalledSporeModList())
{
CloseZipFiles();
return false;
}

CloseZipFiles();
return returnValue;
}

bool SporeModManager::UpdateMods(std::vector<std::filesystem::path> paths, bool requiresInstalled)
{
int installedSporeModId = 0;
std::vector<int> installedSporeModIds;
std::string uniqueName;
std::vector<std::string> uniqueNames;
std::string extension;
SporeMod::Xml::SporeModInfo sporeModInfo;

if (!GetInstalledSporeModList())
{
Expand All @@ -238,11 +254,13 @@ bool SporeModManager::UpdateMods(std::vector<std::filesystem::path> 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))
{
CloseZipFiles();
return false;
}
}
Expand All @@ -253,21 +271,21 @@ bool SporeModManager::UpdateMods(std::vector<std::filesystem::path> paths, bool
}

// 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/update 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);

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
CloseZipFiles();
std::cerr << "No mod found with the same unique name (" << sporeModInfo.UniqueName << ")" << std::endl
<< "Did you mean install?" << std::endl;
return false;
}
Expand All @@ -284,6 +302,7 @@ bool SporeModManager::UpdateMods(std::vector<std::filesystem::path> paths, bool
// apply changes
if (!installedSporeModIds.empty() && !UninstallMods(installedSporeModIds))
{
CloseZipFiles();
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion SporeModManager/SporeModManagerHelpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ namespace SporeModManagerHelpers
/// <summary>
/// Installs sporemod file
/// </summary>
bool InstallSporeMod(std::filesystem::path path, Xml::InstalledSporeMod& installedSporeMod, const std::vector<Xml::InstalledSporeMod>& installedSporeMods);
bool InstallSporeMod(void* zipFile, const Xml::SporeModInfo& sporeModInfo, Xml::InstalledSporeMod& installedSporeMod, const std::vector<Xml::InstalledSporeMod>& installedSporeMods);

/// <summary>
/// Installs package file
Expand Down
32 changes: 2 additions & 30 deletions SporeModManager/SporeModManagerHelpers/SporeMod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ static bool CheckIfOtherModContainsFiles(std::vector<SporeMod::Xml::SporeModFile
if (installedFileIter != installedSporeMod.InstalledFiles.end())
{
std::cerr << "An already installed mod (" << installedSporeMod.Name
<< ") contains a file (\"" << sporeModFile.FileName.string() << "\") that this mod wants to install!" << std::endl;
<< ") contains a file (\"" << sporeModFile.FileName.string() << "\") that this mod wants to install!" << std::endl;
return true;
}
}
Expand Down Expand Up @@ -75,11 +75,8 @@ bool SporeMod::FindInstalledMod(std::string uniqueName, int& installedSporeModId
return false;
}

bool SporeMod::InstallSporeMod(std::filesystem::path path, Xml::InstalledSporeMod& installedSporeMod, const std::vector<Xml::InstalledSporeMod>& installedSporeMods)
bool SporeMod::InstallSporeMod(void* zipFile, const Xml::SporeModInfo& sporeModInfo, Xml::InstalledSporeMod& installedSporeMod, const std::vector<Xml::InstalledSporeMod>& installedSporeMods)
{
Zip::ZipFile zipFile;
std::vector<char> modInfoFileBuffer;
Xml::SporeModInfo sporeModInfo;
Xml::SporeModInfoComponent component;
size_t componentsSize;
std::optional<int> defaultComponentId;
Expand All @@ -88,26 +85,6 @@ bool SporeMod::InstallSporeMod(std::filesystem::path path, Xml::InstalledSporeMo
std::vector<int> 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;
Expand All @@ -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;
}

Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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;
}

Expand All @@ -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)
{
Expand All @@ -304,7 +277,6 @@ bool SporeMod::InstallSporeMod(std::filesystem::path path, Xml::InstalledSporeMo
}
}

Zip::CloseFile(zipFile);
return true;
}

Expand Down
26 changes: 20 additions & 6 deletions SporeModManager/SporeModManagerHelpers/Zip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <iostream>
#include <fstream>
#include <map>

#include <unzip.h>

Expand All @@ -22,6 +23,12 @@ using namespace SporeModManagerHelpers;

#define UNZIP_READ_SIZE 67108860 /* 64 MiB */

//
// Local Variables
//

static std::map<std::filesystem::path, std::ifstream> l_ZipFileStreams;

//
// Local Functions
//
Expand All @@ -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)
Expand All @@ -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;
Expand Down

0 comments on commit 5da9e30

Please sign in to comment.