Example #1
0
/*
===========
G_ClientCleanName
============
*/
static void G_ClientCleanName( const char *in, char *out, int outSize, gclient_t *client )
{
	--outSize;

	bool        has_visible_characters = false;
	std::string out_string;
	bool        hasletter = false;
	int         spaces = 0;

	for ( const auto& token : Color::Parser( in ) )
	{
		if ( out_string.size() + token.Size() > outSize )
		{
			break;
		}

		if ( token.Type() == Color::Token::TokenType::CHARACTER )
		{
			int cp = Q_UTF8_CodePoint(token.Begin());

			// don't allow leading spaces
			// TODO: use a Unicode-aware isspace
			if ( !has_visible_characters && Str::cisspace( cp ) )
			{
				continue;
			}

			// don't allow nonprinting characters or (dead) console keys
			// but do allow UTF-8 (unvalidated)
			if ( cp >= 0 && cp < ' ' )
			{
				continue;
			}

			bool escaped_emote = false;
			// single trailing ^ will mess up some things
			if ( cp == Color::Constants::ESCAPE && !*token.End() )
			{
				if ( out_string.size() + 2 > outSize )
				{
					break;
				}
				out_string += Color::Constants::ESCAPE;
			}
			else if ( !g_emoticonsAllowedInNames.integer && G_IsEmoticon( in, &escaped_emote ) )
			{
				if ( out_string.size() + 2 + token.Size() > outSize )
				{
					break;
				}

				out_string += "[[";
				if ( escaped_emote )
				{
					continue;
				}
			}

			if ( Q_Unicode_IsAlphaOrIdeo( cp ) )
			{
				hasletter = true;
			}

		// don't allow too many consecutive spaces
			// TODO: use a Unicode-aware isspace
			if ( Str::cisspace( cp ) )
			{
				spaces++;
				if ( spaces > 3 )
				{
					continue;
				}
			}
			else
			{
				spaces = 0;
				has_visible_characters = true;
			}
		}
		else if ( token.Type() == Color::Token::TokenType::ESCAPE )
		{
			has_visible_characters = true;
		}

		out_string.append(token.Begin(), token.Size());
	}

	bool invalid = false;

	// don't allow names beginning with S_SKIPNOTIFY because it messes up /ignore-related code
	if ( !out_string.compare( 0, 12, S_SKIPNOTIFY ) )
	{
		invalid = true;
	}

	// don't allow comment-beginning strings because it messes up various parsers
	if ( out_string.find( "//" ) != std::string::npos ||
		out_string.find( "/*" ) != std::string::npos )
	{
		out_string.erase( std::remove( out_string.begin(), out_string.end(), '/' ) );
	}

	// don't allow empty names
	if ( out_string.empty() || !hasletter )
	{
		invalid = true;
	}
	// don't allow names beginning with digits
	else if ( Str::cisdigit( out_string[0] ) )
	{
		out_string.erase( out_string.begin(),
			std::find_if_not( out_string.begin(), out_string.end(), Str::cisdigit ) );
	}

	// if something made the name bad, put them back to UnnamedPlayer
	if ( invalid )
	{
		Q_strncpyz( out, G_UnnamedClientName( client ), outSize );
	}
	else
	{
		Q_strncpyz( out, out_string.c_str(), outSize );
	}
}
Example #2
0
/*
===========
G_ClientCleanName
============
*/
static void G_ClientCleanName( const char *in, char *out, int outSize, gclient_t *client )
{
	int      len, colorlessLen;
	char     *p;
	int      spaces;
	qboolean escaped;
	qboolean invalid = qfalse;
	qboolean hasletter = qfalse;

	//save room for trailing null byte
	outSize--;

	len = 0;
	colorlessLen = 0;
	p = out;
	*p = 0;
	spaces = 0;

	for ( ; *in; in++ )
	{
		int cp, w;

		// don't allow leading spaces
		if ( colorlessLen == 0 && *in == ' ' )
		{
			continue;
		}

		// don't allow nonprinting characters or (dead) console keys
		// but do allow UTF-8 (unvalidated)
		if ( *in >= 0 && *in < ' ' )
		{
			continue;
		}

		// check colors
		if ( Q_IsColorString( in ) )
		{
			in++;

			// make sure room in dest for both chars
			if ( len > outSize - 2 )
			{
				break;
			}

			*out++ = Q_COLOR_ESCAPE;

			*out++ = *in;

			len += 2;
			continue;
		}
		else if ( !g_emoticonsAllowedInNames.integer && G_IsEmoticon( in, &escaped ) )
		{
			// make sure room in dest for both chars
			if ( len > outSize - 2 )
			{
				break;
			}

			*out++ = '[';
			*out++ = '[';
			len += 2;

			if ( escaped )
			{
				in++;
			}

			continue;
		}

		cp = Q_UTF8_CodePoint( in );

		if ( Q_Unicode_IsAlphaOrIdeo( cp ) )
		{
			hasletter = qtrue;
		}

		// don't allow too many consecutive spaces
		if ( *in == ' ' )
		{
			spaces++;

			if ( spaces > 3 )
			{
				continue;
			}
		}
		else
		{
			spaces = 0;
		}

		w = Q_UTF8_WidthCP( cp );

		if ( len > outSize - w )
		{
			break;
		}

		memcpy( out, in, w );
		colorlessLen++;
		len += w;
		out += w;
		in += w - 1; // allow for loop increment
	}

	*out = 0;

	// don't allow names beginning with S_SKIPNOTIFY because it messes up /ignore-related code
	if ( !Q_strnicmp( p, S_SKIPNOTIFY, 12 ) )
	{
		invalid = qtrue;
	}

	// don't allow comment-beginning strings because it messes up various parsers
	if ( strstr( p, "//" ) || strstr( p, "/*" ) )
	{
		invalid = qtrue;
	}

	// don't allow empty names
	if ( *p == 0 || colorlessLen == 0 )
	{
		invalid = qtrue;
	}

	// limit no. of code points
	if ( Q_UTF8_PrintStrlen( p ) > MAX_NAME_LENGTH_CP )
	{
		invalid = qtrue;
	}

	// if something made the name bad, put them back to UnnamedPlayer
	if ( invalid || !hasletter )
	{
		Q_strncpyz( p, G_UnnamedClientName( client ), outSize );
	}
}