Changeset - r27391:048886674223
[Not reviewed]
src/3rdparty/md5/md5.cpp
Show inline comments
 
@@ -294,13 +294,13 @@ void Md5::Append(const void *data, const
 
	for (; left >= 64; p += 64, left -= 64) this->Process(p);
 

	
 
	/* Process a final partial block. */
 
	if (left) memcpy(this->buf, p, left);
 
}
 

	
 
void Md5::Finish(uint8 digest[16])
 
void Md5::Finish(MD5Hash &digest)
 
{
 
	static const uint8 pad[64] = {
 
		0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 
		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
src/3rdparty/md5/md5.h
Show inline comments
 
@@ -50,21 +50,40 @@
 
  1999-05-03 lpd Original version.
 
 */
 

	
 
#ifndef MD5_INCLUDED
 
#define MD5_INCLUDED
 

	
 
/** The number of bytes in a MD5 hash. */
 
static const size_t MD5_HASH_BYTES = 16;
 

	
 
/** Container for storing a MD5 hash/checksum/digest. */
 
using MD5Hash = std::array<byte, MD5_HASH_BYTES>;
 

	
 
/**
 
 * Exclusively-or one hash into another hash.
 
 * @param lhs The hash to exclusively-or into.
 
 * @param rhs The hash to exclusively-or with.
 
 * @return Reference to \c lhs hash.
 
 */
 
inline MD5Hash &operator^=(MD5Hash &lhs, const MD5Hash &rhs)
 
{
 
	for (size_t i = 0; i < lhs.size(); i++) lhs[i] ^= rhs[i];
 
	return lhs;
 
}
 

	
 

	
 
struct Md5 {
 
private:
 
	uint32 count[2]; ///< message length in bits, lsw first
 
	uint32 abcd[4];  ///< digest buffer
 
	uint8 buf[64];   ///< accumulate block
 

	
 
	void Process(const uint8 *data);
 

	
 
public:
 
	Md5();
 
	void Append(const void *data, const size_t nbytes);
 
	void Finish(uint8 digest[16]);
 
	void Finish(MD5Hash &digest);
 
};
 

	
 
#endif /* MD5_INCLUDED */
src/base_media_base.h
Show inline comments
 
@@ -11,12 +11,13 @@
 
#define BASE_MEDIA_BASE_H
 

	
 
#include "fileio_func.h"
 
#include "gfx_type.h"
 
#include "textfile_type.h"
 
#include "textfile_gui.h"
 
#include "3rdparty/md5/md5.h"
 
#include <unordered_map>
 

	
 
/* Forward declare these; can't do 'struct X' in functions as older GCCs barf on that */
 
struct IniFile;
 
struct ContentInfo;
 

	
 
@@ -28,13 +29,13 @@ struct MD5File {
 
		CR_MATCH,    ///< The file did exist and the md5 checksum did match
 
		CR_MISMATCH, ///< The file did exist, just the md5 checksum did not match
 
		CR_NO_FILE,  ///< The file did not exist
 
	};
 

	
 
	std::string filename;        ///< filename
 
	uint8 hash[16];              ///< md5 sum of the file
 
	MD5Hash hash;                ///< md5 sum of the file
 
	std::string missing_warning; ///< warning when this file is missing
 
	ChecksumResult check_result; ///< cached result of md5 check
 

	
 
	ChecksumResult CheckMD5(Subdirectory subdir, size_t max_size) const;
 
};
 

	
src/base_media_func.h
Show inline comments
 
@@ -96,13 +96,13 @@ bool BaseSet<T, Tnum_files, Tsearch_in_t
 
		item = md5s->GetItem(filename, false);
 
		if (item == nullptr || !item->value.has_value()) {
 
			Debug(grf, 0, "No MD5 checksum specified for: {} (in {})", filename, full_filename);
 
			return false;
 
		}
 
		const char *c = item->value->c_str();
 
		for (uint i = 0; i < sizeof(file->hash) * 2; i++, c++) {
 
		for (size_t i = 0; i < file->hash.size() * 2; i++, c++) {
 
			uint j;
 
			if ('0' <= *c && *c <= '9') {
 
				j = *c - '0';
 
			} else if ('a' <= *c && *c <= 'f') {
 
				j = *c - 'a' + 10;
 
			} else if ('A' <= *c && *c <= 'F') {
 
@@ -282,20 +282,17 @@ template <class Tbase_set> const char *T
 
	for (; s != nullptr; s = s->next) {
 
		if (s->GetNumMissing() != 0) continue;
 

	
 
		if (s->shortname != ci->unique_id) continue;
 
		if (!md5sum) return s->files[0].filename.c_str();
 

	
 
		byte md5[16];
 
		memset(md5, 0, sizeof(md5));
 
		MD5Hash md5;
 
		for (uint i = 0; i < Tbase_set::NUM_FILES; i++) {
 
			for (uint j = 0; j < sizeof(md5); j++) {
 
				md5[j] ^= s->files[i].hash[j];
 
			}
 
			md5 ^= s->files[i].hash;
 
		}
 
		if (memcmp(md5, ci->md5sum, sizeof(md5)) == 0) return s->files[0].filename.c_str();
 
		if (md5 == ci->md5sum) return s->files[0].filename.c_str();
 
	}
 
	return nullptr;
 
}
 

	
 
template <class Tbase_set>
 
/* static */ bool BaseMedia<Tbase_set>::HasSet(const ContentInfo *ci, bool md5sum)
src/fios.cpp
Show inline comments
 
@@ -626,19 +626,18 @@ const char *FiosGetScreenshotDir()
 
	return fios_screenshot_path->c_str();
 
}
 

	
 
/** Basic data to distinguish a scenario. Used in the server list window */
 
struct ScenarioIdentifier {
 
	uint32 scenid;           ///< ID for the scenario (generated by content).
 
	uint8 md5sum[16];        ///< MD5 checksum of file.
 
	MD5Hash md5sum;          ///< MD5 checksum of file.
 
	std::string filename;    ///< filename of the file.
 

	
 
	bool operator == (const ScenarioIdentifier &other) const
 
	{
 
		return this->scenid == other.scenid &&
 
				memcmp(this->md5sum, other.md5sum, sizeof(this->md5sum)) == 0;
 
		return this->scenid == other.scenid && this->md5sum == other.md5sum;
 
	}
 

	
 
	bool operator != (const ScenarioIdentifier &other) const
 
	{
 
		return !(*this == other);
 
	}
 
@@ -711,13 +710,13 @@ static ScenarioScanner _scanner;
 
 */
 
const char *FindScenario(const ContentInfo *ci, bool md5sum)
 
{
 
	_scanner.Scan(false);
 

	
 
	for (ScenarioIdentifier &id : _scanner) {
 
		if (md5sum ? (memcmp(id.md5sum, ci->md5sum, sizeof(id.md5sum)) == 0)
 
		if (md5sum ? (id.md5sum == ci->md5sum)
 
		           : (id.scenid == ci->unique_id)) {
 
			return id.filename.c_str();
 
		}
 
	}
 

	
 
	return nullptr;
src/gamelog.cpp
Show inline comments
 
@@ -103,16 +103,16 @@ void Gamelog::Reset()
 
 * @param output_iterator The iterator to add the GRF info to.
 
 * @param last The end of the buffer
 
 * @param grfid GRF ID
 
 * @param md5sum array of md5sum to print, if known
 
 * @param gc GrfConfig, if known
 
 */
 
static void AddGrfInfo(std::back_insert_iterator<std::string> &output_iterator, uint32_t grfid, const uint8_t *md5sum, const GRFConfig *gc)
 
static void AddGrfInfo(std::back_insert_iterator<std::string> &output_iterator, uint32_t grfid, const MD5Hash *md5sum, const GRFConfig *gc)
 
{
 
	if (md5sum != nullptr) {
 
		fmt::format_to(output_iterator, "GRF ID {:08X}, checksum {}", BSWAP32(grfid), MD5SumToString(md5sum));
 
		fmt::format_to(output_iterator, "GRF ID {:08X}, checksum {}", BSWAP32(grfid), MD5SumToString(*md5sum));
 
	} else {
 
		fmt::format_to(output_iterator, "GRF ID {:08X}", BSWAP32(grfid));
 
	}
 

	
 
	if (gc != nullptr) {
 
		fmt::format_to(output_iterator, ", filename: {} (md5sum matches)", gc->filename);
 
@@ -227,15 +227,15 @@ void Gamelog::Print(std::function<void(c
 
	fmt::format_to(output_iterator, "Setting changed: {} : {} -> {}", this->name, this->oldval, this->newval);
 
}
 

	
 
/* virtual */ void LoggedChangeGRFAdd::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type)
 
{
 
	/* A NewGRF got added to the game, either at the start of the game (never an issue), or later on when it could be an issue. */
 
	const GRFConfig *gc = FindGRFConfig(this->grfid, FGCM_EXACT, this->md5sum);
 
	const GRFConfig *gc = FindGRFConfig(this->grfid, FGCM_EXACT, &this->md5sum);
 
	fmt::format_to(output_iterator, "Added NewGRF: ");
 
	AddGrfInfo(output_iterator, this->grfid, this->md5sum, gc);
 
	AddGrfInfo(output_iterator, this->grfid, &this->md5sum, gc);
 
	auto gm = grf_names.find(this->grfid);
 
	if (gm != grf_names.end() && !gm->second.was_missing) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was already added!");
 
	grf_names[this->grfid] = gc;
 
}
 

	
 
/* virtual */ void LoggedChangeGRFRemoved::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type)
 
@@ -256,15 +256,15 @@ void Gamelog::Print(std::function<void(c
 
	}
 
}
 

	
 
/* virtual */ void LoggedChangeGRFChanged::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type)
 
{
 
	/* Another version of the same NewGRF got loaded. */
 
	const GRFConfig *gc = FindGRFConfig(this->grfid, FGCM_EXACT, this->md5sum);
 
	const GRFConfig *gc = FindGRFConfig(this->grfid, FGCM_EXACT, &this->md5sum);
 
	fmt::format_to(output_iterator, "Compatible NewGRF loaded: ");
 
	AddGrfInfo(output_iterator, this->grfid, this->md5sum, gc);
 
	AddGrfInfo(output_iterator, this->grfid, &this->md5sum, gc);
 
	if (grf_names.count(this->grfid) == 0) fmt::format_to(output_iterator, ". Gamelog inconsistency: GrfID was never added!");
 
	grf_names[this->grfid] = gc;
 
}
 

	
 
/* virtual */ void LoggedChangeGRFParameterChanged::FormatTo(std::back_insert_iterator<std::string> &output_iterator, GrfIDMapping &grf_names, GamelogActionType action_type)
 
{
 
@@ -651,13 +651,13 @@ void Gamelog::GRFUpdate(const GRFConfig 
 
				/* GRF was moved down */
 
				this->GRFMove(ol[o++]->ident.grfid, ni);
 
			} else {
 
				this->GRFMove(nl[n++]->ident.grfid, -(int)oi);
 
			}
 
		} else {
 
			if (memcmp(og->ident.md5sum, ng->ident.md5sum, sizeof(og->ident.md5sum)) != 0) {
 
			if (og->ident.md5sum != ng->ident.md5sum) {
 
				/* md5sum changed, probably loading 'compatible' GRF */
 
				this->GRFCompatible(&nl[n]->ident);
 
			}
 

	
 
			if (og->num_params != ng->num_params || memcmp(og->param, ng->param, og->num_params * sizeof(og->param[0])) != 0) {
 
				this->GRFParameters(ol[o]->ident.grfid);
src/gfxinit.cpp
Show inline comments
 
@@ -412,24 +412,24 @@ MD5File::ChecksumResult MD5File::CheckMD
 
	if (f == nullptr) return CR_NO_FILE;
 

	
 
	size = std::min(size, max_size);
 

	
 
	Md5 checksum;
 
	uint8 buffer[1024];
 
	uint8 digest[16];
 
	MD5Hash digest;
 
	size_t len;
 

	
 
	while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
 
		size -= len;
 
		checksum.Append(buffer, len);
 
	}
 

	
 
	FioFCloseFile(f);
 

	
 
	checksum.Finish(digest);
 
	return memcmp(this->hash, digest, sizeof(this->hash)) == 0 ? CR_MATCH : CR_MISMATCH;
 
	return this->hash == digest ? CR_MATCH : CR_MISMATCH;
 
}
 

	
 
/** Names corresponding to the GraphicsFileType */
 
static const char * const _graphics_file_names[] = { "base", "logos", "arctic", "tropical", "toyland", "extra" };
 

	
 
/** Implementation */
src/misc.cpp
Show inline comments
 
@@ -74,13 +74,13 @@ void InitializeOldNames();
 
std::string GenerateUid(std::string_view subject)
 
{
 
	auto current_time = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
 
	std::string coding_string = fmt::format("{}{}{}", InteractiveRandom(), current_time, subject);
 

	
 
	Md5 checksum;
 
	uint8 digest[16];
 
	MD5Hash digest;
 
	checksum.Append(coding_string.c_str(), coding_string.length());
 
	checksum.Finish(digest);
 

	
 
	return MD5SumToString(digest);
 
}
 

	
src/network/core/game_info.cpp
Show inline comments
 
@@ -161,13 +161,13 @@ const NetworkServerGameInfo *GetCurrentN
 
 * @param config The GRF to handle.
 
 * @param name The name of the NewGRF, empty when unknown.
 
 */
 
static void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config, std::string name)
 
{
 
	/* Find the matching GRF file */
 
	const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, config->ident.md5sum);
 
	const GRFConfig *f = FindGRFConfig(config->ident.grfid, FGCM_EXACT, &config->ident.md5sum);
 
	if (f == nullptr) {
 
		AddGRFTextToList(config->name, name.empty() ? GetString(STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN) : name);
 
		config->status = GCS_NOT_FOUND;
 
	} else {
 
		config->filename = f->filename;
 
		config->name = f->name;
 
@@ -359,29 +359,27 @@ void DeserializeNetworkGameInfo(Packet *
 
 * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet
 
 * @param p    the packet to write the data to.
 
 * @param grf  the GRFIdentifier to serialize.
 
 */
 
void SerializeGRFIdentifier(Packet *p, const GRFIdentifier *grf)
 
{
 
	uint j;
 
	p->Send_uint32(grf->grfid);
 
	for (j = 0; j < sizeof(grf->md5sum); j++) {
 
	for (size_t j = 0; j < grf->md5sum.size(); j++) {
 
		p->Send_uint8(grf->md5sum[j]);
 
	}
 
}
 

	
 
/**
 
 * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet
 
 * @param p    the packet to read the data from.
 
 * @param grf  the GRFIdentifier to deserialize.
 
 */
 
void DeserializeGRFIdentifier(Packet *p, GRFIdentifier *grf)
 
{
 
	uint j;
 
	grf->grfid = p->Recv_uint32();
 
	for (j = 0; j < sizeof(grf->md5sum); j++) {
 
	for (size_t j = 0; j < grf->md5sum.size(); j++) {
 
		grf->md5sum[j] = p->Recv_uint8();
 
	}
 
}
 

	
 
/**
 
 * Deserializes the NamedGRFIdentifier (GRF ID, MD5 checksum and name) from the packet
src/network/core/tcp_content.cpp
Show inline comments
 
@@ -67,13 +67,13 @@ std::optional<std::string> ContentInfo::
 
			tmp = Game::GetScannerInfo()->FindMainScript(this, true);
 
			break;
 
		case CONTENT_TYPE_GAME_LIBRARY:
 
			tmp = Game::GetScannerLibrary()->FindMainScript(this, true);
 
			break;
 
		case CONTENT_TYPE_NEWGRF: {
 
			const GRFConfig *gc = FindGRFConfig(BSWAP32(this->unique_id), FGCM_EXACT, this->md5sum);
 
			const GRFConfig *gc = FindGRFConfig(BSWAP32(this->unique_id), FGCM_EXACT, &this->md5sum);
 
			tmp = gc != nullptr ? gc->filename.c_str() : nullptr;
 
			break;
 
		}
 
		case CONTENT_TYPE_BASE_GRAPHICS:
 
			tmp = TryGetBaseSetFile(this, true, BaseGraphics::GetAvailableSets());
 
			break;
src/network/core/tcp_content_type.h
Show inline comments
 
@@ -9,12 +9,14 @@
 
 * @file tcp_content_type.h Basic types related to the content on the content server.
 
 */
 

	
 
#ifndef NETWORK_CORE_TCP_CONTENT_TYPE_H
 
#define NETWORK_CORE_TCP_CONTENT_TYPE_H
 

	
 
#include "../../3rdparty/md5/md5.h"
 

	
 
/** The values in the enum are important; they are used as database 'keys' */
 
enum ContentType {
 
	CONTENT_TYPE_BEGIN         = 1, ///< Helper to mark the begin of the types
 
	CONTENT_TYPE_BASE_GRAPHICS = 1, ///< The content consists of base graphics
 
	CONTENT_TYPE_NEWGRF        = 2, ///< The content consists of a NewGRF
 
	CONTENT_TYPE_AI            = 3, ///< The content consists of an AI
 
@@ -64,13 +66,13 @@ struct ContentInfo {
 
	std::string filename;                    ///< Filename (for the .tar.gz; only valid on download)
 
	std::string name;                        ///< Name of the content
 
	std::string version;                     ///< Version of the content
 
	std::string url;                         ///< URL related to the content
 
	std::string description;                 ///< Description of the content
 
	uint32 unique_id = 0;                    ///< Unique ID; either GRF ID or shortname
 
	byte md5sum[16] = {0};                   ///< The MD5 checksum
 
	MD5Hash md5sum;                          ///< The MD5 checksum
 
	std::vector<ContentID> dependencies;     ///< The dependencies (unique server side ids)
 
	StringList tags;                         ///< Tags associated with the content
 
	State state = State::UNSELECTED;         ///< Whether the content info is selected (for download)
 
	bool upgrade = false;                    ///< This item is an upgrade
 

	
 
	bool IsSelected() const;
src/network/network.cpp
Show inline comments
 
@@ -187,24 +187,20 @@ std::string GenerateCompanyPasswordHash(
 
		char server_id_char = (i < password_server_id_length ? password_server_id[i] : 0);
 
		char seed_char = password_game_seed >> (i % 32);
 
		salted_password << (char)(password_char ^ server_id_char ^ seed_char); // Cast needed, otherwise interpreted as integer to format
 
	}
 

	
 
	Md5 checksum;
 
	uint8 digest[16];
 
	MD5Hash digest;
 

	
 
	/* Generate the MD5 hash */
 
	std::string salted_password_string = salted_password.str();
 
	checksum.Append(salted_password_string.data(), salted_password_string.size());
 
	checksum.Finish(digest);
 

	
 
	std::ostringstream hashed_password;
 
	hashed_password << std::hex << std::setfill('0');
 
	for (int di = 0; di < 16; di++) hashed_password << std::setw(2) << (int)digest[di]; // Cast needed, otherwise interpreted as character to add
 

	
 
	return hashed_password.str();
 
	return MD5SumToString(digest);
 
}
 

	
 
/**
 
 * Check if the company we want to join requires a password.
 
 * @param company_id id of the company we want to check the 'passworded' flag for.
 
 * @return true if the company requires a password.
src/network/network_client.cpp
Show inline comments
 
@@ -319,13 +319,13 @@ static uint8 _network_server_max_compani
 
std::string _network_server_name;
 

	
 
/** Information about the game to join to. */
 
NetworkJoinInfo _network_join;
 

	
 
/** Make sure the server ID length is the same as a md5 hash. */
 
static_assert(NETWORK_SERVER_ID_LENGTH == 16 * 2 + 1);
 
static_assert(NETWORK_SERVER_ID_LENGTH == MD5_HASH_BYTES * 2 + 1);
 

	
 
/***********
 
 * Sending functions
 
 *   DEF_CLIENT_SEND_COMMAND has no parameters
 
 ************/
 

	
 
@@ -660,13 +660,13 @@ NetworkRecvStatus ClientNetworkGameSocke
 
	/* Check all GRFs */
 
	for (; grf_count > 0; grf_count--) {
 
		GRFIdentifier c;
 
		DeserializeGRFIdentifier(p, &c);
 

	
 
		/* Check whether we know this GRF */
 
		const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum);
 
		const GRFConfig *f = FindGRFConfig(c.grfid, FGCM_EXACT, &c.md5sum);
 
		if (f == nullptr) {
 
			/* We do not know this GRF, bail out of initialization */
 
			Debug(grf, 0, "NewGRF {:08X} not found; checksum {}", BSWAP32(c.grfid), MD5SumToString(c.md5sum));
 
			ret = NETWORK_RECV_STATUS_NEWGRF_MISMATCH;
 
		}
 
	}
src/network/network_content.cpp
Show inline comments
 
@@ -34,13 +34,13 @@ extern bool HasScenario(const ContentInf
 
/** The client we use to connect to the server. */
 
ClientNetworkContentSocketHandler _network_content_client;
 

	
 
/** Wrapper function for the HasProc */
 
static bool HasGRFConfig(const ContentInfo *ci, bool md5sum)
 
{
 
	return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? ci->md5sum : nullptr) != nullptr;
 
	return FindGRFConfig(BSWAP32(ci->unique_id), md5sum ? FGCM_EXACT : FGCM_ANY, md5sum ? &ci->md5sum : nullptr) != nullptr;
 
}
 

	
 
/**
 
 * Check whether a function piece of content is locally known.
 
 * Matches on the unique ID and possibly the MD5 checksum.
 
 * @param ci     the content info to search for
 
@@ -59,13 +59,13 @@ bool ClientNetworkContentSocketHandler::
 
	ci->name        = p->Recv_string(NETWORK_CONTENT_NAME_LENGTH);
 
	ci->version     = p->Recv_string(NETWORK_CONTENT_VERSION_LENGTH);
 
	ci->url         = p->Recv_string(NETWORK_CONTENT_URL_LENGTH);
 
	ci->description = p->Recv_string(NETWORK_CONTENT_DESC_LENGTH, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE);
 

	
 
	ci->unique_id = p->Recv_uint32();
 
	for (uint j = 0; j < sizeof(ci->md5sum); j++) {
 
	for (size_t j = 0; j < ci->md5sum.size(); j++) {
 
		ci->md5sum[j] = p->Recv_uint8();
 
	}
 

	
 
	uint dependency_count = p->Recv_uint8();
 
	ci->dependencies.reserve(dependency_count);
 
	for (uint i = 0; i < dependency_count; i++) {
 
@@ -141,14 +141,13 @@ bool ClientNetworkContentSocketHandler::
 

	
 
	/* Something we don't have and has filesize 0 does not exist in the system */
 
	if (ci->state == ContentInfo::UNSELECTED && ci->filesize == 0) ci->state = ContentInfo::DOES_NOT_EXIST;
 

	
 
	/* Do we already have a stub for this? */
 
	for (ContentInfo *ici : this->infos) {
 
		if (ici->type == ci->type && ici->unique_id == ci->unique_id &&
 
				memcmp(ci->md5sum, ici->md5sum, sizeof(ci->md5sum)) == 0) {
 
		if (ici->type == ci->type && ici->unique_id == ci->unique_id && ci->md5sum == ici->md5sum) {
 
			/* Preserve the name if possible */
 
			if (ci->name.empty()) ci->name = ici->name;
 
			if (ici->IsSelected()) ci->state = ici->state;
 

	
 
			/*
 
			 * As ici might be selected by the content window we cannot delete that.
 
@@ -264,34 +263,34 @@ void ClientNetworkContentSocketHandler::
 
	if (cv == nullptr) return;
 

	
 
	this->Connect();
 

	
 
	assert(cv->size() < 255);
 
	assert(cv->size() < (TCP_MTU - sizeof(PacketSize) - sizeof(byte) - sizeof(uint8)) /
 
			(sizeof(uint8) + sizeof(uint32) + (send_md5sum ? /*sizeof(ContentInfo::md5sum)*/16 : 0)));
 
			(sizeof(uint8) + sizeof(uint32) + (send_md5sum ? MD5_HASH_BYTES : 0)));
 

	
 
	Packet *p = new Packet(send_md5sum ? PACKET_CONTENT_CLIENT_INFO_EXTID_MD5 : PACKET_CONTENT_CLIENT_INFO_EXTID, TCP_MTU);
 
	p->Send_uint8((uint8)cv->size());
 

	
 
	for (const ContentInfo *ci : *cv) {
 
		p->Send_uint8((byte)ci->type);
 
		p->Send_uint32(ci->unique_id);
 
		if (!send_md5sum) continue;
 

	
 
		for (uint j = 0; j < sizeof(ci->md5sum); j++) {
 
		for (size_t j = 0; j < ci->md5sum.size(); j++) {
 
			p->Send_uint8(ci->md5sum[j]);
 
		}
 
	}
 

	
 
	this->SendPacket(p);
 

	
 
	for (ContentInfo *ci : *cv) {
 
		bool found = false;
 
		for (ContentInfo *ci2 : this->infos) {
 
			if (ci->type == ci2->type && ci->unique_id == ci2->unique_id &&
 
					(!send_md5sum || memcmp(ci->md5sum, ci2->md5sum, sizeof(ci->md5sum)) == 0)) {
 
					(!send_md5sum || ci->md5sum == ci2->md5sum)) {
 
				found = true;
 
				break;
 
			}
 
		}
 
		if (!found) {
 
			this->infos.push_back(ci);
src/network/network_gamelist.cpp
Show inline comments
 
@@ -121,13 +121,13 @@ void NetworkAfterNewGRFScan()
 
		/* Reset compatibility state */
 
		item->info.compatible = item->info.version_compatible;
 

	
 
		for (GRFConfig *c = item->info.grfconfig; c != nullptr; c = c->next) {
 
			assert(HasBit(c->flags, GCF_COPY));
 

	
 
			const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum);
 
			const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, &c->ident.md5sum);
 
			if (f == nullptr) {
 
				/* Don't know the GRF (anymore), so mark game incompatible. */
 
				c->status = GCS_NOT_FOUND;
 

	
 
				/* If we miss a file, we're obviously incompatible. */
 
				item->info.compatible = false;
src/newgrf_config.cpp
Show inline comments
 
@@ -43,12 +43,13 @@ GRFConfig::GRFConfig(const std::string &
 
 * Create a new GRFConfig that is a deep copy of an existing config.
 
 * @param config The GRFConfig object to make a copy of.
 
 */
 
GRFConfig::GRFConfig(const GRFConfig &config) :
 
	ZeroedMemoryAllocator(),
 
	ident(config.ident),
 
	original_md5sum(config.original_md5sum),
 
	filename(config.filename),
 
	name(config.name),
 
	info(config.info),
 
	url(config.url),
 
	version(config.version),
 
	min_loadable_version(config.min_loadable_version),
 
@@ -58,13 +59,12 @@ GRFConfig::GRFConfig(const GRFConfig &co
 
	num_params(config.num_params),
 
	num_valid_params(config.num_valid_params),
 
	palette(config.palette),
 
	param_info(config.param_info),
 
	has_param_defaults(config.has_param_defaults)
 
{
 
	MemCpyT<uint8>(this->original_md5sum, config.original_md5sum, lengthof(this->original_md5sum));
 
	MemCpyT<uint32>(this->param, config.param, lengthof(this->param));
 
	if (config.error != nullptr) this->error = std::make_unique<GRFError>(*config.error);
 
}
 

	
 
/**
 
 * Copy the parameter information from the \a src config.
 
@@ -472,23 +472,23 @@ void ResetGRFConfig(bool defaults)
 
 */
 
GRFListCompatibility IsGoodGRFConfigList(GRFConfig *grfconfig)
 
{
 
	GRFListCompatibility res = GLC_ALL_GOOD;
 

	
 
	for (GRFConfig *c = grfconfig; c != nullptr; c = c->next) {
 
		const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum);
 
		const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, &c->ident.md5sum);
 
		if (f == nullptr || HasBit(f->flags, GCF_INVALID)) {
 
			/* If we have not found the exactly matching GRF try to find one with the
 
			 * same grfid, as it most likely is compatible */
 
			f = FindGRFConfig(c->ident.grfid, FGCM_COMPATIBLE, nullptr, c->version);
 
			if (f != nullptr) {
 
				Debug(grf, 1, "NewGRF {:08X} ({}) not found; checksum {}. Compatibility mode on", BSWAP32(c->ident.grfid), c->filename, MD5SumToString(c->ident.md5sum));
 
				if (!HasBit(c->flags, GCF_COMPATIBLE)) {
 
					/* Preserve original_md5sum after it has been assigned */
 
					SetBit(c->flags, GCF_COMPATIBLE);
 
					memcpy(c->original_md5sum, c->ident.md5sum, sizeof(c->original_md5sum));
 
					c->original_md5sum = c->ident.md5sum;
 
				}
 

	
 
				/* Non-found has precedence over compatibility load */
 
				if (res != GLC_NOT_FOUND) res = GLC_COMPATIBLE;
 
				goto compatible_grf;
 
			}
 
@@ -505,13 +505,13 @@ compatible_grf:
 
			 * to load the GRF here, we need the correct filename, so overwrite that
 
			 * in any case and set the name and info when it is not set already.
 
			 * When the GCF_COPY flag is set, it is certain that the filename is
 
			 * already a local one, so there is no need to replace it. */
 
			if (!HasBit(c->flags, GCF_COPY)) {
 
				c->filename = f->filename;
 
				memcpy(c->ident.md5sum, f->ident.md5sum, sizeof(c->ident.md5sum));
 
				c->ident.md5sum = f->ident.md5sum;
 
				c->name = f->name;
 
				c->info = f->name;
 
				c->error = nullptr;
 
				c->version = f->version;
 
				c->min_loadable_version = f->min_loadable_version;
 
				c->num_valid_params = f->num_valid_params;
 
@@ -572,13 +572,13 @@ bool GRFFileScanner::AddFile(const std::
 
		} else {
 
			/* Insert file into list at a position determined by its
 
			 * name, so the list is sorted as we go along */
 
			GRFConfig **pd, *d;
 
			bool stop = false;
 
			for (pd = &_all_grfs; (d = *pd) != nullptr; pd = &d->next) {
 
				if (c->ident.grfid == d->ident.grfid && memcmp(c->ident.md5sum, d->ident.md5sum, sizeof(c->ident.md5sum)) == 0) added = false;
 
				if (c->ident.grfid == d->ident.grfid && c->ident.md5sum == d->ident.md5sum) added = false;
 
				/* Because there can be multiple grfs with the same name, make sure we checked all grfs with the same name,
 
				 *  before inserting the entry. So insert a new grf at the end of all grfs with the same name, instead of
 
				 *  just after the first with the same name. Avoids doubles in the list. */
 
				if (StrCompareIgnoreCase(c->GetName(), d->GetName()) <= 0) {
 
					stop = true;
 
				} else if (stop) {
 
@@ -688,13 +688,13 @@ void ScanNewGRFFiles(NewGRFScanCallback 
 
 * @param grfid GRFID to look for,
 
 * @param mode Restrictions for matching grfs
 
 * @param md5sum Expected MD5 sum
 
 * @param desired_version Requested version
 
 * @return The matching grf, if it exists in #_all_grfs, else \c nullptr.
 
 */
 
const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 *md5sum, uint32 desired_version)
 
const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32 desired_version)
 
{
 
	assert((mode == FGCM_EXACT) != (md5sum == nullptr));
 
	const GRFConfig *best = nullptr;
 
	for (const GRFConfig *c = _all_grfs; c != nullptr; c = c->next) {
 
		/* if md5sum is set, we look for an exact match and continue if not found */
 
		if (!c->ident.HasGrfIdentifier(grfid, md5sum)) continue;
src/newgrf_config.h
Show inline comments
 
@@ -13,12 +13,13 @@
 
#include "strings_type.h"
 
#include "core/alloc_type.hpp"
 
#include "misc/countedptr.hpp"
 
#include "fileio_type.h"
 
#include "textfile_type.h"
 
#include "newgrf_text.h"
 
#include "3rdparty/md5/md5.h"
 

	
 
/** GRF config bit flags */
 
enum GCF_Flags {
 
	GCF_SYSTEM,     ///< GRF file is an openttd-internal system grf
 
	GCF_UNSAFE,     ///< GRF file is unsafe for static usage
 
	GCF_STATIC,     ///< GRF file is used statically (can be used in any MP game)
 
@@ -78,35 +79,32 @@ enum GRFPalette {
 
};
 

	
 

	
 
/** Basic data to distinguish a GRF. Used in the server list window */
 
struct GRFIdentifier {
 
	uint32 grfid;     ///< GRF ID (defined by Action 0x08)
 
	uint8 md5sum[16]; ///< MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF)
 
	MD5Hash md5sum;   ///< MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF)
 

	
 
	GRFIdentifier() = default;
 
	GRFIdentifier(const GRFIdentifier &other) = default;
 
	GRFIdentifier(GRFIdentifier &&other) = default;
 
	GRFIdentifier(uint32 grfid, const uint8 *md5sum) : grfid(grfid)
 
	{
 
		MemCpyT(this->md5sum, md5sum, lengthof(this->md5sum));
 
	}
 
	GRFIdentifier(uint32 grfid, const MD5Hash &md5sum) : grfid(grfid), md5sum(md5sum) {}
 

	
 
	GRFIdentifier& operator =(const GRFIdentifier &other) = default;
 

	
 
	/**
 
	 * Does the identification match the provided values?
 
	 * @param grfid  Expected grfid.
 
	 * @param md5sum Expected md5sum, may be \c nullptr (in which case, do not check it).
 
	 * @return the object has the provided grfid and md5sum.
 
	 */
 
	inline bool HasGrfIdentifier(uint32 grfid, const uint8 *md5sum) const
 
	inline bool HasGrfIdentifier(uint32 grfid, const MD5Hash *md5sum) const
 
	{
 
		if (this->grfid != grfid) return false;
 
		if (md5sum == nullptr) return true;
 
		return memcmp(md5sum, this->md5sum, sizeof(this->md5sum)) == 0;
 
		return *md5sum == this->md5sum;
 
	}
 
};
 

	
 
/** Information about why GRF had problems during initialisation */
 
struct GRFError {
 
	GRFError(StringID severity, StringID message = 0);
 
@@ -155,13 +153,13 @@ struct GRFConfig : ZeroedMemoryAllocator
 
	GRFConfig(const GRFConfig &config);
 

	
 
	/* Remove the copy assignment, as the default implementation will not do the right thing. */
 
	GRFConfig &operator=(GRFConfig &rhs) = delete;
 

	
 
	GRFIdentifier ident; ///< grfid and md5sum to uniquely identify newgrfs
 
	uint8 original_md5sum[16]; ///< MD5 checksum of original file if only a 'compatible' file was loaded
 
	MD5Hash original_md5sum; ///< MD5 checksum of original file if only a 'compatible' file was loaded
 
	std::string filename; ///< Filename - either with or without full path
 
	GRFTextWrapper name; ///< NOSAVE: GRF name (Action 0x08)
 
	GRFTextWrapper info; ///< NOSAVE: GRF info (author, copyright, ...) (Action 0x08)
 
	GRFTextWrapper url; ///< NOSAVE: URL belonging to this GRF.
 
	std::unique_ptr<GRFError> error; ///< NOSAVE: Error/Warning during GRF loading (Action 0x0B)
 

	
 
@@ -214,13 +212,13 @@ struct NewGRFScanCallback {
 
	virtual void OnNewGRFsScanned() = 0;
 
};
 

	
 
size_t GRFGetSizeOfDataSection(FILE *f);
 

	
 
void ScanNewGRFFiles(NewGRFScanCallback *callback);
 
const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const uint8 *md5sum = nullptr, uint32 desired_version = 0);
 
const GRFConfig *FindGRFConfig(uint32 grfid, FindGRFConfigMode mode, const MD5Hash *md5sum = nullptr, uint32 desired_version = 0);
 
GRFConfig *GetGRFConfig(uint32 grfid, uint32 mask = 0xFFFFFFFF);
 
GRFConfig **CopyGRFConfigList(GRFConfig **dst, const GRFConfig *src, bool init_only);
 
void AppendStaticGRFConfigs(GRFConfig **dst);
 
void AppendToGRFConfigList(GRFConfig **dst, GRFConfig *el);
 
void ClearGRFConfigList(GRFConfig **config);
 
void ResetGRFConfig(bool defaults);
src/newgrf_gui.cpp
Show inline comments
 
@@ -1242,13 +1242,13 @@ struct NewGRFWindow : public Window, New
 
				/* Search the list for items that are now found and mark them as such. */
 
				for (GRFConfig **l = &this->actives; *l != nullptr; l = &(*l)->next) {
 
					GRFConfig *c = *l;
 
					bool compatible = HasBit(c->flags, GCF_COMPATIBLE);
 
					if (c->status != GCS_NOT_FOUND && !compatible) continue;
 

	
 
					const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? c->original_md5sum : c->ident.md5sum);
 
					const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? &c->original_md5sum : &c->ident.md5sum);
 
					if (f == nullptr || HasBit(f->flags, GCF_INVALID)) continue;
 

	
 
					*l = new GRFConfig(*f);
 
					(*l)->next = c->next;
 

	
 
					if (this->active_sel == c) this->active_sel = *l;
 
@@ -1449,13 +1449,13 @@ private:
 
		int i = StrNaturalCompare(a->GetName(), b->GetName(), true); // Sort by name (natural sorting).
 
		if (i != 0) return i < 0;
 

	
 
		i = a->version - b->version;
 
		if (i != 0) return i < 0;
 

	
 
		return memcmp(a->ident.md5sum, b->ident.md5sum, lengthof(b->ident.md5sum)) < 0;
 
		return a->ident.md5sum < b->ident.md5sum;
 
	}
 

	
 
	/** Filter grfs by tags/name */
 
	static bool CDECL TagNameFilter(const GRFConfig * const *a, StringFilter &filter)
 
	{
 
		filter.ResetState();
 
@@ -1470,13 +1470,13 @@ private:
 
		if (!this->avails.NeedRebuild()) return;
 

	
 
		this->avails.clear();
 

	
 
		for (const GRFConfig *c = _all_grfs; c != nullptr; c = c->next) {
 
			bool found = false;
 
			for (const GRFConfig *grf = this->actives; grf != nullptr && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum);
 
			for (const GRFConfig *grf = this->actives; grf != nullptr && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum);
 
			if (found) continue;
 

	
 
			if (_settings_client.gui.newgrf_show_old_versions) {
 
				this->avails.push_back(c);
 
			} else {
 
				const GRFConfig *best = FindGRFConfig(c->ident.grfid, HasBit(c->flags, GCF_INVALID) ? FGCM_NEWEST : FGCM_NEWEST_VALID);
 
@@ -1487,13 +1487,13 @@ private:
 
				 * If the best version is 0, then all NewGRF with this GRF ID
 
				 * have version 0, so for backward compatibility reasons we
 
				 * want to show them all.
 
				 * If we are the best version, then we definitely want to
 
				 * show that NewGRF!.
 
				 */
 
				if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum)) {
 
				if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, &c->ident.md5sum)) {
 
					this->avails.push_back(c);
 
				}
 
			}
 
		}
 

	
 
		this->avails.Filter(this->string_filter);
 
@@ -1572,13 +1572,13 @@ void ShowMissingContentWindow(const GRFC
 

	
 
		ContentInfo *ci = new ContentInfo();
 
		ci->type = CONTENT_TYPE_NEWGRF;
 
		ci->state = ContentInfo::DOES_NOT_EXIST;
 
		ci->name = c->GetName();
 
		ci->unique_id = BSWAP32(c->ident.grfid);
 
		memcpy(ci->md5sum, HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum, sizeof(ci->md5sum));
 
		ci->md5sum = HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum;
 
		cv.push_back(ci);
 
	}
 
	ShowNetworkContentListWindow(cv.size() == 0 ? nullptr : &cv, CONTENT_TYPE_NEWGRF);
 
}
 

	
 
Listing NewGRFWindow::last_sorting     = {false, 0};
src/script/script_scanner.cpp
Show inline comments
 
@@ -151,48 +151,45 @@ std::string ScriptScanner::GetConsoleLis
 

	
 
	return p;
 
}
 

	
 
/** Helper for creating a MD5sum of all files within of a script. */
 
struct ScriptFileChecksumCreator : FileScanner {
 
	byte md5sum[16];  ///< The final md5sum.
 
	MD5Hash md5sum; ///< The final md5sum.
 
	Subdirectory dir; ///< The directory to look in.
 

	
 
	/**
 
	 * Initialise the md5sum to be all zeroes,
 
	 * so we can easily xor the data.
 
	 */
 
	ScriptFileChecksumCreator(Subdirectory dir)
 
	{
 
		this->dir = dir;
 
		memset(this->md5sum, 0, sizeof(this->md5sum));
 
	}
 
	ScriptFileChecksumCreator(Subdirectory dir) : dir(dir) {}
 

	
 
	/* Add the file and calculate the md5 sum. */
 
	virtual bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename)
 
	{
 
		Md5 checksum;
 
		uint8 buffer[1024];
 
		size_t len, size;
 
		byte tmp_md5sum[16];
 

	
 
		/* Open the file ... */
 
		FILE *f = FioFOpenFile(filename, "rb", this->dir, &size);
 
		if (f == nullptr) return false;
 

	
 
		/* ... calculate md5sum... */
 
		while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
 
			size -= len;
 
			checksum.Append(buffer, len);
 
		}
 

	
 
		MD5Hash tmp_md5sum;
 
		checksum.Finish(tmp_md5sum);
 

	
 
		FioFCloseFile(f);
 

	
 
		/* ... and xor it to the overall md5sum. */
 
		for (uint i = 0; i < sizeof(md5sum); i++) this->md5sum[i] ^= tmp_md5sum[i];
 
		this->md5sum ^= tmp_md5sum;
 

	
 
		return true;
 
	}
 
};
 

	
 
/**
 
@@ -234,13 +231,13 @@ static bool IsSameScript(const ContentIn
 
		 * be in a subdirectory of the script directory; so <dir>/<path>/main.nut. */
 
		const std::string &main_script = info->GetMainScript();
 
		std::string path = main_script.substr(0, main_script.find_last_of(PATHSEPCHAR));
 
		checksum.Scan(".nut", path);
 
	}
 

	
 
	return memcmp(ci->md5sum, checksum.md5sum, sizeof(ci->md5sum)) == 0;
 
	return ci->md5sum == checksum.md5sum;
 
}
 

	
 
bool ScriptScanner::HasScript(const ContentInfo *ci, bool md5sum)
 
{
 
	for (const auto &item : this->info_list) {
 
		if (IsSameScript(ci, md5sum, item.second, this->GetDirectory())) return true;
src/settings.cpp
Show inline comments
 
@@ -966,27 +966,28 @@ static GRFConfig *GRFLoadConfig(IniFile 
 
	if (group == nullptr) return nullptr;
 

	
 
	uint num_grfs = 0;
 
	for (item = group->item; item != nullptr; item = item->next) {
 
		GRFConfig *c = nullptr;
 

	
 
		uint8 grfid_buf[4], md5sum[16];
 
		uint8 grfid_buf[4];
 
		MD5Hash md5sum;
 
		const char *filename = item->name.c_str();
 
		bool has_grfid = false;
 
		bool has_md5sum = false;
 

	
 
		/* Try reading "<grfid>|" and on success, "<md5sum>|". */
 
		has_grfid = DecodeHexText(filename, grfid_buf, lengthof(grfid_buf));
 
		if (has_grfid) {
 
			filename += 1 + 2 * lengthof(grfid_buf);
 
			has_md5sum = DecodeHexText(filename, md5sum, lengthof(md5sum));
 
			if (has_md5sum) filename += 1 + 2 * lengthof(md5sum);
 
			has_md5sum = DecodeHexText(filename, md5sum.data(), md5sum.size());
 
			if (has_md5sum) filename += 1 + 2 * md5sum.size();
 

	
 
			uint32 grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
 
			if (has_md5sum) {
 
				const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, md5sum);
 
				const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum);
 
				if (s != nullptr) c = new GRFConfig(*s);
 
			}
 
			if (c == nullptr && !FioCheckFileExists(filename, NEWGRF_DIR)) {
 
				const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID);
 
				if (s != nullptr) c = new GRFConfig(*s);
 
			}
src/string.cpp
Show inline comments
 
@@ -615,15 +615,15 @@ int CDECL seprintf(char *str, const char
 

	
 
/**
 
 * Convert the md5sum to a hexadecimal string representation
 
 * @param md5sum the md5sum itself
 
 * @return the string representation of the md5sum.
 
 */
 
std::string MD5SumToString(const uint8 md5sum[16])
 
std::string MD5SumToString(const MD5Hash &md5sum)
 
{
 
	return FormatArrayAsHex({md5sum, 16});
 
	return FormatArrayAsHex(md5sum);
 
}
 

	
 

	
 
/* UTF-8 handling routines */
 

	
 

	
src/string_func.h
Show inline comments
 
@@ -26,12 +26,13 @@
 

	
 
#include <iosfwd>
 

	
 
#include "core/bitmath_func.hpp"
 
#include "core/span_type.hpp"
 
#include "string_type.h"
 
#include "3rdparty/md5/md5.h"
 

	
 
char *strecat(char *dst, const char *src, const char *last) NOACCESS(3);
 
char *strecpy(char *dst, const char *src, const char *last) NOACCESS(3);
 
char *stredup(const char *src, const char *last = nullptr) NOACCESS(2);
 

	
 
int CDECL seprintf(char *str, const char *last, const char *format, ...) WARN_FORMAT(3, 4) NOACCESS(2);
 
@@ -87,13 +88,13 @@ static inline size_t ttd_strnlen(const c
 
{
 
	const char *t;
 
	for (t = str; (size_t)(t - str) < maxlen && *t != '\0'; t++) {}
 
	return t - str;
 
}
 

	
 
std::string MD5SumToString(const uint8 md5sum[16]);
 
std::string MD5SumToString(const MD5Hash &md5sum);
 

	
 
bool IsValidChar(WChar key, CharSetFilter afilter);
 

	
 
size_t Utf8Decode(WChar *c, const char *s);
 
size_t Utf8Encode(char *buf, WChar c);
 
size_t Utf8Encode(std::ostreambuf_iterator<char> &buf, WChar c);
0 comments (0 inline, 0 general)