mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	- removed CResourceLoader class in favor of one that implements resource loader interface - removed global pool of files, in favour of more dynamic approach - renamed some files to match current situation All these changes are needed mostly for future mod manager + .zip support
		
			
				
	
	
		
			181 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			181 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "StdInc.h"
 | |
| #include "CArchiveLoader.h"
 | |
| 
 | |
| #include "CFileInputStream.h"
 | |
| #include "CCompressedStream.h"
 | |
| 
 | |
| #include "CBinaryReader.h"
 | |
| #include "CFileInfo.h"
 | |
| 
 | |
| ArchiveEntry::ArchiveEntry()
 | |
| 	: offset(0), fullSize(0), compressedSize(0)
 | |
| {
 | |
| 
 | |
| }
 | |
| 
 | |
| CArchiveLoader::CArchiveLoader(const std::string &mountPoint, const std::string & archive):
 | |
|     archive(archive),
 | |
|     mountPoint(mountPoint)
 | |
| {
 | |
| 	// Open archive file(.snd, .vid, .lod)
 | |
| 	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();
 | |
| 	boost::to_upper(ext);
 | |
| 
 | |
| 	// Init the specific lod container format
 | |
| 	if(ext == ".LOD" || ext == ".PAC")
 | |
| 	{
 | |
| 		initLODArchive(mountPoint, fileStream);
 | |
| 	}
 | |
| 	else if(ext == ".VID")
 | |
| 	{
 | |
| 		initVIDArchive(mountPoint, fileStream);
 | |
| 	}
 | |
| 	else if(ext == ".SND")
 | |
| 	{
 | |
| 		initSNDArchive(mountPoint, fileStream);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		throw std::runtime_error("LOD archive format unknown. Cannot deal with " + archive);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void CArchiveLoader::initLODArchive(const std::string &mountPoint, CFileInputStream & fileStream)
 | |
| {
 | |
| 	// Read count of total files
 | |
| 	CBinaryReader reader(&fileStream);
 | |
| 
 | |
| 	fileStream.seek(8);
 | |
| 	ui32 totalFiles = reader.readUInt32();
 | |
| 
 | |
| 	// Get all entries from file
 | |
| 	fileStream.seek(0x5c);
 | |
| 
 | |
| 	// Insert entries to list
 | |
| 	for(ui32 i = 0; i < totalFiles; i++)
 | |
| 	{
 | |
| 		char filename[16];
 | |
| 		reader.read(reinterpret_cast<ui8*>(filename), 16);
 | |
| 
 | |
| 		// Create archive entry
 | |
| 		ArchiveEntry entry;
 | |
| 		entry.name     = filename;
 | |
| 		entry.offset   = reader.readUInt32();
 | |
| 		entry.fullSize = reader.readUInt32();
 | |
| 		fileStream.skip(4); // unused, unknown
 | |
| 		entry.compressedSize     = reader.readUInt32();
 | |
| 
 | |
| 		// Add lod entry to local entries map
 | |
| 		entries[ResourceID(mountPoint + entry.name)] = entry;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void CArchiveLoader::initVIDArchive(const std::string &mountPoint, CFileInputStream & fileStream)
 | |
| {
 | |
| 
 | |
| 	// Read count of total files
 | |
| 	CBinaryReader reader(&fileStream);
 | |
| 	fileStream.seek(0);
 | |
| 	ui32 totalFiles = reader.readUInt32();
 | |
| 
 | |
| 	std::set<int> offsets;
 | |
| 
 | |
| 	// Insert entries to list
 | |
| 	for(ui32 i = 0; i < totalFiles; i++)
 | |
| 	{
 | |
| 		char filename[40];
 | |
| 		reader.read(reinterpret_cast<ui8*>(filename), 40);
 | |
| 
 | |
| 		ArchiveEntry entry;
 | |
| 		entry.name = filename;
 | |
| 		entry.offset = reader.readInt32();
 | |
| 		entry.compressedSize = 0;
 | |
| 
 | |
| 		offsets.insert(entry.offset);
 | |
| 		entries[ResourceID(mountPoint + entry.name)] = entry;
 | |
| 	}
 | |
| 	offsets.insert(fileStream.getSize());
 | |
| 
 | |
| 	// now when we know postion of all files their sizes can be set correctly
 | |
| 	for (auto & entry : entries)
 | |
| 	{
 | |
| 		auto it = offsets.find(entry.second.offset);
 | |
| 		it++;
 | |
| 		entry.second.fullSize = *it - entry.second.offset;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void CArchiveLoader::initSNDArchive(const std::string &mountPoint, CFileInputStream & fileStream)
 | |
| {
 | |
| 	// Read count of total files
 | |
| 	CBinaryReader reader(&fileStream);
 | |
| 	fileStream.seek(0);
 | |
| 	ui32 totalFiles = reader.readUInt32();
 | |
| 
 | |
| 	// Insert entries to list
 | |
| 	for(ui32 i = 0; i < totalFiles; i++)
 | |
| 	{
 | |
| 		char filename[40];
 | |
| 		reader.read(reinterpret_cast<ui8*>(filename), 40);
 | |
| 
 | |
| 		//for some reason entries in snd have format NAME\0WAVRUBBISH....
 | |
| 		//we need to replace first \0 with dot and take the 3 chars with extension (and drop the rest)
 | |
| 		ArchiveEntry entry;
 | |
| 		entry.name  = filename; // till 1st \0
 | |
| 		entry.name += '.';
 | |
| 		entry.name += std::string(filename + entry.name.size(), 3);
 | |
| 
 | |
| 		entry.offset = reader.readInt32();
 | |
| 		entry.fullSize = reader.readInt32();
 | |
| 		entry.compressedSize = 0;
 | |
| 		entries[ResourceID(mountPoint + entry.name)] = entry;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| std::unique_ptr<CInputStream> CArchiveLoader::load(const ResourceID & resourceName) const
 | |
| {
 | |
| 	assert(existsResource(resourceName));
 | |
| 
 | |
| 	const ArchiveEntry & entry = entries.at(resourceName);
 | |
| 
 | |
| 	if (entry.compressedSize != 0) //compressed data
 | |
| 	{
 | |
| 		std::unique_ptr<CInputStream> fileStream(new CFileInputStream(archive, entry.offset, entry.compressedSize));
 | |
| 
 | |
| 		return std::unique_ptr<CInputStream>(new CCompressedStream(std::move(fileStream), false, entry.fullSize));
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		return std::unique_ptr<CInputStream>(new CFileInputStream(archive, entry.offset, entry.fullSize));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| bool CArchiveLoader::existsResource(const ResourceID & resourceName) const
 | |
| {
 | |
| 	return entries.count(resourceName) != 0;
 | |
| }
 | |
| 
 | |
| std::string CArchiveLoader::getMountPoint() const
 | |
| {
 | |
| 	return mountPoint;
 | |
| }
 | |
| 
 | |
| std::unordered_set<ResourceID> CArchiveLoader::getFilteredFiles(std::function<bool(const ResourceID &)> filter) const
 | |
| {
 | |
| 	std::unordered_set<ResourceID> foundID;
 | |
| 
 | |
| 	for (auto & file : entries)
 | |
| 	{
 | |
| 		if (filter(file.first))
 | |
| 			foundID.insert(file.first);
 | |
| 	}
 | |
| 	return foundID;
 | |
| } |