예제 #1
0
/// Returns a pointer to a newly created suitable subclass of CArchiveBase
CArchiveBase* CArchiveFactory::OpenArchive(const std::string& fileName, const std::string& type)
{
	std::string ext = type;
	if (type.empty()) {
		ext = filesystem.GetExtension(fileName);
	}

	std::string fn = filesystem.LocateFile(fileName);

	CArchiveBase* ret = NULL;

	if (ext == "sd7") {
		ret = new CArchive7Zip(fn);
	} else if (ext == "sdz") {
		ret = new CArchiveZip(fn);
	} else if (ext == "sdd") {
		ret = new CArchiveDir(fn);
	} else if (ext == "sdp") {
		ret = new CArchivePool(fn);
	}

	if (ret && ret->IsOpen()) {
		return ret;
	}

	delete ret;
	return NULL;
}
예제 #2
0
// Returns a pointer to a newly created suitable subclass of CArchiveBase
CArchiveBase* CArchiveFactory::OpenArchive(const std::string& fileName,
                                           const std::string& type)
{
	std::string ext = type;
	if (type.empty()) {
		ext = filesystem.GetExtension(fileName);
	}

	     if (ext == "sd7") { ext = "7z";  }
	else if (ext == "sdz") { ext = "zip"; }
	else if (ext == "sdd") { ext = "dir"; }
	else if (ext == "sdp") { ext = "pool"; }
	else if ((ext == "ccx") || (ext == "hpi") || (ext == "ufo") ||
	         (ext == "gp3") || (ext == "gp4") || (ext == "swx")) {
		ext = "hpi";
	}
	

	std::string fn = filesystem.LocateFile(fileName);

	CArchiveBase* ret = NULL;

	if (ext == "7z") {
		ret = new CArchive7Zip(fn);
	} else if (ext == "zip") {
		ret = new CArchiveZip(fn);
	} else if (ext == "dir") {
		ret = new CArchiveDir(fn);
	} else if (ext == "pool") {
		ret = new CArchivePool(fn);

	} else if (ext == "hpi") {
		ret = new CArchiveHPI(fn);
	}

	if (ret && ret->IsOpen()) {
		return ret;
	}

	delete ret;
	return NULL;
}
// Returns a pointer to a newly created suitable subclass of CArchiveBase
CArchiveBase* CArchiveFactory::OpenArchive(const std::string& fileName)
{
	std::string ext = StringToLower(filesystem.GetExtension(fileName));
	std::string fn = filesystem.LocateFile(fileName);

	CArchiveBase* ret = NULL;

	if (ext == "sd7")
		ret = SAFE_NEW CArchive7Zip(fn);
	else if (ext == "sdz")
		ret = SAFE_NEW CArchiveZip(fn);
	else if (ext == "sdd")
		ret = SAFE_NEW CArchiveDir(fn);
	else if ((ext == "ccx") || (ext == "hpi") || (ext == "ufo") || (ext == "gp3") || (ext == "gp4") || (ext == "swx"))
		ret = SAFE_NEW CArchiveHPI(fn);

	if (ret && ret->IsOpen())
		return ret;

	delete ret;
	return NULL;
}
// Returns a pointer to a newly created suitable subclass of CArchiveBase
CArchiveBase* CArchiveFactory::OpenArchive(const std::string& fileName)
{
	std::string ext = StringToLower(filesystem.GetExtension(fileName));

	std::vector<std::string> filenames = filesystem.GetNativeFilenames(fileName);
	for (std::vector<std::string>::iterator it = filenames.begin(); it != filenames.end(); ++it) {
		CArchiveBase* ret = NULL;

		if (ext == "sd7")
			ret = new CArchive7Zip(*it);
		else if (ext == "sdz")
			ret = new CArchiveZip(*it);
		else if (ext == "sdd")
			ret = new CArchiveDir(*it);
		else if ((ext == "ccx") || (ext == "hpi") || (ext == "ufo") || (ext == "gp3") || (ext == "gp4") || (ext == "swx"))
			ret = new CArchiveHPI(*it);

		if (ret && ret->IsOpen())
			return ret;

		delete ret;
	}
	return NULL;
}
// Returns a pointer to a newly created suitable subclass of CArchiveBase
CArchiveBase* CArchiveFactory::OpenArchive(const string& fileName)
{
	string ext = fileName.substr(fileName.find_last_of('.') + 1);
	transform(ext.begin(), ext.end(), ext.begin(), (int (*)(int))tolower);

	CArchiveBase* ret = NULL;

	if (ext == "sd7")
		ret = new CArchive7ZipDll(fileName);
	if (ext == "sdz")
		ret = new CArchiveZip(fileName);
	else if ((ext == "ccx") || (ext == "hpi") || (ext == "ufo") || (ext == "gp3") || (ext == "gp4") || (ext == "swx"))
		ret = new CArchiveHPI(fileName);

	if (!ret)
		return NULL;

	if (!ret->IsOpen()) {
		delete ret;
		return NULL;
	}

	return ret;
}
예제 #6
0
void CArchiveScanner::ScanArchive(const std::string& fullName, bool doChecksum)
{
	struct stat info;
	stat(fullName.c_str(), &info);

	const std::string fn    = filesystem.GetFilename(fullName);
	const std::string fpath = filesystem.GetDirectory(fullName);
	const std::string lcfn  = StringToLower(fn);

	//! Determine whether this archive has earlier be found to be broken
	std::map<std::string, BrokenArchive>::iterator bai = brokenArchives.find(lcfn);
	if (bai != brokenArchives.end()) {
		if ((unsigned)info.st_mtime == bai->second.modified && fpath == bai->second.path) {
			bai->second.updated = true;
			return;
		}
	}

	//! Determine whether to rely on the cached info or not
	bool cached = false;

	std::map<std::string, ArchiveInfo>::iterator aii = archiveInfo.find(lcfn);
	if (aii != archiveInfo.end()) {

		//! This archive may have been obsoleted, do not process it if so
		if (aii->second.replaced.length() > 0) {
			return;
		}

		if ((unsigned)info.st_mtime == aii->second.modified && fpath == aii->second.path) {
			cached = true;
			aii->second.updated = true;
		}

		//! If we are here, we could have invalid info in the cache
		//! Force a reread if it's a directory archive, as st_mtime only
		//! reflects changes to the directory itself, not the contents.
		if (!cached) {
			archiveInfo.erase(aii);
		}
	}

	//! Time to parse the info we are interested in
	if (cached) {
		//! If cached is true, aii will point to the archive
		if (doChecksum && (aii->second.checksum == 0))
			aii->second.checksum = GetCRC(fullName);
	} else {
		CArchiveBase* ar = CArchiveFactory::OpenArchive(fullName);
		if (!ar || !ar->IsOpen()) {
			logOutput.Print("Unable to open archive: %s", fullName.c_str());
			return;
		}

		ArchiveInfo ai;
		std::string error = "";

		std::string mapfile;
		bool hasModinfo = ar->FileExists("modinfo.lua");
		bool hasMapinfo = ar->FileExists("mapinfo.lua");
		
		//! check for smf/sm3 and if the uncompression of important files is too costy
		for (unsigned fid = 0; fid != ar->NumFiles(); ++fid)
		{
			std::string name;
			int size;
			ar->FileInfo(fid, name, size);
			const std::string lowerName = StringToLower(name);
			const std::string ext = filesystem.GetExtension(lowerName);

			if ((ext == "smf") || (ext == "sm3")) {
				mapfile = name;
			}

			const unsigned char metaFileClass = GetMetaFileClass(lowerName);
			if ((metaFileClass != 0) && !(ar->HasLowReadingCost(fid))) {
				//! is a meta-file and not cheap to read
				if (metaFileClass == 1) {
					//! 1st class
					error = "Unpacking/reading cost for meta file " + name
							+ " is too high, please repack the archive (make sure to use a non-solid algorithm, if applicable)";
					break;
				} else if (metaFileClass == 2) {
					//! 2nd class
					logOutput.Print(LOG_ARCHIVESCANNER,
							"Warning: Archive %s: The cost for reading a 2nd class meta-file is too high: %s",
							fullName.c_str(), name.c_str());
				}
			}
		}

		if (!error.empty()) {
			//! we already have an error, no further evaluation required
		} if (hasMapinfo || !mapfile.empty()) {
			//! it is a map
			if (hasMapinfo) {
				ScanArchiveLua(ar, "mapinfo.lua", ai, error);
			} else if (hasModinfo) {
				//! backwards-compat for modinfo.lua in maps
				ScanArchiveLua(ar, "modinfo.lua", ai, error);
			}
			if (ai.archiveData.GetName().empty()) {
				//! FIXME The name will never be empty, if version is set (see HACK in ArchiveData)
				ai.archiveData.SetInfoItemValueString("name", filesystem.GetBasename(mapfile));
			}
			if (ai.archiveData.GetMapFile().empty()) {
				ai.archiveData.SetInfoItemValueString("mapfile", mapfile);
			}
			AddDependency(ai.archiveData.GetDependencies(), "Map Helper v1");
			ai.archiveData.SetInfoItemValueInteger("modType", modtype::map);

			logOutput.Print(LOG_ARCHIVESCANNER, "Found new map: %s", ai.archiveData.GetName().c_str());
		} else if (hasModinfo) {
			//! it is a mod
			ScanArchiveLua(ar, "modinfo.lua", ai, error);
			if (ai.archiveData.GetModType() == modtype::primary) {
				AddDependency(ai.archiveData.GetDependencies(), "Spring content v1");
			}

			logOutput.Print(LOG_ARCHIVESCANNER, "Found new game: %s", ai.archiveData.GetName().c_str());
		} else {
			//! neither a map nor a mod: error
			error = "missing modinfo.lua/mapinfo.lua";
		}

		delete ar;

		if (!error.empty()) {
			//! for some reason, the archive is marked as broken
			logOutput.Print("Failed to scan %s (%s)", fullName.c_str(), error.c_str());

			//! record it as broken, so we don't need to look inside everytime
			BrokenArchive ba;
			ba.path = fpath;
			ba.modified = info.st_mtime;
			ba.updated = true;
			ba.problem = error;
			brokenArchives[lcfn] = ba;
			return;
		}

		ai.path = fpath;
		ai.modified = info.st_mtime;
		ai.origName = fn;
		ai.updated = true;

		//! Optionally calculate a checksum for the file
		//! To prevent reading all files in all directory (.sdd) archives
		//! every time this function is called, directory archive checksums
		//! are calculated on the fly.
		if (doChecksum) {
			ai.checksum = GetCRC(fullName);
		} else {
			ai.checksum = 0;
		}

		archiveInfo[lcfn] = ai;
	}
}
예제 #7
0
void CArchiveScanner::ScanArchive(const std::string& fullName, bool doChecksum)
{
	struct stat info;
	stat(fullName.c_str(), &info);

	const std::string fn    = filesystem.GetFilename(fullName);
	const std::string fpath = filesystem.GetDirectory(fullName);
	const std::string lcfn  = StringToLower(fn);

	// Determine whether this archive has earlier be found to be broken
	std::map<std::string, BrokenArchive>::iterator bai = brokenArchives.find(lcfn);
	if (bai != brokenArchives.end()) {
		if ((unsigned)info.st_mtime == bai->second.modified && fpath == bai->second.path) {
			bai->second.updated = true;
			return;
		}
	}

	// Determine whether to rely on the cached info or not
	bool cached = false;

	std::map<std::string, ArchiveInfo>::iterator aii = archiveInfo.find(lcfn);
	if (aii != archiveInfo.end()) {

		// This archive may have been obsoleted, do not process it if so
		if (aii->second.replaced.length() > 0) {
			return;
		}

		if ((unsigned)info.st_mtime == aii->second.modified && fpath == aii->second.path) {
			cached = true;
			aii->second.updated = true;
		}

		// If we are here, we could have invalid info in the cache
		// Force a reread if it's a directory archive, as st_mtime only
		// reflects changes to the directory itself, not the contents.
		if (!cached) {
			archiveInfo.erase(aii);
		}
	}

	// Time to parse the info we are interested in
	if (cached) {
		// If cached is true, aii will point to the archive
		if (doChecksum && (aii->second.checksum == 0))
			aii->second.checksum = GetCRC(fullName);
	} else {
		CArchiveBase* ar = CArchiveFactory::OpenArchive(fullName);
		if (ar && ar->IsOpen()) {
			ArchiveInfo ai;

			std::string mapfile;
			bool hasModinfo = false;
			bool hasMapinfo = false;
			for (unsigned fid = 0; fid != ar->NumFiles(); ++fid)
			{
				std::string name;
				int size;
				ar->FileInfo(fid, name, size);

				const std::string lowerName = StringToLower(name);
				const std::string ext = filesystem.GetExtension(lowerName);

				if ((ext == "smf") || (ext == "sm3")) {
					mapfile = name;
				} else if (lowerName == "modinfo.lua") {
					hasModinfo = true;
				} else if (lowerName == "mapinfo.lua") {
					hasMapinfo = true;
				}
			}

			if (hasMapinfo || !mapfile.empty()) {
				// it is a map
				if (hasMapinfo) {
					ScanArchiveLua(ar, "mapinfo.lua", ai);
				} else if (hasModinfo) {
					// backwards-compat for modinfo.lua in maps
					ScanArchiveLua(ar, "modinfo.lua", ai);
				}
				if (ai.archiveData.name.empty()) {
					ai.archiveData.name = filesystem.GetBasename(mapfile);
				}
				if (ai.archiveData.mapfile.empty()) {
					ai.archiveData.mapfile = mapfile;
				}
				AddDependency(ai.archiveData.dependencies, "Map Helper v1");
				ai.archiveData.modType = modtype::map;
				
			} else if (hasModinfo) {
				// it is a mod
				ScanArchiveLua(ar, "modinfo.lua", ai);
				if (ai.archiveData.modType == modtype::primary)
					AddDependency(ai.archiveData.dependencies, "Spring content v1");
			} else {
				// neither a map nor a mod: error
				logOutput.Print(LOG_ARCHIVESCANNER, "Failed to scan %s (missing modinfo.lua/mapinfo.lua)", fullName.c_str());
				delete ar;

				// record it as broken, so we don't need to look inside everytime
				BrokenArchive ba;
				ba.path = fpath;
				ba.modified = info.st_mtime;
				ba.updated = true;
				brokenArchives[lcfn] = ba;
				return;
			}

			ai.path = fpath;
			ai.modified = info.st_mtime;
			ai.origName = fn;
			ai.updated = true;

			delete ar;

			// Optionally calculate a checksum for the file
			// To prevent reading all files in all directory (.sdd) archives
			// every time this function is called, directory archive checksums
			// are calculated on the fly.
			if (doChecksum) {
				ai.checksum = GetCRC(fullName);
			} else {
				ai.checksum = 0;
			}

			archiveInfo[lcfn] = ai;
		} else {
			logOutput.Print(LOG_ARCHIVESCANNER, "Unable to open archive: %s", fullName.c_str());
		}
	}
}