| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | #include "StdInc.h"
 | 
					
						
							|  |  |  | #include "Filesystem.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "CArchiveLoader.h"
 | 
					
						
							|  |  |  | #include "CFilesystemLoader.h"
 | 
					
						
							|  |  |  | #include "AdapterLoaders.h"
 | 
					
						
							| 
									
										
										
										
											2013-07-30 15:02:55 +00:00
										 |  |  | #include "CZipLoader.h"
 | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | //For filesystem initialization
 | 
					
						
							|  |  |  | #include "../JsonNode.h"
 | 
					
						
							|  |  |  | #include "../GameConstants.h"
 | 
					
						
							|  |  |  | #include "../VCMIDirs.h"
 | 
					
						
							|  |  |  | #include "../CStopWatch.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-11 17:12:39 +00:00
										 |  |  | std::map<std::string, ISimpleResourceLoader*> CResourceHandler::knownLoaders = std::map<std::string, ISimpleResourceLoader*>(); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | CFilesystemGenerator::CFilesystemGenerator(std::string prefix): | 
					
						
							|  |  |  | 	filesystem(new CFilesystemList()), | 
					
						
							|  |  |  | 	prefix(prefix) | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | CFilesystemGenerator::TLoadFunctorMap CFilesystemGenerator::genFunctorMap() | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	TLoadFunctorMap map; | 
					
						
							| 
									
										
										
										
											2014-08-04 20:33:59 +02:00
										 |  |  | 	map["map"] = std::bind(&CFilesystemGenerator::loadJsonMap, this, _1, _2); | 
					
						
							|  |  |  | 	map["dir"] = std::bind(&CFilesystemGenerator::loadDirectory, this, _1, _2); | 
					
						
							|  |  |  | 	map["lod"] = std::bind(&CFilesystemGenerator::loadArchive<EResType::ARCHIVE_LOD>, this, _1, _2); | 
					
						
							|  |  |  | 	map["snd"] = std::bind(&CFilesystemGenerator::loadArchive<EResType::ARCHIVE_SND>, this, _1, _2); | 
					
						
							|  |  |  | 	map["vid"] = std::bind(&CFilesystemGenerator::loadArchive<EResType::ARCHIVE_VID>, this, _1, _2); | 
					
						
							|  |  |  | 	map["zip"] = std::bind(&CFilesystemGenerator::loadZipArchive, this, _1, _2); | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	return map; | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | void CFilesystemGenerator::loadConfig(const JsonNode & config) | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	for(auto & mountPoint : config.Struct()) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		for(auto & entry : mountPoint.second.Vector()) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			CStopWatch timer; | 
					
						
							|  |  |  | 			logGlobal->debugStream() << "\t\tLoading resource at " << prefix + entry["path"].String(); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 			auto map = genFunctorMap(); | 
					
						
							|  |  |  | 			auto functor = map.find(entry["type"].String()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (functor != map.end()) | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				functor->second(mountPoint.first, entry); | 
					
						
							|  |  |  | 				logGlobal->debugStream() << "Resource loaded in " << timer.getDiff() << " ms."; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				logGlobal->errorStream() << "Unknown filesystem format: " << functor->first; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | CFilesystemList * CFilesystemGenerator::getFilesystem() | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	return filesystem; | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | void CFilesystemGenerator::loadDirectory(const std::string &mountPoint, const JsonNode & config) | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	std::string URI = prefix + config["path"].String(); | 
					
						
							|  |  |  | 	int depth = 16; | 
					
						
							|  |  |  | 	if (!config["depth"].isNull()) | 
					
						
							| 
									
										
										
										
											2014-08-10 23:42:39 +02:00
										 |  |  | 		depth = (int)config["depth"].Float(); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	ResourceID resID(URI, EResType::DIRECTORY); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	for(auto & loader : CResourceHandler::get("initial")->getResourcesWithName(resID)) | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		auto filename = loader->getResourceName(resID); | 
					
						
							|  |  |  | 		filesystem->addLoader(new CFilesystemLoader(mountPoint, *filename, depth), false); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | void CFilesystemGenerator::loadZipArchive(const std::string &mountPoint, const JsonNode & config) | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	std::string URI = prefix + config["path"].String(); | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	auto filename = CResourceHandler::get("initial")->getResourceName(ResourceID(URI, EResType::ARCHIVE_ZIP)); | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	if (filename) | 
					
						
							|  |  |  | 		filesystem->addLoader(new CZipLoader(mountPoint, *filename), false); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | template<EResType::Type archiveType> | 
					
						
							|  |  |  | void CFilesystemGenerator::loadArchive(const std::string &mountPoint, const JsonNode & config) | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	std::string URI = prefix + config["path"].String(); | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	auto filename = CResourceHandler::get("initial")->getResourceName(ResourceID(URI, archiveType)); | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	if (filename) | 
					
						
							|  |  |  | 		filesystem->addLoader(new CArchiveLoader(mountPoint, *filename), false); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | void CFilesystemGenerator::loadJsonMap(const std::string &mountPoint, const JsonNode & config) | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	std::string URI = prefix + config["path"].String(); | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	auto filename = CResourceHandler::get("initial")->getResourceName(ResourceID(URI, EResType::TEXT)); | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	if (filename) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 		auto configData = CResourceHandler::get("initial")->load(ResourceID(URI, EResType::TEXT))->readAll(); | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 		const JsonNode config((char*)configData.first.get(), configData.second); | 
					
						
							|  |  |  | 		filesystem->addLoader(new CMappedFileLoader(mountPoint, config), false); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | void CResourceHandler::clear() | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	delete knownLoaders["root"]; | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | ISimpleResourceLoader * CResourceHandler::createInitial() | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	//temporary filesystem that will be used to initialize main one.
 | 
					
						
							|  |  |  | 	//used to solve several case-sensivity issues like Mp3 vs MP3
 | 
					
						
							|  |  |  | 	auto initialLoader = new CFilesystemList; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | 	//recurse only into specific directories
 | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	auto recurseInDir = [&](std::string URI, int depth) | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		ResourceID ID(URI, EResType::DIRECTORY); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for(auto & loader : initialLoader->getResourcesWithName(ID)) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			auto filename = loader->getResourceName(ID); | 
					
						
							|  |  |  | 			if (filename) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2014-08-21 22:26:28 +02:00
										 |  |  | 				auto dir = new CFilesystemLoader(URI + '/', *filename, depth, true); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | 				initialLoader->addLoader(dir, false); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (auto & path : VCMIDirs::get().dataPaths()) | 
					
						
							| 
									
										
										
										
											2014-03-04 14:51:10 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		if (boost::filesystem::is_directory(path)) // some of system-provided paths may not exist
 | 
					
						
							| 
									
										
										
										
											2014-08-21 22:26:28 +02:00
										 |  |  | 			initialLoader->addLoader(new CFilesystemLoader("", path, 0, true), false); | 
					
						
							| 
									
										
										
										
											2014-03-04 14:51:10 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-08-21 22:26:28 +02:00
										 |  |  | 	initialLoader->addLoader(new CFilesystemLoader("", VCMIDirs::get().userDataPath(), 0, true), false); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	recurseInDir("CONFIG", 0);// look for configs
 | 
					
						
							|  |  |  | 	recurseInDir("DATA", 0); // look for archives
 | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	recurseInDir("MODS", 64); // look for mods.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return initialLoader; | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | void CResourceHandler::initialize() | 
					
						
							| 
									
										
										
										
											2013-07-30 15:02:55 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	// Create tree-loke structure that looks like this:
 | 
					
						
							|  |  |  | 	// root
 | 
					
						
							|  |  |  | 	// |
 | 
					
						
							|  |  |  | 	// |- initial
 | 
					
						
							|  |  |  | 	// |
 | 
					
						
							|  |  |  | 	// |- data
 | 
					
						
							|  |  |  | 	// |  |-core
 | 
					
						
							|  |  |  | 	// |  |-mod1
 | 
					
						
							|  |  |  | 	// |  |-modN
 | 
					
						
							|  |  |  | 	// |
 | 
					
						
							|  |  |  | 	// |- local
 | 
					
						
							|  |  |  | 	//    |-saves
 | 
					
						
							|  |  |  | 	//    |-config
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	knownLoaders["root"] = new CFilesystemList(); | 
					
						
							| 
									
										
										
										
											2014-08-21 22:26:28 +02:00
										 |  |  | 	knownLoaders["saves"] = new CFilesystemLoader("SAVES/", VCMIDirs::get().userSavePath()); | 
					
						
							|  |  |  | 	knownLoaders["config"] = new CFilesystemLoader("CONFIG/", VCMIDirs::get().userConfigPath()); | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	auto localFS = new CFilesystemList(); | 
					
						
							|  |  |  | 	localFS->addLoader(knownLoaders["saves"], true); | 
					
						
							|  |  |  | 	localFS->addLoader(knownLoaders["config"], true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	addFilesystem("root", "initial", createInitial()); | 
					
						
							|  |  |  | 	addFilesystem("root", "data", new CFilesystemList()); | 
					
						
							|  |  |  | 	addFilesystem("root", "local", localFS); | 
					
						
							| 
									
										
										
										
											2013-07-30 15:02:55 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | ISimpleResourceLoader * CResourceHandler::get() | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	return get("root"); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | ISimpleResourceLoader * CResourceHandler::get(std::string identifier) | 
					
						
							| 
									
										
										
										
											2013-11-11 20:11:51 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	return knownLoaders.at(identifier); | 
					
						
							| 
									
										
										
										
											2013-11-11 20:11:51 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | void CResourceHandler::load(const std::string &fsConfigURI) | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	auto fsConfigData = get("initial")->load(ResourceID(fsConfigURI, EResType::TEXT))->readAll(); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	const JsonNode fsConfig((char*)fsConfigData.first.get(), fsConfigData.second); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 	addFilesystem("data", "core", createFileSystem("", fsConfig["filesystem"])); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | void CResourceHandler::addFilesystem(const std::string & parent, const std::string & identifier, ISimpleResourceLoader * loader) | 
					
						
							| 
									
										
										
										
											2013-12-11 17:12:39 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-12-13 08:53:44 +00:00
										 |  |  | 	assert(knownLoaders.count(identifier) == 0); | 
					
						
							| 
									
										
										
										
											2014-03-08 16:05:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	auto list = dynamic_cast<CFilesystemList *>(knownLoaders.at(parent)); | 
					
						
							|  |  |  | 	assert(list); | 
					
						
							|  |  |  | 	list->addLoader(loader, false); | 
					
						
							| 
									
										
										
										
											2013-12-11 17:12:39 +00:00
										 |  |  | 	knownLoaders[identifier] = loader; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ISimpleResourceLoader * CResourceHandler::createFileSystem(const std::string & prefix, const JsonNode &fsConfig) | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2013-11-08 20:36:26 +00:00
										 |  |  | 	CFilesystemGenerator generator(prefix); | 
					
						
							|  |  |  | 	generator.loadConfig(fsConfig); | 
					
						
							|  |  |  | 	return generator.getFilesystem(); | 
					
						
							| 
									
										
										
										
											2013-07-28 14:49:50 +00:00
										 |  |  | } |