q3rally/engine/code/qcommon/q_shared.c

1653 lines
28 KiB
C
Raw Normal View History

2011-02-18 14:31:32 +00:00
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
2021-03-24 20:13:01 +00:00
Copyright (C) 2002-2021 Q3Rally Team (Per Thormann - q3rally@gmail.com)
2011-02-18 14:31:32 +00:00
This file is part of q3rally source code.
q3rally source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
q3rally source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with q3rally; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
===========================================================================
*/
//
// q_shared.c -- stateless support routines that are included in each code dll
#include "q_shared.h"
// ^[0-9a-zA-Z]
qboolean Q_IsColorString(const char *p) {
if (!p)
return qfalse;
if (p[0] != Q_COLOR_ESCAPE)
return qfalse;
if (p[1] == 0)
return qfalse;
// isalnum expects a signed integer in the range -1 (EOF) to 255, or it might assert on undefined behaviour
// a dereferenced char pointer has the range -128 to 127, so we just need to rangecheck the negative part
if (p[1] < 0)
return qfalse;
if (isalnum(p[1]) == 0)
return qfalse;
return qtrue;
}
2011-02-18 14:31:32 +00:00
float Com_Clamp( float min, float max, float value ) {
if ( value < min ) {
return min;
}
if ( value > max ) {
return max;
}
return value;
}
// STONELANCE
float vectoyaw( const vec3_t vec ) {
float yaw;
if (vec[YAW] == 0 && vec[PITCH] == 0) {
yaw = 0;
} else {
if (vec[PITCH]) {
yaw = ( atan2( vec[YAW], vec[PITCH]) * M_180_PI );
} else if (vec[YAW] > 0) {
yaw = 90;
} else {
yaw = 270;
}
if (yaw < 0) {
yaw += 360;
}
}
return yaw;
}
/*
=============
VectorToString
This is just a convenience function
for printing vectors
=============
*/
char *vtos( const vec3_t v ) {
static int index;
static char str[8][64];
char *s;
// use an array so that multiple vtos won't collide
s = str[index];
index = (index + 1)&7;
Com_sprintf (s, 64, "(%.3f %.3f %.3f)", v[0], v[1], v[2]);
return s;
}
char *getStringForTime( int time ){
char *str;
int minutes, seconds, msec;
char sec[3], ms[3];
minutes = time / 60000;
seconds = (time % 60000) / 1000;
msec = (time % 1000) / 10;
if (seconds < 10)
Com_sprintf(sec, sizeof(sec), "0%i", seconds);
else
Com_sprintf(sec, sizeof(sec), "%i", seconds);
if (msec < 10)
Com_sprintf(ms, sizeof(ms), "0%i", msec);
else
Com_sprintf(ms, sizeof(ms), "%i", msec);
//Com_sprintf(str, 64, "%i:%s:%s", minutes, sec, ms);
str = va("%i:%s:%s", minutes, sec, ms);
return str;
}
char *getStringForTimeDuration( int startTime, int finishTime){
int delta;
delta = finishTime - startTime;
if (delta < 0)
delta = 0;
return getStringForTime( delta );
}
/*
==============
AngleDifference
returns the difference between the two angles
==============
*/
float AngleDifference(float ang1, float ang2) {
float diff;
diff = ang1 - ang2;
if (ang1 > ang2) {
if (diff > 180.0) diff -= 360.0;
}
else {
if (diff < -180.0) diff += 360.0;
}
return diff;
}
/*
==============
WheelAngle
calculates the angle of the wheels from the car yaw and view yaw
==============
*/
float WheelAngle(float carYaw, float viewYaw){
float angleDiff;
angleDiff = AngleNormalize180(carYaw - viewYaw);
if (angleDiff > 90){
angleDiff = 180 - angleDiff;
}
if (angleDiff < -90){
angleDiff = -180 - angleDiff;
}
if (angleDiff < -30){
angleDiff = -30;
}
if (angleDiff > 30){
angleDiff = 30;
}
return angleDiff;
}
// END
/*
============
COM_SkipPath
============
*/
char *COM_SkipPath (char *pathname)
{
char *last;
last = pathname;
while (*pathname)
{
if (*pathname=='/')
last = pathname+1;
pathname++;
}
return last;
}
/*
============
COM_GetExtension
============
*/
const char *COM_GetExtension( const char *name )
{
const char *dot = strrchr(name, '.'), *slash;
if (dot && (!(slash = strrchr(name, '/')) || slash < dot))
return dot + 1;
else
return "";
2011-02-18 14:31:32 +00:00
}
/*
============
COM_StripExtension
============
*/
void COM_StripExtension( const char *in, char *out, int destsize )
{
const char *dot = strrchr(in, '.'), *slash;
if (dot && (!(slash = strrchr(in, '/')) || slash < dot))
destsize = (destsize < dot-in+1 ? destsize : dot-in+1);
if ( in == out && destsize > 1 )
out[destsize-1] = '\0';
else
Q_strncpyz(out, in, destsize);
}
2011-02-18 14:31:32 +00:00
/*
============
COM_CompareExtension
2011-02-18 14:31:32 +00:00
string compare the end of the strings and return qtrue if strings match
============
*/
qboolean COM_CompareExtension(const char *in, const char *ext)
{
int inlen, extlen;
inlen = strlen(in);
extlen = strlen(ext);
if(extlen <= inlen)
2011-02-18 14:31:32 +00:00
{
in += inlen - extlen;
if(!Q_stricmp(in, ext))
return qtrue;
2011-02-18 14:31:32 +00:00
}
return qfalse;
2011-02-18 14:31:32 +00:00
}
/*
==================
COM_DefaultExtension
if path doesn't have an extension, then append
the specified one (which should include the .)
2011-02-18 14:31:32 +00:00
==================
*/
void COM_DefaultExtension( char *path, int maxSize, const char *extension )
{
const char *dot = strrchr(path, '.'), *slash;
if (dot && (!(slash = strrchr(path, '/')) || slash < dot))
return;
else
Q_strcat(path, maxSize, extension);
2011-02-18 14:31:32 +00:00
}
/*
============================================================================
BYTE ORDER FUNCTIONS
============================================================================
*/
/*
// can't just use function pointers, or dll linkage can
// mess up when qcommon is included in multiple places
static short (*_BigShort) (short l);
static short (*_LittleShort) (short l);
static int (*_BigLong) (int l);
static int (*_LittleLong) (int l);
static qint64 (*_BigLong64) (qint64 l);
static qint64 (*_LittleLong64) (qint64 l);
static float (*_BigFloat) (const float *l);
static float (*_LittleFloat) (const float *l);
short BigShort(short l){return _BigShort(l);}
short LittleShort(short l) {return _LittleShort(l);}
int BigLong (int l) {return _BigLong(l);}
int LittleLong (int l) {return _LittleLong(l);}
qint64 BigLong64 (qint64 l) {return _BigLong64(l);}
qint64 LittleLong64 (qint64 l) {return _LittleLong64(l);}
float BigFloat (const float *l) {return _BigFloat(l);}
float LittleFloat (const float *l) {return _LittleFloat(l);}
*/
void CopyShortSwap(void *dest, void *src)
{
byte *to = dest, *from = src;
to[0] = from[1];
to[1] = from[0];
}
void CopyLongSwap(void *dest, void *src)
{
byte *to = dest, *from = src;
to[0] = from[3];
to[1] = from[2];
to[2] = from[1];
to[3] = from[0];
}
2011-02-18 14:31:32 +00:00
short ShortSwap (short l)
{
byte b1,b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
short ShortNoSwap (short l)
{
return l;
}
int LongSwap (int l)
{
byte b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
int LongNoSwap (int l)
{
return l;
}
qint64 Long64Swap (qint64 ll)
{
qint64 result;
result.b0 = ll.b7;
result.b1 = ll.b6;
result.b2 = ll.b5;
result.b3 = ll.b4;
result.b4 = ll.b3;
result.b5 = ll.b2;
result.b6 = ll.b1;
result.b7 = ll.b0;
return result;
}
qint64 Long64NoSwap (qint64 ll)
{
return ll;
}
float FloatSwap (const float *f) {
floatint_t out;
out.f = *f;
out.ui = LongSwap(out.ui);
return out.f;
}
float FloatNoSwap (const float *f)
{
return *f;
}
/*
================
Swap_Init
================
*/
/*
void Swap_Init (void)
{
byte swaptest[2] = {1,0};
// set the byte swapping variables in a portable manner
if ( *(short *)swaptest == 1)
{
_BigShort = ShortSwap;
_LittleShort = ShortNoSwap;
_BigLong = LongSwap;
_LittleLong = LongNoSwap;
_BigLong64 = Long64Swap;
_LittleLong64 = Long64NoSwap;
_BigFloat = FloatSwap;
_LittleFloat = FloatNoSwap;
}
else
{
_BigShort = ShortNoSwap;
_LittleShort = ShortSwap;
_BigLong = LongNoSwap;
_LittleLong = LongSwap;
_BigLong64 = Long64NoSwap;
_LittleLong64 = Long64Swap;
_BigFloat = FloatNoSwap;
_LittleFloat = FloatSwap;
}
}
*/
/*
============================================================================
PARSING
============================================================================
*/
static char com_token[MAX_TOKEN_CHARS];
static char com_parsename[MAX_TOKEN_CHARS];
static int com_lines;
static int com_tokenline;
2011-02-18 14:31:32 +00:00
void COM_BeginParseSession( const char *name )
{
com_lines = 1;
com_tokenline = 0;
2011-02-18 14:31:32 +00:00
Com_sprintf(com_parsename, sizeof(com_parsename), "%s", name);
}
int COM_GetCurrentParseLine( void )
{
if ( com_tokenline )
{
return com_tokenline;
}
2011-02-18 14:31:32 +00:00
return com_lines;
}
char *COM_Parse( char **data_p )
{
return COM_ParseExt( data_p, qtrue );
}
void COM_ParseError( char *format, ... )
{
va_list argptr;
static char string[4096];
va_start (argptr, format);
Q_vsnprintf (string, sizeof(string), format, argptr);
va_end (argptr);
Com_Printf("ERROR: %s, line %d: %s\n", com_parsename, COM_GetCurrentParseLine(), string);
2011-02-18 14:31:32 +00:00
}
void COM_ParseWarning( char *format, ... )
{
va_list argptr;
static char string[4096];
va_start (argptr, format);
Q_vsnprintf (string, sizeof(string), format, argptr);
va_end (argptr);
Com_Printf("WARNING: %s, line %d: %s\n", com_parsename, COM_GetCurrentParseLine(), string);
2011-02-18 14:31:32 +00:00
}
/*
==============
COM_Parse
Parse a token out of a string
Will never return NULL, just empty strings
If "allowLineBreaks" is qtrue then an empty
string will be returned if the next token is
a newline.
==============
*/
static char *SkipWhitespace( char *data, qboolean *hasNewLines ) {
int c;
while( (c = *data) <= ' ') {
if( !c ) {
return NULL;
}
if( c == '\n' ) {
com_lines++;
*hasNewLines = qtrue;
}
data++;
}
return data;
}
int COM_Compress( char *data_p ) {
char *in, *out;
int c;
qboolean newline = qfalse, whitespace = qfalse;
in = out = data_p;
if (in) {
while ((c = *in) != 0) {
// skip double slash comments
if ( c == '/' && in[1] == '/' ) {
while (*in && *in != '\n') {
in++;
}
// skip /* */ comments
} else if ( c == '/' && in[1] == '*' ) {
while ( *in && ( *in != '*' || in[1] != '/' ) )
in++;
if ( *in )
in += 2;
// record when we hit a newline
} else if ( c == '\n' || c == '\r' ) {
newline = qtrue;
in++;
// record when we hit whitespace
} else if ( c == ' ' || c == '\t') {
whitespace = qtrue;
in++;
// an actual token
} else {
// if we have a pending newline, emit it (and it counts as whitespace)
if (newline) {
*out++ = '\n';
newline = qfalse;
whitespace = qfalse;
} if (whitespace) {
*out++ = ' ';
whitespace = qfalse;
}
// copy quoted strings unmolested
if (c == '"') {
*out++ = c;
in++;
while (1) {
c = *in;
if (c && c != '"') {
*out++ = c;
in++;
} else {
break;
}
}
if (c == '"') {
*out++ = c;
in++;
}
} else {
*out = c;
out++;
in++;
}
}
}
*out = 0;
2011-02-18 14:31:32 +00:00
}
return out - data_p;
}
char *COM_ParseExt( char **data_p, qboolean allowLineBreaks )
{
int c = 0, len;
qboolean hasNewLines = qfalse;
char *data;
data = *data_p;
len = 0;
com_token[0] = 0;
com_tokenline = 0;
2011-02-18 14:31:32 +00:00
// make sure incoming data is valid
if ( !data )
{
*data_p = NULL;
return com_token;
}
while ( 1 )
{
// skip whitespace
data = SkipWhitespace( data, &hasNewLines );
if ( !data )
{
*data_p = NULL;
return com_token;
}
if ( hasNewLines && !allowLineBreaks )
{
*data_p = data;
return com_token;
}
c = *data;
// skip double slash comments
if ( c == '/' && data[1] == '/' )
{
data += 2;
while (*data && *data != '\n') {
data++;
}
}
// skip /* */ comments
else if ( c=='/' && data[1] == '*' )
{
data += 2;
while ( *data && ( *data != '*' || data[1] != '/' ) )
{
if ( *data == '\n' )
{
com_lines++;
}
2011-02-18 14:31:32 +00:00
data++;
}
if ( *data )
{
data += 2;
}
}
else
{
break;
}
}
// token starts on this line
com_tokenline = com_lines;
2011-02-18 14:31:32 +00:00
// handle quoted strings
if (c == '\"')
{
data++;
while (1)
{
c = *data++;
if (c=='\"' || !c)
{
com_token[len] = 0;
*data_p = ( char * ) data;
return com_token;
}
if ( c == '\n' )
{
com_lines++;
}
2011-02-18 14:31:32 +00:00
if (len < MAX_TOKEN_CHARS - 1)
{
com_token[len] = c;
len++;
}
}
}
// parse a regular word
do
{
if (len < MAX_TOKEN_CHARS - 1)
{
com_token[len] = c;
len++;
}
data++;
c = *data;
} while (c>32);
com_token[len] = 0;
*data_p = ( char * ) data;
return com_token;
}
#if 0
// no longer used
/*
===============
COM_ParseInfos
===============
*/
int COM_ParseInfos( char *buf, int max, char infos[][MAX_INFO_STRING] ) {
char *token;
int count;
char key[MAX_TOKEN_CHARS];
count = 0;
while ( 1 ) {
token = COM_Parse( &buf );
if ( !token[0] ) {
break;
}
if ( strcmp( token, "{" ) ) {
Com_Printf( "Missing { in info file\n" );
break;
}
if ( count == max ) {
Com_Printf( "Max infos exceeded\n" );
break;
}
infos[count][0] = 0;
while ( 1 ) {
token = COM_ParseExt( &buf, qtrue );
if ( !token[0] ) {
Com_Printf( "Unexpected end of info file\n" );
break;
}
if ( !strcmp( token, "}" ) ) {
break;
}
Q_strncpyz( key, token, sizeof( key ) );
token = COM_ParseExt( &buf, qfalse );
if ( !token[0] ) {
strcpy( token, "<NULL>" );
}
Info_SetValueForKey( infos[count], key, token );
}
count++;
}
return count;
}
#endif
/*
==================
COM_MatchToken
==================
*/
void COM_MatchToken( char **buf_p, char *match ) {
char *token;
token = COM_Parse( buf_p );
if ( strcmp( token, match ) ) {
Com_Error( ERR_DROP, "MatchToken: %s != %s", token, match );
}
}
/*
=================
SkipBracedSection
The next token should be an open brace or set depth to 1 if already parsed it.
2011-02-18 14:31:32 +00:00
Skips until a matching close brace is found.
Internal brace depths are properly skipped.
=================
*/
qboolean SkipBracedSection (char **program, int depth) {
2011-02-18 14:31:32 +00:00
char *token;
do {
token = COM_ParseExt( program, qtrue );
if( token[1] == 0 ) {
if( token[0] == '{' ) {
depth++;
}
else if( token[0] == '}' ) {
depth--;
}
}
} while( depth && *program );
return ( depth == 0 );
2011-02-18 14:31:32 +00:00
}
/*
=================
SkipRestOfLine
=================
*/
void SkipRestOfLine ( char **data ) {
char *p;
int c;
p = *data;
if ( !*p )
return;
2011-02-18 14:31:32 +00:00
while ( (c = *p++) != 0 ) {
if ( c == '\n' ) {
com_lines++;
break;
}
}
*data = p;
}
void Parse1DMatrix (char **buf_p, int x, float *m) {
char *token;
int i;
COM_MatchToken( buf_p, "(" );
for (i = 0 ; i < x ; i++) {
token = COM_Parse(buf_p);
m[i] = atof(token);
}
COM_MatchToken( buf_p, ")" );
}
void Parse2DMatrix (char **buf_p, int y, int x, float *m) {
int i;
COM_MatchToken( buf_p, "(" );
for (i = 0 ; i < y ; i++) {
Parse1DMatrix (buf_p, x, m + i * x);
}
COM_MatchToken( buf_p, ")" );
}
void Parse3DMatrix (char **buf_p, int z, int y, int x, float *m) {
int i;
COM_MatchToken( buf_p, "(" );
for (i = 0 ; i < z ; i++) {
Parse2DMatrix (buf_p, y, x, m + i * x*y);
}
COM_MatchToken( buf_p, ")" );
}
/*
===================
Com_HexStrToInt
===================
*/
int Com_HexStrToInt( const char *str )
{
ioquake3 resync to revision 3444 from 3393. Fix GCC 6 misleading-indentation warning add SECURITY.md OpenGL2: Restore adding fixed ambient light when HDR is enabled Few LCC memory fixes. fix a few potential buffer overwrite in Game VM Enable compiler optimization on all macOS architectures Don't allow qagame module to create "botlib.log" at ANY filesystem location Make FS_BuildOSPath for botlib.log consistent with typical usage tiny readme thing Remove extra plus sign from Huff_Compress() Fix VMs being able to change CVAR_PROTECTED cvars Don't register fs_game cvar everywhere just to get the value Don't let VMs change engine latch cvars immediately Fix fs_game '..' reading outside of home and base path Fix VMs forcing engine latch cvar to update to latched value Revert my recent cvar latch changes Revert "Don't let VMs change engine latch cvars immediately" Partially revert "Fix fs_game '..' reading outside of home and base path" Revert "Fix VMs forcing engine latch cvar to update to latched value" Fix exploit to bypass filename restrictions on Windows Changes to systemd q3a.service Fix Q_vsnprintf for mingw-w64 Fix timelimit causing an infinite map ending loop Fix invalid access to cluster 0 in AAS_AreaRouteToGoalArea() Fix negative frag/capturelimit causing an infinite map end loop OpenGL2: Fix dark lightmap on shader in mpteam6 Make FS_InvalidGameDir() consider subdirectories invalid [qcommon] Remove dead serialization code [qcommon] Make several zone variables and functions static. Fix MAC_OS_X_VERSION_MIN_REQUIRED for macOS 10.10 and later Increase q3_ui .arena filename list buffer size to 4096 bytes OpenGL2: Fix crash when BSP has deluxe maps and vertex lit surfaces Support Unicode characters greater than 0xFF in cl_consoleKeys Fix macOS app bundle with space in name OpenGL1: Use glGenTextures instead of hardcoded values Remove CON_FlushIn function and where STDIN needs flushing, use tcflush POSIX function Update libogg from 1.3.2 to 1.3.3 Rename (already updated) libogg-1.3.2 to libogg-1.3.3 Update libvorbis from 1.3.5 to 1.3.6 * Fix CVE-2018-5146 - out-of-bounds write on codebook decoding. * Fix CVE-2017-14632 - free() on unitialized data * Fix CVE-2017-14633 - out-of-bounds read Rename (already updated) libvorbis-1.3.5 to libvorbis-1.3.6 Update opus from 1.1.4 to 1.2.1 Rename (already updated) opus-1.1.4 to opus-1.2.1 Update opusfile from 0.8 to 0.9 Rename (already updated) opusfile-0.8 to opusfile-0.9 First swing at a CONTRIBUTING.md Allow loading system OpenAL library on macOS again Remove duplicate setting of FREETYPE_CFLAGS in Makefile Fix exploit to reset player by sending wrong serverId Fix "Going to CS_ZOMBIE for [clientname]" developer message Fix MSG_Read*String*() functions not being able to read last byte from message
2018-04-07 23:02:52 +00:00
if ( !str )
2011-02-18 14:31:32 +00:00
return -1;
// check for hex code
ioquake3 resync to revision 3444 from 3393. Fix GCC 6 misleading-indentation warning add SECURITY.md OpenGL2: Restore adding fixed ambient light when HDR is enabled Few LCC memory fixes. fix a few potential buffer overwrite in Game VM Enable compiler optimization on all macOS architectures Don't allow qagame module to create "botlib.log" at ANY filesystem location Make FS_BuildOSPath for botlib.log consistent with typical usage tiny readme thing Remove extra plus sign from Huff_Compress() Fix VMs being able to change CVAR_PROTECTED cvars Don't register fs_game cvar everywhere just to get the value Don't let VMs change engine latch cvars immediately Fix fs_game '..' reading outside of home and base path Fix VMs forcing engine latch cvar to update to latched value Revert my recent cvar latch changes Revert "Don't let VMs change engine latch cvars immediately" Partially revert "Fix fs_game '..' reading outside of home and base path" Revert "Fix VMs forcing engine latch cvar to update to latched value" Fix exploit to bypass filename restrictions on Windows Changes to systemd q3a.service Fix Q_vsnprintf for mingw-w64 Fix timelimit causing an infinite map ending loop Fix invalid access to cluster 0 in AAS_AreaRouteToGoalArea() Fix negative frag/capturelimit causing an infinite map end loop OpenGL2: Fix dark lightmap on shader in mpteam6 Make FS_InvalidGameDir() consider subdirectories invalid [qcommon] Remove dead serialization code [qcommon] Make several zone variables and functions static. Fix MAC_OS_X_VERSION_MIN_REQUIRED for macOS 10.10 and later Increase q3_ui .arena filename list buffer size to 4096 bytes OpenGL2: Fix crash when BSP has deluxe maps and vertex lit surfaces Support Unicode characters greater than 0xFF in cl_consoleKeys Fix macOS app bundle with space in name OpenGL1: Use glGenTextures instead of hardcoded values Remove CON_FlushIn function and where STDIN needs flushing, use tcflush POSIX function Update libogg from 1.3.2 to 1.3.3 Rename (already updated) libogg-1.3.2 to libogg-1.3.3 Update libvorbis from 1.3.5 to 1.3.6 * Fix CVE-2018-5146 - out-of-bounds write on codebook decoding. * Fix CVE-2017-14632 - free() on unitialized data * Fix CVE-2017-14633 - out-of-bounds read Rename (already updated) libvorbis-1.3.5 to libvorbis-1.3.6 Update opus from 1.1.4 to 1.2.1 Rename (already updated) opus-1.1.4 to opus-1.2.1 Update opusfile from 0.8 to 0.9 Rename (already updated) opusfile-0.8 to opusfile-0.9 First swing at a CONTRIBUTING.md Allow loading system OpenAL library on macOS again Remove duplicate setting of FREETYPE_CFLAGS in Makefile Fix exploit to reset player by sending wrong serverId Fix "Going to CS_ZOMBIE for [clientname]" developer message Fix MSG_Read*String*() functions not being able to read last byte from message
2018-04-07 23:02:52 +00:00
if( str[ 0 ] == '0' && str[ 1 ] == 'x' && str[ 2 ] != '\0' )
2011-02-18 14:31:32 +00:00
{
ioquake3 resync to revision 3444 from 3393. Fix GCC 6 misleading-indentation warning add SECURITY.md OpenGL2: Restore adding fixed ambient light when HDR is enabled Few LCC memory fixes. fix a few potential buffer overwrite in Game VM Enable compiler optimization on all macOS architectures Don't allow qagame module to create "botlib.log" at ANY filesystem location Make FS_BuildOSPath for botlib.log consistent with typical usage tiny readme thing Remove extra plus sign from Huff_Compress() Fix VMs being able to change CVAR_PROTECTED cvars Don't register fs_game cvar everywhere just to get the value Don't let VMs change engine latch cvars immediately Fix fs_game '..' reading outside of home and base path Fix VMs forcing engine latch cvar to update to latched value Revert my recent cvar latch changes Revert "Don't let VMs change engine latch cvars immediately" Partially revert "Fix fs_game '..' reading outside of home and base path" Revert "Fix VMs forcing engine latch cvar to update to latched value" Fix exploit to bypass filename restrictions on Windows Changes to systemd q3a.service Fix Q_vsnprintf for mingw-w64 Fix timelimit causing an infinite map ending loop Fix invalid access to cluster 0 in AAS_AreaRouteToGoalArea() Fix negative frag/capturelimit causing an infinite map end loop OpenGL2: Fix dark lightmap on shader in mpteam6 Make FS_InvalidGameDir() consider subdirectories invalid [qcommon] Remove dead serialization code [qcommon] Make several zone variables and functions static. Fix MAC_OS_X_VERSION_MIN_REQUIRED for macOS 10.10 and later Increase q3_ui .arena filename list buffer size to 4096 bytes OpenGL2: Fix crash when BSP has deluxe maps and vertex lit surfaces Support Unicode characters greater than 0xFF in cl_consoleKeys Fix macOS app bundle with space in name OpenGL1: Use glGenTextures instead of hardcoded values Remove CON_FlushIn function and where STDIN needs flushing, use tcflush POSIX function Update libogg from 1.3.2 to 1.3.3 Rename (already updated) libogg-1.3.2 to libogg-1.3.3 Update libvorbis from 1.3.5 to 1.3.6 * Fix CVE-2018-5146 - out-of-bounds write on codebook decoding. * Fix CVE-2017-14632 - free() on unitialized data * Fix CVE-2017-14633 - out-of-bounds read Rename (already updated) libvorbis-1.3.5 to libvorbis-1.3.6 Update opus from 1.1.4 to 1.2.1 Rename (already updated) opus-1.1.4 to opus-1.2.1 Update opusfile from 0.8 to 0.9 Rename (already updated) opusfile-0.8 to opusfile-0.9 First swing at a CONTRIBUTING.md Allow loading system OpenAL library on macOS again Remove duplicate setting of FREETYPE_CFLAGS in Makefile Fix exploit to reset player by sending wrong serverId Fix "Going to CS_ZOMBIE for [clientname]" developer message Fix MSG_Read*String*() functions not being able to read last byte from message
2018-04-07 23:02:52 +00:00
int i, n = 0, len = strlen( str );
2011-02-18 14:31:32 +00:00
ioquake3 resync to revision 3444 from 3393. Fix GCC 6 misleading-indentation warning add SECURITY.md OpenGL2: Restore adding fixed ambient light when HDR is enabled Few LCC memory fixes. fix a few potential buffer overwrite in Game VM Enable compiler optimization on all macOS architectures Don't allow qagame module to create "botlib.log" at ANY filesystem location Make FS_BuildOSPath for botlib.log consistent with typical usage tiny readme thing Remove extra plus sign from Huff_Compress() Fix VMs being able to change CVAR_PROTECTED cvars Don't register fs_game cvar everywhere just to get the value Don't let VMs change engine latch cvars immediately Fix fs_game '..' reading outside of home and base path Fix VMs forcing engine latch cvar to update to latched value Revert my recent cvar latch changes Revert "Don't let VMs change engine latch cvars immediately" Partially revert "Fix fs_game '..' reading outside of home and base path" Revert "Fix VMs forcing engine latch cvar to update to latched value" Fix exploit to bypass filename restrictions on Windows Changes to systemd q3a.service Fix Q_vsnprintf for mingw-w64 Fix timelimit causing an infinite map ending loop Fix invalid access to cluster 0 in AAS_AreaRouteToGoalArea() Fix negative frag/capturelimit causing an infinite map end loop OpenGL2: Fix dark lightmap on shader in mpteam6 Make FS_InvalidGameDir() consider subdirectories invalid [qcommon] Remove dead serialization code [qcommon] Make several zone variables and functions static. Fix MAC_OS_X_VERSION_MIN_REQUIRED for macOS 10.10 and later Increase q3_ui .arena filename list buffer size to 4096 bytes OpenGL2: Fix crash when BSP has deluxe maps and vertex lit surfaces Support Unicode characters greater than 0xFF in cl_consoleKeys Fix macOS app bundle with space in name OpenGL1: Use glGenTextures instead of hardcoded values Remove CON_FlushIn function and where STDIN needs flushing, use tcflush POSIX function Update libogg from 1.3.2 to 1.3.3 Rename (already updated) libogg-1.3.2 to libogg-1.3.3 Update libvorbis from 1.3.5 to 1.3.6 * Fix CVE-2018-5146 - out-of-bounds write on codebook decoding. * Fix CVE-2017-14632 - free() on unitialized data * Fix CVE-2017-14633 - out-of-bounds read Rename (already updated) libvorbis-1.3.5 to libvorbis-1.3.6 Update opus from 1.1.4 to 1.2.1 Rename (already updated) opus-1.1.4 to opus-1.2.1 Update opusfile from 0.8 to 0.9 Rename (already updated) opusfile-0.8 to opusfile-0.9 First swing at a CONTRIBUTING.md Allow loading system OpenAL library on macOS again Remove duplicate setting of FREETYPE_CFLAGS in Makefile Fix exploit to reset player by sending wrong serverId Fix "Going to CS_ZOMBIE for [clientname]" developer message Fix MSG_Read*String*() functions not being able to read last byte from message
2018-04-07 23:02:52 +00:00
for( i = 2; i < len; i++ )
2011-02-18 14:31:32 +00:00
{
char digit;
n *= 16;
digit = tolower( str[ i ] );
if( digit >= '0' && digit <= '9' )
digit -= '0';
else if( digit >= 'a' && digit <= 'f' )
digit = digit - 'a' + 10;
else
return -1;
n += digit;
}
return n;
}
return -1;
}
/*
============================================================================
LIBRARY REPLACEMENT FUNCTIONS
============================================================================
*/
int Q_isprint( int c )
{
if ( c >= 0x20 && c <= 0x7E )
return ( 1 );
return ( 0 );
}
int Q_islower( int c )
{
if (c >= 'a' && c <= 'z')
return ( 1 );
return ( 0 );
}
int Q_isupper( int c )
{
if (c >= 'A' && c <= 'Z')
return ( 1 );
return ( 0 );
}
int Q_isalpha( int c )
{
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
return ( 1 );
return ( 0 );
}
qboolean Q_isanumber( const char *s )
{
char *p;
double UNUSED_VAR d;
2011-02-18 14:31:32 +00:00
if( *s == '\0' )
return qfalse;
d = strtod( s, &p );
2011-02-18 14:31:32 +00:00
return *p == '\0';
}
qboolean Q_isintegral( float f )
{
return (int)f == f;
}
ioquake3 resync to revision 3444 from 3393. Fix GCC 6 misleading-indentation warning add SECURITY.md OpenGL2: Restore adding fixed ambient light when HDR is enabled Few LCC memory fixes. fix a few potential buffer overwrite in Game VM Enable compiler optimization on all macOS architectures Don't allow qagame module to create "botlib.log" at ANY filesystem location Make FS_BuildOSPath for botlib.log consistent with typical usage tiny readme thing Remove extra plus sign from Huff_Compress() Fix VMs being able to change CVAR_PROTECTED cvars Don't register fs_game cvar everywhere just to get the value Don't let VMs change engine latch cvars immediately Fix fs_game '..' reading outside of home and base path Fix VMs forcing engine latch cvar to update to latched value Revert my recent cvar latch changes Revert "Don't let VMs change engine latch cvars immediately" Partially revert "Fix fs_game '..' reading outside of home and base path" Revert "Fix VMs forcing engine latch cvar to update to latched value" Fix exploit to bypass filename restrictions on Windows Changes to systemd q3a.service Fix Q_vsnprintf for mingw-w64 Fix timelimit causing an infinite map ending loop Fix invalid access to cluster 0 in AAS_AreaRouteToGoalArea() Fix negative frag/capturelimit causing an infinite map end loop OpenGL2: Fix dark lightmap on shader in mpteam6 Make FS_InvalidGameDir() consider subdirectories invalid [qcommon] Remove dead serialization code [qcommon] Make several zone variables and functions static. Fix MAC_OS_X_VERSION_MIN_REQUIRED for macOS 10.10 and later Increase q3_ui .arena filename list buffer size to 4096 bytes OpenGL2: Fix crash when BSP has deluxe maps and vertex lit surfaces Support Unicode characters greater than 0xFF in cl_consoleKeys Fix macOS app bundle with space in name OpenGL1: Use glGenTextures instead of hardcoded values Remove CON_FlushIn function and where STDIN needs flushing, use tcflush POSIX function Update libogg from 1.3.2 to 1.3.3 Rename (already updated) libogg-1.3.2 to libogg-1.3.3 Update libvorbis from 1.3.5 to 1.3.6 * Fix CVE-2018-5146 - out-of-bounds write on codebook decoding. * Fix CVE-2017-14632 - free() on unitialized data * Fix CVE-2017-14633 - out-of-bounds read Rename (already updated) libvorbis-1.3.5 to libvorbis-1.3.6 Update opus from 1.1.4 to 1.2.1 Rename (already updated) opus-1.1.4 to opus-1.2.1 Update opusfile from 0.8 to 0.9 Rename (already updated) opusfile-0.8 to opusfile-0.9 First swing at a CONTRIBUTING.md Allow loading system OpenAL library on macOS again Remove duplicate setting of FREETYPE_CFLAGS in Makefile Fix exploit to reset player by sending wrong serverId Fix "Going to CS_ZOMBIE for [clientname]" developer message Fix MSG_Read*String*() functions not being able to read last byte from message
2018-04-07 23:02:52 +00:00
#ifdef _WIN32
/*
=============
Q_vsnprintf
ioquake3 resync to revision 3444 from 3393. Fix GCC 6 misleading-indentation warning add SECURITY.md OpenGL2: Restore adding fixed ambient light when HDR is enabled Few LCC memory fixes. fix a few potential buffer overwrite in Game VM Enable compiler optimization on all macOS architectures Don't allow qagame module to create "botlib.log" at ANY filesystem location Make FS_BuildOSPath for botlib.log consistent with typical usage tiny readme thing Remove extra plus sign from Huff_Compress() Fix VMs being able to change CVAR_PROTECTED cvars Don't register fs_game cvar everywhere just to get the value Don't let VMs change engine latch cvars immediately Fix fs_game '..' reading outside of home and base path Fix VMs forcing engine latch cvar to update to latched value Revert my recent cvar latch changes Revert "Don't let VMs change engine latch cvars immediately" Partially revert "Fix fs_game '..' reading outside of home and base path" Revert "Fix VMs forcing engine latch cvar to update to latched value" Fix exploit to bypass filename restrictions on Windows Changes to systemd q3a.service Fix Q_vsnprintf for mingw-w64 Fix timelimit causing an infinite map ending loop Fix invalid access to cluster 0 in AAS_AreaRouteToGoalArea() Fix negative frag/capturelimit causing an infinite map end loop OpenGL2: Fix dark lightmap on shader in mpteam6 Make FS_InvalidGameDir() consider subdirectories invalid [qcommon] Remove dead serialization code [qcommon] Make several zone variables and functions static. Fix MAC_OS_X_VERSION_MIN_REQUIRED for macOS 10.10 and later Increase q3_ui .arena filename list buffer size to 4096 bytes OpenGL2: Fix crash when BSP has deluxe maps and vertex lit surfaces Support Unicode characters greater than 0xFF in cl_consoleKeys Fix macOS app bundle with space in name OpenGL1: Use glGenTextures instead of hardcoded values Remove CON_FlushIn function and where STDIN needs flushing, use tcflush POSIX function Update libogg from 1.3.2 to 1.3.3 Rename (already updated) libogg-1.3.2 to libogg-1.3.3 Update libvorbis from 1.3.5 to 1.3.6 * Fix CVE-2018-5146 - out-of-bounds write on codebook decoding. * Fix CVE-2017-14632 - free() on unitialized data * Fix CVE-2017-14633 - out-of-bounds read Rename (already updated) libvorbis-1.3.5 to libvorbis-1.3.6 Update opus from 1.1.4 to 1.2.1 Rename (already updated) opus-1.1.4 to opus-1.2.1 Update opusfile from 0.8 to 0.9 Rename (already updated) opusfile-0.8 to opusfile-0.9 First swing at a CONTRIBUTING.md Allow loading system OpenAL library on macOS again Remove duplicate setting of FREETYPE_CFLAGS in Makefile Fix exploit to reset player by sending wrong serverId Fix "Going to CS_ZOMBIE for [clientname]" developer message Fix MSG_Read*String*() functions not being able to read last byte from message
2018-04-07 23:02:52 +00:00
Special wrapper function for Microsoft's broken _vsnprintf() function.
ioquake3 resync to revision 3444 from 3393. Fix GCC 6 misleading-indentation warning add SECURITY.md OpenGL2: Restore adding fixed ambient light when HDR is enabled Few LCC memory fixes. fix a few potential buffer overwrite in Game VM Enable compiler optimization on all macOS architectures Don't allow qagame module to create "botlib.log" at ANY filesystem location Make FS_BuildOSPath for botlib.log consistent with typical usage tiny readme thing Remove extra plus sign from Huff_Compress() Fix VMs being able to change CVAR_PROTECTED cvars Don't register fs_game cvar everywhere just to get the value Don't let VMs change engine latch cvars immediately Fix fs_game '..' reading outside of home and base path Fix VMs forcing engine latch cvar to update to latched value Revert my recent cvar latch changes Revert "Don't let VMs change engine latch cvars immediately" Partially revert "Fix fs_game '..' reading outside of home and base path" Revert "Fix VMs forcing engine latch cvar to update to latched value" Fix exploit to bypass filename restrictions on Windows Changes to systemd q3a.service Fix Q_vsnprintf for mingw-w64 Fix timelimit causing an infinite map ending loop Fix invalid access to cluster 0 in AAS_AreaRouteToGoalArea() Fix negative frag/capturelimit causing an infinite map end loop OpenGL2: Fix dark lightmap on shader in mpteam6 Make FS_InvalidGameDir() consider subdirectories invalid [qcommon] Remove dead serialization code [qcommon] Make several zone variables and functions static. Fix MAC_OS_X_VERSION_MIN_REQUIRED for macOS 10.10 and later Increase q3_ui .arena filename list buffer size to 4096 bytes OpenGL2: Fix crash when BSP has deluxe maps and vertex lit surfaces Support Unicode characters greater than 0xFF in cl_consoleKeys Fix macOS app bundle with space in name OpenGL1: Use glGenTextures instead of hardcoded values Remove CON_FlushIn function and where STDIN needs flushing, use tcflush POSIX function Update libogg from 1.3.2 to 1.3.3 Rename (already updated) libogg-1.3.2 to libogg-1.3.3 Update libvorbis from 1.3.5 to 1.3.6 * Fix CVE-2018-5146 - out-of-bounds write on codebook decoding. * Fix CVE-2017-14632 - free() on unitialized data * Fix CVE-2017-14633 - out-of-bounds read Rename (already updated) libvorbis-1.3.5 to libvorbis-1.3.6 Update opus from 1.1.4 to 1.2.1 Rename (already updated) opus-1.1.4 to opus-1.2.1 Update opusfile from 0.8 to 0.9 Rename (already updated) opusfile-0.8 to opusfile-0.9 First swing at a CONTRIBUTING.md Allow loading system OpenAL library on macOS again Remove duplicate setting of FREETYPE_CFLAGS in Makefile Fix exploit to reset player by sending wrong serverId Fix "Going to CS_ZOMBIE for [clientname]" developer message Fix MSG_Read*String*() functions not being able to read last byte from message
2018-04-07 23:02:52 +00:00
MinGW comes with its own vsnprintf() which is not broken. mingw-w64
however, uses Microsoft's broken _vsnprintf() function.
=============
*/
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
{
int retval;
retval = _vsnprintf(str, size, format, ap);
if(retval < 0 || retval == size)
{
// Microsoft doesn't adhere to the C99 standard of vsnprintf,
// which states that the return value must be the number of
// bytes written if the output string had sufficient length.
//
// Obviously we cannot determine that value from Microsoft's
// implementation, so we have no choice but to return size.
str[size - 1] = '\0';
return size;
}
return retval;
}
#endif
2011-02-18 14:31:32 +00:00
/*
=============
Q_strncpyz
Safe strncpy that ensures a trailing zero
=============
*/
void Q_strncpyz( char *dest, const char *src, int destsize ) {
if ( !dest ) {
Com_Error( ERR_FATAL, "Q_strncpyz: NULL dest" );
}
if ( !src ) {
Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
}
if ( destsize < 1 ) {
Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
}
strncpy( dest, src, destsize-1 );
dest[destsize-1] = 0;
}
int Q_stricmpn (const char *s1, const char *s2, int n) {
int c1, c2;
if ( s1 == NULL ) {
if ( s2 == NULL )
return 0;
else
return -1;
}
else if ( s2==NULL )
return 1;
do {
c1 = *s1++;
c2 = *s2++;
if (!n--) {
return 0; // strings are equal until end point
}
if (c1 != c2) {
if (c1 >= 'a' && c1 <= 'z') {
c1 -= ('a' - 'A');
}
if (c2 >= 'a' && c2 <= 'z') {
c2 -= ('a' - 'A');
}
if (c1 != c2) {
return c1 < c2 ? -1 : 1;
}
}
} while (c1);
return 0; // strings are equal
}
int Q_strncmp (const char *s1, const char *s2, int n) {
int c1, c2;
do {
c1 = *s1++;
c2 = *s2++;
if (!n--) {
return 0; // strings are equal until end point
}
if (c1 != c2) {
return c1 < c2 ? -1 : 1;
}
} while (c1);
return 0; // strings are equal
}
int Q_stricmp (const char *s1, const char *s2) {
return (s1 && s2) ? Q_stricmpn (s1, s2, 99999) : -1;
}
char *Q_strlwr( char *s1 ) {
char *s;
s = s1;
while ( *s ) {
*s = tolower(*s);
s++;
}
return s1;
}
char *Q_strupr( char *s1 ) {
char *s;
s = s1;
while ( *s ) {
*s = toupper(*s);
s++;
}
return s1;
}
// never goes past bounds or leaves without a terminating 0
void Q_strcat( char *dest, int size, const char *src ) {
int l1;
l1 = strlen( dest );
if ( l1 >= size ) {
Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
}
Q_strncpyz( dest + l1, src, size - l1 );
}
/*
* Find the first occurrence of find in s.
*/
const char *Q_stristr( const char *s, const char *find)
{
char c, sc;
size_t len;
if ((c = *find++) != 0)
{
if (c >= 'a' && c <= 'z')
{
c -= ('a' - 'A');
}
len = strlen(find);
do
{
do
{
if ((sc = *s++) == 0)
return NULL;
if (sc >= 'a' && sc <= 'z')
{
sc -= ('a' - 'A');
}
} while (sc != c);
} while (Q_stricmpn(s, find, len) != 0);
s--;
}
return s;
}
int Q_PrintStrlen( const char *string ) {
int len;
const char *p;
if( !string ) {
return 0;
}
len = 0;
p = string;
while( *p ) {
if( Q_IsColorString( p ) ) {
p += 2;
continue;
}
p++;
len++;
}
return len;
}
char *Q_CleanStr( char *string ) {
char* d;
char* s;
int c;
s = string;
d = string;
while ((c = *s) != 0 ) {
if ( Q_IsColorString( s ) ) {
s++;
}
else if ( c >= 0x20 && c <= 0x7E ) {
*d++ = c;
}
s++;
}
*d = '\0';
return string;
}
int Q_CountChar(const char *string, char tocount)
{
int count;
for(count = 0; *string; string++)
{
if(*string == tocount)
count++;
}
return count;
}
int QDECL Com_sprintf(char *dest, int size, const char *fmt, ...)
{
2011-02-18 14:31:32 +00:00
int len;
va_list argptr;
va_start (argptr,fmt);
len = Q_vsnprintf(dest, size, fmt, argptr);
2011-02-18 14:31:32 +00:00
va_end (argptr);
if(len >= size)
Com_Printf("Com_sprintf: Output length %d too short, require %d bytes.\n", size, len + 1);
return len;
}
2011-02-18 14:31:32 +00:00
/*
============
va
does a varargs printf into a temp buffer, so I don't need to have
varargs versions of all text functions.
============
*/
char * QDECL va( char *format, ... ) {
va_list argptr;
static char string[2][32000]; // in case va is called by nested functions
static int index = 0;
char *buf;
buf = string[index & 1];
index++;
va_start (argptr, format);
Q_vsnprintf (buf, sizeof(*string), format, argptr);
va_end (argptr);
return buf;
}
/*
============
Com_TruncateLongString
Assumes buffer is atleast TRUNCATE_LENGTH big
============
*/
void Com_TruncateLongString( char *buffer, const char *s )
{
int length = strlen( s );
if( length <= TRUNCATE_LENGTH )
Q_strncpyz( buffer, s, TRUNCATE_LENGTH );
else
{
Q_strncpyz( buffer, s, ( TRUNCATE_LENGTH / 2 ) - 3 );
Q_strcat( buffer, TRUNCATE_LENGTH, " ... " );
Q_strcat( buffer, TRUNCATE_LENGTH, s + length - ( TRUNCATE_LENGTH / 2 ) + 3 );
}
}
/*
=====================================================================
INFO STRINGS
=====================================================================
*/
/*
===============
Info_ValueForKey
Searches the string for the given
key and returns the associated value, or an empty string.
FIXME: overflow check?
===============
*/
char *Info_ValueForKey( const char *s, const char *key ) {
char pkey[BIG_INFO_KEY];
static char value[2][BIG_INFO_VALUE]; // use two buffers so compares
// work without stomping on each other
static int valueindex = 0;
char *o;
if ( !s || !key ) {
return "";
}
if ( strlen( s ) >= BIG_INFO_STRING ) {
Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
}
valueindex ^= 1;
if (*s == '\\')
s++;
while (1)
{
o = pkey;
while (*s != '\\')
{
if (!*s)
return "";
*o++ = *s++;
}
*o = 0;
s++;
o = value[valueindex];
while (*s != '\\' && *s)
{
*o++ = *s++;
}
*o = 0;
if (!Q_stricmp (key, pkey) )
return value[valueindex];
if (!*s)
break;
s++;
}
return "";
}
/*
===================
Info_NextPair
Used to itterate through all the key/value pairs in an info string
===================
*/
void Info_NextPair( const char **head, char *key, char *value ) {
char *o;
const char *s;
s = *head;
if ( *s == '\\' ) {
s++;
}
key[0] = 0;
value[0] = 0;
o = key;
while ( *s != '\\' ) {
if ( !*s ) {
*o = 0;
*head = s;
return;
}
*o++ = *s++;
}
*o = 0;
s++;
o = value;
while ( *s != '\\' && *s ) {
*o++ = *s++;
}
*o = 0;
*head = s;
}
/*
===================
Info_RemoveKey
===================
*/
void Info_RemoveKey( char *s, const char *key ) {
char *start;
char pkey[MAX_INFO_KEY];
char value[MAX_INFO_VALUE];
char *o;
if ( strlen( s ) >= MAX_INFO_STRING ) {
Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
}
if (strchr (key, '\\')) {
return;
}
while (1)
{
start = s;
if (*s == '\\')
s++;
o = pkey;
while (*s != '\\')
{
if (!*s)
return;
*o++ = *s++;
}
*o = 0;
s++;
o = value;
while (*s != '\\' && *s)
{
if (!*s)
return;
*o++ = *s++;
}
*o = 0;
if (!strcmp (key, pkey) )
{
memmove(start, s, strlen(s) + 1); // remove this part
return;
}
if (!*s)
return;
}
}
/*
===================
Info_RemoveKey_Big
===================
*/
void Info_RemoveKey_Big( char *s, const char *key ) {
char *start;
char pkey[BIG_INFO_KEY];
char value[BIG_INFO_VALUE];
char *o;
if ( strlen( s ) >= BIG_INFO_STRING ) {
Com_Error( ERR_DROP, "Info_RemoveKey_Big: oversize infostring" );
}
if (strchr (key, '\\')) {
return;
}
while (1)
{
start = s;
if (*s == '\\')
s++;
o = pkey;
while (*s != '\\')
{
if (!*s)
return;
*o++ = *s++;
}
*o = 0;
s++;
o = value;
while (*s != '\\' && *s)
{
if (!*s)
return;
*o++ = *s++;
}
*o = 0;
if (!strcmp (key, pkey) )
{
memmove(start, s, strlen(s) + 1); // remove this part
2011-02-18 14:31:32 +00:00
return;
}
if (!*s)
return;
}
}
/*
==================
Info_Validate
Some characters are illegal in info strings because they
can mess up the server's parsing
==================
*/
qboolean Info_Validate( const char *s ) {
if ( strchr( s, '\"' ) ) {
return qfalse;
}
if ( strchr( s, ';' ) ) {
return qfalse;
}
return qtrue;
}
/*
==================
Info_SetValueForKey
Changes or adds a key/value pair
==================
*/
void Info_SetValueForKey( char *s, const char *key, const char *value ) {
char newi[MAX_INFO_STRING];
const char* blacklist = "\\;\"";
if ( strlen( s ) >= MAX_INFO_STRING ) {
Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
}
for(; *blacklist; ++blacklist)
{
if (strchr (key, *blacklist) || strchr (value, *blacklist))
{
Com_Printf (S_COLOR_YELLOW "Can't use keys or values with a '%c': %s = %s\n", *blacklist, key, value);
return;
}
}
Info_RemoveKey (s, key);
if (!value || !strlen(value))
return;
Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
if (strlen(newi) + strlen(s) >= MAX_INFO_STRING)
{
Com_Printf ("Info string length exceeded\n");
return;
}
strcat (newi, s);
strcpy (s, newi);
}
/*
==================
Info_SetValueForKey_Big
Changes or adds a key/value pair
Includes and retains zero-length values
2011-02-18 14:31:32 +00:00
==================
*/
void Info_SetValueForKey_Big( char *s, const char *key, const char *value ) {
char newi[BIG_INFO_STRING];
const char* blacklist = "\\;\"";
if ( strlen( s ) >= BIG_INFO_STRING ) {
Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
}
for(; *blacklist; ++blacklist)
{
if (strchr (key, *blacklist) || strchr (value, *blacklist))
{
Com_Printf (S_COLOR_YELLOW "Can't use keys or values with a '%c': %s = %s\n", *blacklist, key, value);
return;
}
}
Info_RemoveKey_Big (s, key);
if (!value)
2011-02-18 14:31:32 +00:00
return;
Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
if (strlen(newi) + strlen(s) >= BIG_INFO_STRING)
{
Com_Printf ("BIG Info string length exceeded\n");
return;
}
strcat (s, newi);
}
//====================================================================
/*
==================
Com_CharIsOneOfCharset
==================
*/
static qboolean Com_CharIsOneOfCharset( char c, char *set )
{
int i;
for( i = 0; i < strlen( set ); i++ )
{
if( set[ i ] == c )
return qtrue;
}
return qfalse;
}
/*
==================
Com_SkipCharset
==================
*/
char *Com_SkipCharset( char *s, char *sep )
{
char *p = s;
while( p )
{
if( Com_CharIsOneOfCharset( *p, sep ) )
p++;
else
break;
}
return p;
}
/*
==================
Com_SkipTokens
==================
*/
char *Com_SkipTokens( char *s, int numTokens, char *sep )
{
int sepCount = 0;
char *p = s;
while( sepCount < numTokens )
{
if( Com_CharIsOneOfCharset( *p++, sep ) )
{
sepCount++;
while( Com_CharIsOneOfCharset( *p, sep ) )
p++;
}
else if( *p == '\0' )
break;
}
if( sepCount == numTokens )
return p;
else
return s;
}