Bläddra i källkod

* std::unordered_map implementation in MSVC 10 has terribly slow destructor. Since bug is fixed only in VC11, I replaced it with boost::unordered_map.
* fixed crash with invalid .lod archive (some H3 installations have fake 1 byte .lod "archives"
* fixed crash when parsing invalid map file
* minor random optimizations (rv-refs, etc)

Michał W. Urbańczyk 13 år sedan
förälder
incheckning
cd63c177e2

+ 11 - 5
Global.h

@@ -29,15 +29,21 @@
 #include "tchar_amigaos4.h"
 #endif
 
-#include <cmath>
+#include <algorithm>
+#include <array>
 #include <cassert>
-#include <assert.h>
-#include <vector>
-#include <string>
+#include <climits>
+#include <cmath>
+#include <cstdlib>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
 #include <map>
-#include <unordered_map>
+#include <memory>
+#include <numeric>
 #include <queue>
 #include <set>
+#include <sstream>
 #include <utility>
 #include <numeric>
 

+ 10 - 7
client/CPreGame.cpp

@@ -1049,16 +1049,19 @@ void SelectionTab::parseMaps(const std::vector<ResourceID> &files, int start, in
 
 	while(start < allItems.size())
 	{
-		CCompressedStream stream(std::move(CResourceHandler::get()->load(files[start])), true);
-		int read = stream.read(mapBuffer, 1500);
-
-		if(read < 50  ||  !mapBuffer[4])
+		try
 		{
-			tlog3 << "\t\tWarning: corrupted map file: " << files[start].getName() << std::endl;
+			CCompressedStream stream(std::move(CResourceHandler::get()->load(files[start])), true);
+			int read = stream.read(mapBuffer, 1500);
+
+			if(read < 50  ||  !mapBuffer[4])
+				throw std::runtime_error("corrupted map file");
+
+			allItems[start].mapInit(files[start].getName(), mapBuffer);
 		}
-		else //valid map
+		catch(std::exception &e)
 		{
-			allItems[start].mapInit(files[start].getName(), mapBuffer);
+			tlog3 << "\t\tWarning: failed to load map " << files[start].getName() << ": " << e.what() << std::endl;
 		}
 		start += threads;
 	}

+ 2 - 2
lib/Filesystem/CFileInfo.cpp

@@ -6,8 +6,8 @@ CFileInfo::CFileInfo() : name("")
 
 }
 
-CFileInfo::CFileInfo(const std::string & name)
-	: name(name)
+CFileInfo::CFileInfo(std::string name)
+	: name(std::move(name))
 {
 
 }

+ 1 - 1
lib/Filesystem/CFileInfo.h

@@ -29,7 +29,7 @@ public:
 	 *
 	 * @param name The path and name of the file.
 	 */
-	explicit CFileInfo(const std::string & name);
+	explicit CFileInfo(std::string name);
 
 	/**
 	 * Checks if the file exists.

+ 3 - 4
lib/Filesystem/CFilesystemLoader.cpp

@@ -29,7 +29,7 @@ bool CFilesystemLoader::existsEntry(const std::string & resourceName) const
 	return false;
 }
 
-std::unordered_map<ResourceID, std::string> CFilesystemLoader::getEntries() const
+boost::unordered_map<ResourceID, std::string> CFilesystemLoader::getEntries() const
 {
 	return fileList;
 }
@@ -54,11 +54,10 @@ bool CFilesystemLoader::createEntry(std::string filename)
 }
 
 
-std::unordered_map<ResourceID, std::string> CFilesystemLoader::listFiles(size_t depth, bool initial) const
+boost::unordered_map<ResourceID, std::string> CFilesystemLoader::listFiles(size_t depth, bool initial) const
 {
-
 	assert(boost::filesystem::is_directory(baseDirectory));
-	std::unordered_map<ResourceID, std::string> fileList;
+	boost::unordered_map<ResourceID, std::string> fileList;
 
 	std::vector<std::string> path;//vector holding relative path to our file
 

+ 3 - 3
lib/Filesystem/CFilesystemLoader.h

@@ -53,7 +53,7 @@ public:
 	 *
 	 * @return a list of all entries in the filesystem.
 	 */
-	std::unordered_map<ResourceID, std::string> getEntries() const;
+	boost::unordered_map<ResourceID, std::string> getEntries() const;
 
 	/**
 	 * Gets the origin of the archive loader.
@@ -72,7 +72,7 @@ private:
 	 * key = ResourceID for resource loader
 	 * value = name that can be used to access file
 	*/
-	std::unordered_map<ResourceID, std::string> fileList;
+	boost::unordered_map<ResourceID, std::string> fileList;
 
 	/**
 	 * Returns a list of pathnames denoting the files in the directory denoted by this pathname.
@@ -83,5 +83,5 @@ private:
 	 * @return a list of pathnames denoting the files and directories in the directory denoted by this pathname
 	 * The array will be empty if the directory is empty. Ptr is null if the directory doesn't exist or if it isn't a directory.
 	 */
-	std::unordered_map<ResourceID, std::string> listFiles(size_t depth, bool initial) const;
+	boost::unordered_map<ResourceID, std::string> listFiles(size_t depth, bool initial) const;
 };

+ 8 - 3
lib/Filesystem/CLodArchiveLoader.cpp

@@ -19,6 +19,10 @@ CLodArchiveLoader::CLodArchiveLoader(const std::string & archive)
 	this->archive = archive;
 	CFileInputStream fileStream(archive);
 
+	// Fake .lod file with no data has to be silently ignored.
+	if(fileStream.getSize() < 10)
+		return;
+
 	// Retrieve file extension of archive in uppercase
 	CFileInfo fileInfo(archive);
 	std::string ext = fileInfo.getExtension();
@@ -57,6 +61,7 @@ void CLodArchiveLoader::initLODArchive(CFileInputStream & fileStream)
 
 	// Read count of total files
 	CBinaryReader reader(fileStream);
+
 	fileStream.seek(8);
 	ui32 totalFiles = reader.readUInt32();
 
@@ -184,9 +189,9 @@ std::unique_ptr<CInputStream> CLodArchiveLoader::load(const std::string & resour
 	}
 }
 
-std::unordered_map<ResourceID, std::string> CLodArchiveLoader::getEntries() const
+boost::unordered_map<ResourceID, std::string> CLodArchiveLoader::getEntries() const
 {
-	std::unordered_map<ResourceID, std::string> retList;
+	boost::unordered_map<ResourceID, std::string> retList;
 
 	for(auto it = entries.begin(); it != entries.end(); ++it)
 	{
@@ -194,7 +199,7 @@ std::unordered_map<ResourceID, std::string> CLodArchiveLoader::getEntries() cons
 		retList[ResourceID(entry.name)] = entry.name;
 	}
 
-	return std::move(retList);
+	return retList;
 }
 
 const ArchiveEntry * CLodArchiveLoader::getArchiveEntry(const std::string & resourceName) const

+ 2 - 2
lib/Filesystem/CLodArchiveLoader.h

@@ -72,7 +72,7 @@ public:
 	 *
 	 * @return a list of all entries in the archive.
 	 */
-	std::unordered_map<ResourceID, std::string> getEntries() const;
+	boost::unordered_map<ResourceID, std::string> getEntries() const;
 
 	/**
 	 * Gets the archive entry for the requested resource
@@ -122,5 +122,5 @@ private:
 	std::string archive;
 
 	/** Holds all entries of the archive file. An entry can be accessed via the entry name. **/
-	std::unordered_map<std::string, ArchiveEntry> entries;
+	boost::unordered_map<std::string, ArchiveEntry> entries;
 };

+ 14 - 10
lib/Filesystem/CResourceLoader.cpp

@@ -8,6 +8,7 @@
 #include "../JsonNode.h"
 #include "../GameConstants.h"
 #include "../VCMIDirs.h"
+#include "../CStopWatch.h"
 
 CResourceLoader * CResourceHandler::resourceLoader = nullptr;
 CResourceLoader * CResourceHandler::initialLoader = nullptr;
@@ -17,16 +18,16 @@ ResourceID::ResourceID()
 {
 }
 
-ResourceID::ResourceID(const std::string & name)
+ResourceID::ResourceID(std::string name)
 {
-	CFileInfo info(name);
+	CFileInfo info(std::move(name));
 	setName(info.getStem());
 	setType(info.getType());
 }
 
-ResourceID::ResourceID(const std::string & name, EResType::Type type)
+ResourceID::ResourceID(std::string name, EResType::Type type)
 {
-	setName(name);
+	setName(std::move(name));
 	setType(type);
 }
 
@@ -53,9 +54,9 @@ EResType::Type ResourceID::getType() const
 	return type;
 }
 
-void ResourceID::setName(const std::string & name)
+void ResourceID::setName(std::string name)
 {
-	this->name = name;
+	this->name = std::move(name);
 
 	size_t dotPos = this->name.find_last_of("/.");
 
@@ -111,9 +112,9 @@ ResourceLocator CResourceLoader::getResource(const ResourceID & resourceIdent) c
 	return resource->second.back();
 }
 
-const std::list<ResourceLocator> & CResourceLoader::getResourcesWithName(const ResourceID & resourceIdent) const
+const std::vector<ResourceLocator> & CResourceLoader::getResourcesWithName(const ResourceID & resourceIdent) const
 {
-	static const std::list<ResourceLocator> emptyList;
+	static const std::vector<ResourceLocator> emptyList;
 	auto resource = resources.find(resourceIdent);
 
 	if (resource == resources.end())
@@ -163,7 +164,7 @@ void CResourceLoader::addLoader(std::string mountPoint, shared_ptr<ISimpleResour
 	loaders.push_back(loaderEntry);
 
 	// Get entries and add them to the resources list
-	const std::unordered_map<ResourceID, std::string> & entries = loader->getEntries();
+	const boost::unordered_map<ResourceID, std::string> & entries = loader->getEntries();
 
 	boost::to_upper(mountPoint);
 
@@ -337,7 +338,8 @@ void CResourceHandler::loadFileSystem(const std::string fsConfigURI)
 	{
 		BOOST_FOREACH(auto & entry, mountPoint.second.Vector())
 		{
-			tlog5 << "loading resource at " << entry["path"].String() << "\n";
+			CStopWatch timer;
+			tlog5 << "\t\tLoading resource at " << entry["path"].String();
 
 			std::string URI = entry["path"].String();
 			if (entry["type"].String() == "dir")
@@ -364,6 +366,8 @@ void CResourceHandler::loadFileSystem(const std::string fsConfigURI)
 					resourceLoader->addLoader(mountPoint.first,
 					    shared_ptr<ISimpleResourceLoader>(new CLodArchiveLoader(filename)), false);
 			}
+
+			tlog5 << " took " << timer.getDiff() << " ms.\n";
 		}
 	}
 }

+ 58 - 26
lib/Filesystem/CResourceLoader.h

@@ -71,12 +71,21 @@ public:
 	 */
 	ResourceID();
 
+	/**
+	 * Move Ctor.
+	 */
+	ResourceID(ResourceID && other)
+		: name(std::move(other.name)), type(other.getType())
+	{
+
+	}
+
 	/**
 	 * Ctor. Can be used to create indentifier for resource loading using one parameter
 	 *
 	 * @param name The resource name including extension.
 	 */
-	explicit ResourceID(const std::string & fullName);
+	explicit ResourceID(std::string fullName);
 
 	/**
 	 * Ctor.
@@ -84,7 +93,7 @@ public:
 	 * @param name The resource name.
 	 * @param type The resource type. A constant from the enumeration EResType.
 	 */
-	ResourceID(const std::string & name, EResType::Type type);
+	ResourceID(std::string name, EResType::Type type);
 
 	/**
 	 * Compares this object with a another resource identifier.
@@ -97,6 +106,16 @@ public:
 		return name == other.name && type == other.type;
 	}
 
+	/*
+	 * Move-assignment operator.
+	 */
+	inline ResourceID& operator=(ResourceID && other)
+	{
+		name = std::move(other.name);
+		type = other.getType();
+		return *this;
+	}
+
 	/**
 	 * Gets the name of the identifier.
 	 *
@@ -116,7 +135,7 @@ public:
 	 *
 	 * @param name the name of the identifier. No extension, will be converted to uppercase.
 	 */
-	void setName(const std::string & name);
+	void setName(std::string name);
 
 	/**
 	 * Sets the type of the identifier.
@@ -147,27 +166,40 @@ private:
 	EResType::Type type;
 };
 
-namespace std
+/**
+ 	* Generates a hash value for the resource identifier object.
+ 	*
+ 	* @param resourceIdent The object from which a hash value should be generated.
+ 	* @return the generated hash value
+ 	*/
+inline size_t hash_value(const ResourceID & resourceIdent)
 {
-	/**
-	 * Template specialization for std::hash.
-	 */
-	template <>
-	class hash<ResourceID>
-	{
-public:
-		/**
-		 * Generates a hash value for the resource identifier object.
-		 *
-		 * @param resourceIdent The object from which a hash value should be generated.
-		 * @return the generated hash value
-		 */
-		size_t operator()(const ResourceID & resourceIdent) const
-		{
-			return hash<string>()(resourceIdent.getName()) ^ hash<int>()(static_cast<int>(resourceIdent.getType()));
-		}
-	};
-};
+	boost::hash<int> intHasher;
+	boost::hash<std::string> stringHasher;
+	return stringHasher(resourceIdent.getName()) ^ intHasher(static_cast<int>(resourceIdent.getType()));
+}
+
+// namespace std
+// {
+// 	/**
+// 	 * Template specialization for std::hash.
+// 	 */
+// 	template <>
+// 	class hash<ResourceID>
+// 	{
+// public:
+// 		/**
+// 		 * Generates a hash value for the resource identifier object.
+// 		 *
+// 		 * @param resourceIdent The object from which a hash value should be generated.
+// 		 * @return the generated hash value
+// 		 */
+// 		size_t operator()(const ResourceID & resourceIdent) const
+// 		{
+// 			return hash<string>()(resourceIdent.getName()) ^ hash<int>()(static_cast<int>(resourceIdent.getType()));
+// 		}
+// 	};
+// };
 
 /**
  * This class manages the loading of resources whether standard
@@ -175,7 +207,7 @@ public:
  */
 class DLL_LINKAGE CResourceLoader
 {
-	typedef std::unordered_map<ResourceID, std::list<ResourceLocator> > ResourcesMap;
+	typedef boost::unordered_map<ResourceID, std::vector<ResourceLocator> > ResourcesMap;
 
 public:
 	/// class for iterating over all available files/Identifiers
@@ -259,7 +291,7 @@ public:
 	ResourceLocator getResource(const ResourceID & resourceIdent) const;
 
 	/// returns ALL overriden resources with same name, including last one acessible via getResource
-	const std::list<ResourceLocator> & getResourcesWithName(const ResourceID & resourceIdent) const;
+	const std::vector<ResourceLocator> & getResourcesWithName(const ResourceID & resourceIdent) const;
 
 	/// returns real name of file in filesystem. Not usable for archives
 	std::string getResourceName(const ResourceID & resourceIdent) const;
@@ -309,7 +341,7 @@ public:
 	 */
 	void addLoader(std::string mountPoint, shared_ptr<ISimpleResourceLoader> loader, bool writeable);
 
-private:
+	public:
 
 	/**
 	 * Contains lists of same resources which can be accessed uniquely by an

+ 1 - 1
lib/Filesystem/ISimpleResourceLoader.h

@@ -45,7 +45,7 @@ public:
 	 *
 	 * @return Returns a list of all entries in the archive or (file) system.
 	 */
-	virtual std::unordered_map<ResourceID, std::string> getEntries() const =0;
+	virtual boost::unordered_map<ResourceID, std::string> getEntries() const =0;
 
 	/**
 	 * Gets the origin of the loader.