Browse Source

fix crash when map is packaged in a zip mod

kdmcser 5 months ago
parent
commit
5e4912d056

+ 34 - 0
lib/filesystem/AdapterLoaders.cpp

@@ -56,6 +56,18 @@ std::unordered_set<ResourcePath> CMappedFileLoader::getFilteredFiles(std::functi
 	return foundID;
 }
 
+std::string CMappedFileLoader::getFullFileURI(const ResourcePath& resourceName) const
+{
+	return CResourceHandler::get()->getFullFileURI(fileList.at(resourceName));
+}
+
+std::time_t CMappedFileLoader::getLastWriteTime(const ResourcePath& resourceName) const
+{
+	return CResourceHandler::get()->getLastWriteTime(fileList.at(resourceName));
+}
+
+
+
 CFilesystemList::CFilesystemList()
 {
 }
@@ -176,7 +188,29 @@ bool CFilesystemList::removeLoader(ISimpleResourceLoader * loader)
 			return true;
 		}
 	}
+
+
 	return false;
 }
 
+std::string CFilesystemList::getFullFileURI(const ResourcePath& resourceName) const
+{
+	for (const auto& loader : boost::adaptors::reverse(loaders))
+		if (loader->existsResource(resourceName))
+			return loader->getFullFileURI(resourceName);
+
+	throw std::runtime_error("Resource with name " + resourceName.getName() + " and type "
+		+ EResTypeHelper::getEResTypeAsString(resourceName.getType()) + " wasn't found.");
+}
+
+std::time_t CFilesystemList::getLastWriteTime(const ResourcePath& resourceName) const
+{
+	for (const auto& loader : boost::adaptors::reverse(loaders))
+		if (loader->existsResource(resourceName))
+			return loader->getLastWriteTime(resourceName);
+
+	throw std::runtime_error("Resource with name " + resourceName.getName() + " and type "
+		+ EResTypeHelper::getEResTypeAsString(resourceName.getType()) + " wasn't found.");
+}
+
 VCMI_LIB_NAMESPACE_END

+ 4 - 0
lib/filesystem/AdapterLoaders.h

@@ -44,6 +44,8 @@ public:
 	std::optional<boost::filesystem::path> getResourceName(const ResourcePath & resourceName) const override;
 	void updateFilteredFiles(std::function<bool(const std::string &)> filter) const override {}
 	std::unordered_set<ResourcePath> getFilteredFiles(std::function<bool(const ResourcePath &)> filter) const override;
+	std::string getFullFileURI(const ResourcePath& resourceName) const override;
+	std::time_t getLastWriteTime(const ResourcePath& resourceName) const override;
 
 private:
 	/** A list of files in this map
@@ -77,6 +79,8 @@ public:
 	std::unordered_set<ResourcePath> getFilteredFiles(std::function<bool(const ResourcePath &)> filter) const override;
 	bool createResource(const std::string & filename, bool update = false) override;
 	std::vector<const ISimpleResourceLoader *> getResourcesWithName(const ResourcePath & resourceName) const override;
+	std::string getFullFileURI(const ResourcePath& resourceName) const override;
+	std::time_t getLastWriteTime(const ResourcePath& resourceName) const override;
 
 	/**
 	 * Adds a resource loader to the loaders list

+ 14 - 0
lib/filesystem/CArchiveLoader.cpp

@@ -15,6 +15,7 @@
 #include "CCompressedStream.h"
 
 #include "CBinaryReader.h"
+#include "../texts/TextOperations.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -240,6 +241,19 @@ void CArchiveLoader::extractToFolder(const std::string & outputSubFolder, const
 	extractToFolder(outputSubFolder, *inputStream, entry, absolute);
 }
 
+
+std::string CArchiveLoader::getFullFileURI(const ResourcePath& resourceName) const
+{
+	auto relativePath = TextOperations::Utf8TofilesystemPath(resourceName.getName());
+	auto path = boost::filesystem::canonical(archive) / relativePath;
+	return TextOperations::filesystemPathToUtf8(path);
+}
+
+std::time_t CArchiveLoader::getLastWriteTime(const ResourcePath& resourceName) const
+{
+	return  boost::filesystem::last_write_time(archive);
+}
+
 boost::filesystem::path createExtractedFilePath(const std::string & outputSubFolder, const std::string & entryName, bool absolute)
 {
 	boost::filesystem::path extractionFolderPath = absolute ? outputSubFolder : VCMIDirs::get().userExtractedPath() / outputSubFolder;

+ 2 - 0
lib/filesystem/CArchiveLoader.h

@@ -70,6 +70,8 @@ public:
 	void extractToFolder(const std::string & outputSubFolder, CInputStream & fileStream, const ArchiveEntry & entry, bool absolute = false) const;
 	/** Extracts one archive entry to the specified subfolder. Used for Images, Sprites, etc */
 	void extractToFolder(const std::string & outputSubFolder, const std::string & mountPoint, ArchiveEntry entry, bool absolute = false) const;
+	std::string getFullFileURI(const ResourcePath& resourceName) const override;
+	std::time_t getLastWriteTime(const ResourcePath& resourceName) const override;
 
 private:
 	/**

+ 13 - 0
lib/filesystem/CFilesystemLoader.cpp

@@ -198,4 +198,17 @@ std::unordered_map<ResourcePath, boost::filesystem::path> CFilesystemLoader::lis
 	return fileList;
 }
 
+std::string CFilesystemLoader::getFullFileURI(const ResourcePath& resourceName) const
+{
+	auto filePath = getResourceName(resourceName);
+	auto path = boost::filesystem::canonical(*filePath);
+	return TextOperations::filesystemPathToUtf8(path);
+}
+
+std::time_t CFilesystemLoader::getLastWriteTime(const ResourcePath& resourceName) const
+{
+	auto resourcePath = getResourceName(resourceName);
+	return  boost::filesystem::last_write_time(*resourcePath);
+}
+
 VCMI_LIB_NAMESPACE_END

+ 2 - 0
lib/filesystem/CFilesystemLoader.h

@@ -41,6 +41,8 @@ public:
 	std::optional<boost::filesystem::path> getResourceName(const ResourcePath & resourceName) const override;
 	void updateFilteredFiles(std::function<bool(const std::string &)> filter) const override;
 	std::unordered_set<ResourcePath> getFilteredFiles(std::function<bool(const ResourcePath &)> filter) const override;
+	std::string getFullFileURI(const ResourcePath& resourceName) const override;
+	std::time_t getLastWriteTime(const ResourcePath& resourceName) const override;
 
 private:
 	/** The base directory which is scanned and indexed. */

+ 14 - 0
lib/filesystem/CZipLoader.cpp

@@ -11,6 +11,7 @@
 #include "CZipLoader.h"
 
 #include "../ScopeGuard.h"
+#include "../texts/TextOperations.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -120,6 +121,19 @@ std::unordered_set<ResourcePath> CZipLoader::getFilteredFiles(std::function<bool
 	return foundID;
 }
 
+std::string CZipLoader::getFullFileURI(const ResourcePath& resourceName) const
+{
+	auto relativePath = TextOperations::Utf8TofilesystemPath(resourceName.getName());
+	auto path = boost::filesystem::canonical(archiveName) / relativePath;
+	return TextOperations::filesystemPathToUtf8(path);
+}
+
+std::time_t CZipLoader::getLastWriteTime(const ResourcePath& resourceName) const
+{
+	auto path = boost::filesystem::canonical(archiveName);
+	return  boost::filesystem::last_write_time(path);
+}
+
 /// extracts currently selected file from zip into stream "where"
 static bool extractCurrent(unzFile file, std::ostream & where)
 {

+ 2 - 0
lib/filesystem/CZipLoader.h

@@ -59,6 +59,8 @@ public:
 	std::string getMountPoint() const override;
 	void updateFilteredFiles(std::function<bool(const std::string &)> filter) const override {}
 	std::unordered_set<ResourcePath> getFilteredFiles(std::function<bool(const ResourcePath &)> filter) const override;
+	std::string getFullFileURI(const ResourcePath& resourceName) const override;
+	std::time_t getLastWriteTime(const ResourcePath& resourceName) const override;
 };
 
 class DLL_LINKAGE ZipArchive : boost::noncopyable

+ 4 - 0
lib/filesystem/ISimpleResourceLoader.h

@@ -106,6 +106,10 @@ public:
 			return std::vector<const ISimpleResourceLoader *>(1, this);
 		return std::vector<const ISimpleResourceLoader *>();
 	}
+
+	virtual std::string getFullFileURI(const ResourcePath& resourceName) const = 0;
+		
+	virtual std::time_t getLastWriteTime(const ResourcePath& resourceName) const = 0;
 };
 
 VCMI_LIB_NAMESPACE_END

+ 5 - 10
lib/mapping/CMapInfo.cpp

@@ -38,11 +38,6 @@ CMapInfo::CMapInfo()
 
 CMapInfo::~CMapInfo() = default;
 
-std::string CMapInfo::getFullFileURI(const ResourcePath & file) const
-{
-	auto path = boost::filesystem::canonical(*CResourceHandler::get()->getResourceName(file));
-	return TextOperations::filesystemPathToUtf8(path);
-}
 
 void CMapInfo::mapInit(const std::string & fname)
 {
@@ -50,9 +45,9 @@ void CMapInfo::mapInit(const std::string & fname)
 	CMapService mapService;
 	ResourcePath resource = ResourcePath(fname, EResType::MAP);
 	originalFileURI = resource.getOriginalName();
-	fullFileURI = getFullFileURI(resource);
+	fullFileURI = CResourceHandler::get()->getFullFileURI(resource);
 	mapHeader = mapService.loadMapHeader(resource);
-	lastWrite = boost::filesystem::last_write_time(*CResourceHandler::get()->getResourceName(resource));
+	lastWrite = CResourceHandler::get()->getLastWriteTime(resource);
 	date = TextOperations::getFormattedDateTimeLocal(lastWrite);
 	countPlayers();
 }
@@ -71,9 +66,9 @@ void CMapInfo::saveInit(const ResourcePath & file)
 
 	fileURI = file.getName();
 	originalFileURI = file.getOriginalName();
-	fullFileURI = getFullFileURI(file);
+	fullFileURI = CResourceHandler::get()->getFullFileURI(file);
 	countPlayers();
-	lastWrite = boost::filesystem::last_write_time(*CResourceHandler::get()->getResourceName(file));
+	lastWrite = CResourceHandler::get()->getLastWriteTime(file);
 	date = TextOperations::getFormattedDateTimeLocal(lastWrite);
 
 	// We absolutely not need this data for lobby and server will read it from save
@@ -85,7 +80,7 @@ void CMapInfo::campaignInit()
 {
 	ResourcePath resource = ResourcePath(fileURI, EResType::CAMPAIGN);
 	originalFileURI = resource.getOriginalName();
-	fullFileURI = getFullFileURI(resource);
+	fullFileURI = CResourceHandler::get()->getFullFileURI(resource);
 	campaign = CampaignHandler::getHeader(fileURI);
 	lastWrite = boost::filesystem::last_write_time(*CResourceHandler::get()->getResourceName(resource));
 	date = TextOperations::getFormattedDateTimeLocal(lastWrite);

+ 0 - 1
lib/mapping/CMapInfo.h

@@ -48,7 +48,6 @@ public:
 	CMapInfo &operator=(CMapInfo &&other) = delete;
 	CMapInfo &operator=(const CMapInfo &other) = delete;
 
-	std::string getFullFileURI(const ResourcePath& file) const;
 	void mapInit(const std::string & fname);
 	void saveInit(const ResourcePath & file);
 	void campaignInit();