archivescanner.cpp

来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 731 行 · 第 1/2 页

CPP
731
字号
	for (int i = 0; i < numArs; ++i) {
		ArchiveInfo ai;
		char keyb[100];
		sprintf(keyb, "ArchiveCache\\Archive%d\\", i);
		string key = keyb;

		ai.origName = p.SGetValueDef("", key + "Name");

		ai.path = p.SGetValueDef("", key + "Path");
		ai.modified = strtoul(p.SGetValueDef("0", key + "Modified").c_str(), 0, 10);
		ai.checksum = strtoul(p.SGetValueDef("0", key + "Checksum").c_str(), 0, 10);
		ai.updated = false;

		int numMaps = atoi(p.SGetValueDef("0", key + "NumMaps").c_str());
		for (int m = 0; m < numMaps; ++m) {
			char mapb[100];
			sprintf(mapb, "%sMap%d\\", key.c_str(), m);
			string map = mapb;

			MapData md;
			md.name = p.SGetValueDef("", map + "Name");
			md.virtualPath = p.SGetValueDef("", map + "VirtualPath");

			ai.mapData.push_back(md);
		}

		if (p.SectionExist(key + "Mod")) {
			ai.modData = GetModData(&p, key + "Mod");
		}

		string lcname = StringToLower(ai.origName);

		archiveInfo[lcname] = ai;
	}

	isDirty = false;
}

void CArchiveScanner::WriteCacheData(const std::string& filename)
{
	if (!isDirty)
		return;

	FILE* out = fopen(filename.c_str(), "wt");
	if (!out)
		return;

	// First delete all outdated information
	for (map<string, ArchiveInfo>::iterator i = archiveInfo.begin(); i != archiveInfo.end(); ) {
		map<string, ArchiveInfo>::iterator next = i;
		next++;
		if (!i->second.updated) {
			archiveInfo.erase(i);
		}
		i = next;
	}

	fprintf(out, "[ARCHIVECACHE]\n{\n");
	fprintf(out, "\tNumArchives=%d;\n", archiveInfo.size());
	fprintf(out, "\tInternalVer=%d;\n", INTERNAL_VER);
	int cur = 0;
	for (map<string, ArchiveInfo>::iterator i = archiveInfo.begin(); i != archiveInfo.end(); ++i) {
		fprintf(out, "\t[ARCHIVE%d]\n\t{\n", cur);
		fprintf(out, "\t\tName=%s;\n", i->second.origName.c_str());
		fprintf(out, "\t\tPath=%s;\n", i->second.path.c_str());
		fprintf(out, "\t\tModified=%u;\n", i->second.modified);
		fprintf(out, "\t\tChecksum=%u;\n", i->second.checksum);
		fprintf(out, "\t\tReplaced=%s;\n", i->second.replaced.c_str());

		fprintf(out, "\t\tNumMaps=%d;\n", i->second.mapData.size());
		int curmap = 0;
		for (vector<MapData>::iterator mi = i->second.mapData.begin(); mi != i->second.mapData.end(); ++mi) {
			fprintf(out, "\t\t[MAP%d]\n\t\t{\n", curmap);
			//WriteData(out, *mi);
			fprintf(out, "\t\t\tName=%s;\n", (*mi).name.c_str());
			fprintf(out, "\t\t\tVirtualPath=%s;\n", (*mi).virtualPath.c_str());
			//fprintf(out, "\t\t\tDescription=%s;\n", (*mi).description.c_str());
			fprintf(out, "\t\t}\n");
			curmap++;
		}

		// Any mod info? or just a map archive?
		if (i->second.modData.name != "") {
			const ModData& md = i->second.modData;
			fprintf(out, "\t\t[MOD]\n\t\t{\n");
			fprintf(out, "\t\t\tName=%s;\n",          md.name.c_str());

			if (!md.shortName.empty()) {
				fprintf(out, "\t\t\tShortName=%s;\n",   md.shortName.c_str());
			}
			if (!md.version.empty()) {
				fprintf(out, "\t\t\tVersion=%s;\n",     md.version.c_str());
			}
			if (!md.mutator.empty()) {
				fprintf(out, "\t\t\tMutator=%s;\n",     md.mutator.c_str());
			}
			if (!md.game.empty()) {
				fprintf(out, "\t\t\tGame=%s;\n",        md.game.c_str());
			}
			if (!md.shortGame.empty()) {
				fprintf(out, "\t\t\tShortGame=%s;\n",   md.shortGame.c_str());
			}
			if (!md.description.empty()) {
				fprintf(out, "\t\t\tDescription=%s;\n", md.description.c_str());
			}

			fprintf(out, "\t\t\tModType=%d;\n",     md.modType);

			fprintf(out, "\t\t\tNumDependencies=%d;\n", i->second.modData.dependencies.size());
			int curdep = 0;
			for (vector<string>::iterator dep = i->second.modData.dependencies.begin(); dep != i->second.modData.dependencies.end(); ++dep) {
				fprintf(out, "\t\t\tDepend%d=%s;\n", curdep, (*dep).c_str());
				curdep++;
			}

			fprintf(out, "\t\t\tNumReplaces=%d;\n", i->second.modData.replaces.size());
			int currep = 0;
			for (vector<string>::iterator rep = i->second.modData.replaces.begin(); rep != i->second.modData.replaces.end(); ++rep) {
				fprintf(out, "\t\t\tReplace%d=%s;\n", currep++, (*rep).c_str());
			}

			fprintf(out, "\t\t}\n");
		}

		fprintf(out, "\t}\n");
		cur++;
	}
	fprintf(out, "}\n");
	fclose(out);

	isDirty = false;
}

vector<CArchiveScanner::ModData> CArchiveScanner::GetPrimaryMods() const
{
	vector<ModData> ret;

	for (map<string, ArchiveInfo>::const_iterator i = archiveInfo.begin(); i != archiveInfo.end(); ++i) {
		if (i->second.modData.name != "") {

			if (i->second.modData.modType != 1)
				continue;

			// Add the archive the mod is in as the first dependency
			ModData md = i->second.modData;
			md.dependencies.insert(md.dependencies.begin(), i->second.origName);
			ret.push_back(md);
		}
	}

	return ret;
}

vector<string> CArchiveScanner::GetArchives(const string& root, int depth)
{
	// Protect against circular dependencies
	// (worst case depth is if all archives form one huge dependency chain)
	if ((unsigned)depth > archiveInfo.size()) {
		throw content_error("Circular dependency");
	}

	vector<string> ret;

	string lcname = StringToLower(root);

	map<string, ArchiveInfo>::iterator aii = archiveInfo.find(lcname);
	if (aii == archiveInfo.end())
		return ret;

	// Check if this archive has been replaced
	while (aii->second.replaced.length() > 0) {
		aii = archiveInfo.find(aii->second.replaced);
		if (aii == archiveInfo.end())
			return ret;
	}

	ret.push_back(aii->second.path + aii->second.origName);

	if (aii->second.modData.name == "")
		return ret;

	// add depth-first
	for (vector<string>::iterator i = aii->second.modData.dependencies.begin(); i != aii->second.modData.dependencies.end(); ++i) {
		vector<string> dep = GetArchives(*i, depth + 1);
		for (vector<string>::iterator j = dep.begin(); j != dep.end(); ++j) {
			ret.push_back(*j);
		}
	}

	return ret;
}

vector<string> CArchiveScanner::GetMaps()
{
	vector<string> ret;

	for (map<string, ArchiveInfo>::iterator aii = archiveInfo.begin(); aii != archiveInfo.end(); ++aii) {
		for (vector<MapData>::iterator i = aii->second.mapData.begin(); i != aii->second.mapData.end(); ++i) {
			ret.push_back((*i).name);
		}
	}

	return ret;
}

vector<string> CArchiveScanner::GetArchivesForMap(const string& mapName)
{
	vector<string> ret;

	for (map<string, ArchiveInfo>::iterator aii = archiveInfo.begin(); aii != archiveInfo.end(); ++aii) {
		for (vector<MapData>::iterator i = aii->second.mapData.begin(); i != aii->second.mapData.end(); ++i) {
			if (mapName == (*i).name) {
				return GetArchives(aii->first);
			}
		}
	}

	return ret;
}

unsigned int CArchiveScanner::GetArchiveChecksum(const string& name)
{
	string lcname = name;

	// Strip path-info if present
	if (lcname.find_last_of('\\') != string::npos)
		lcname = lcname.substr(lcname.find_last_of('\\') + 1);
	if (lcname.find_last_of('/') != string::npos)
		lcname = lcname.substr(lcname.find_last_of('/') + 1);

	StringToLowerInPlace(lcname);

	map<string, ArchiveInfo>::iterator aii = archiveInfo.find(lcname);
	if (aii == archiveInfo.end()) {
		return 0;
	}

	return aii->second.checksum;
}

std::string CArchiveScanner::GetArchivePath(const string& name)
{
	string lcname = name;

	// Strip path-info if present
	if (lcname.find_last_of('\\') != string::npos)
		lcname = lcname.substr(lcname.find_last_of('\\') + 1);
	if (lcname.find_last_of('/') != string::npos)
		lcname = lcname.substr(lcname.find_last_of('/') + 1);

	StringToLowerInPlace(lcname);

	map<string, ArchiveInfo>::iterator aii = archiveInfo.find(lcname);
	if (aii == archiveInfo.end()) {
		return 0;
	}

	return aii->second.path;
}

/** Get checksum of all required archives depending on selected mod. */
unsigned int CArchiveScanner::GetModChecksum(const string& root)
{
	unsigned int checksum = 0;
	vector<string> ars = GetArchives(root);

	for (vector<string>::iterator i = ars.begin(); i != ars.end(); ++i)
	{
		checksum ^= GetArchiveChecksum(*i);
	}
	return checksum;
}

/** Get checksum of all required archives depending on selected map. */
unsigned int CArchiveScanner::GetMapChecksum(const string& mapName)
{
	unsigned int checksum = 0;
	vector<string> ars = GetArchivesForMap(mapName);

	for (vector<string>::iterator i = ars.begin(); i != ars.end(); ++i)
		checksum ^= GetArchiveChecksum(*i);
	return checksum;
}

/** Check if calculated mod checksum equals given checksum. Throws content_error if not equal. */
void CArchiveScanner::CheckMod(const string& root, unsigned checksum)
{
	unsigned local = GetModChecksum(root);
	if (local != checksum) {
		throw content_error(
				"Your mod differs from the host's mod. This may be caused by a\n"
				"missing archive, a corrupted download, or there may even be\n"
				"2 different versions in circulation. Make sure you and the host\n"
				"have installed the chosen mod and it's dependencies and\n"
				"consider redownloading the mod.");
	}
}

/** Check if calculated map checksum equals given checksum. Throws content_error if not equal. */
void CArchiveScanner::CheckMap(const string& mapName, unsigned checksum)
{
	unsigned local = GetMapChecksum(mapName);
	if (local != checksum) {
		throw content_error(
				"Your map differs from the host's map. This may be caused by a\n"
				"missing archive, a corrupted download, or there may even be\n"
				"2 different versions in circulation. Make sure you and the host\n"
				"have installed the chosen map and it's dependencies and\n"
				"consider redownloading the map.");
	}
}

/** Convert mod name to mod primary archive, e.g. ModNameToModArchive("XTA v8.1") returns "xtape.sd7". */
std::string CArchiveScanner::ModNameToModArchive(const std::string& s) const
{
	// Convert mod name to mod archive
	std::vector<ModData> found = GetPrimaryMods();
	for (std::vector<ModData>::iterator it = found.begin(); it != found.end(); ++it) {
		if (it->name == s)
			return it->dependencies.front();
	}
	return s;
}

/** The reverse of ModNameToModArchive() */
std::string CArchiveScanner::ModArchiveToModName(const std::string& s) const
{
	// Convert mod archive to mod name
	std::vector<ModData> found = GetPrimaryMods();
	for (std::vector<ModData>::iterator it = found.begin(); it != found.end(); ++it) {
		if (it->dependencies.front() == s) {
			return it->name;
		}
	}
	return s;
}

/** Convert mod name to mod data struct, can return empty ModData */
CArchiveScanner::ModData CArchiveScanner::ModNameToModData(const std::string& s) const
{
	// Convert mod name to mod archive
	std::vector<ModData> found = GetPrimaryMods();
	for (std::vector<ModData>::iterator it = found.begin(); it != found.end(); ++it) {
		const ModData& md = *it;
		if (md.name == s) {
			return md;
		}
	}
	return ModData();
}

/** Convert mod archive to mod data struct, can return empty ModData */
CArchiveScanner::ModData CArchiveScanner::ModArchiveToModData(const std::string& s) const
{
	// Convert mod archive to mod name
	std::vector<ModData> found = GetPrimaryMods();
	for (std::vector<ModData>::iterator it = found.begin(); it != found.end(); ++it) {
		const ModData& md = *it;
		if (md.dependencies.front() == s) {
			return md;
		}
	}
	return ModData();
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?