1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

* 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)
This commit is contained in:
Michał W. Urbańczyk 2012-08-08 08:25:27 +00:00
parent 9cbc1f1058
commit cd63c177e2
11 changed files with 114 additions and 65 deletions

View File

@ -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>

View File

@ -1049,17 +1049,20 @@ 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);
try
{
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");
if(read < 50 || !mapBuffer[4])
{
tlog3 << "\t\tWarning: corrupted map file: " << files[start].getName() << std::endl;
}
else //valid map
{
allItems[start].mapInit(files[start].getName(), mapBuffer);
}
catch(std::exception &e)
{
tlog3 << "\t\tWarning: failed to load map " << files[start].getName() << ": " << e.what() << std::endl;
}
start += threads;
}
}

View File

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

View File

@ -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.

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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;
};

View File

@ -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";
}
}
}

View File

@ -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

View File

@ -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.