//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $Header: $ // $NoKeywords: $ //=============================================================================// #include "quakedef.h" #include #include #include "filesystem.h" #include "filesystem_engine.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" #define MAX_KV_LEN 127 /* =============== Info_ValueForKey Searches the string for the given key and returns the associated value, or an empty string. =============== */ const char *Info_ValueForKey ( const char *s, const char *key ) { char pkey[512]; static char value[4][512]; // use two buffers so compares // work without stomping on each other static int valueindex; char *o; valueindex = (valueindex + 1) % 4; if (*s == '\\') s++; while (1) { o = pkey; while (*s != '\\') { if (!*s) return ""; *o++ = *s++; } *o = 0; s++; o = value[valueindex]; while (*s != '\\' && *s) { if (!*s) return ""; *o++ = *s++; } *o = 0; if (!Q_strcmp (key, pkey) ) return value[valueindex]; if (!*s) return ""; s++; } } void Info_RemoveKey ( char *s, const char *key ) { char *start; char pkey[512]; char value[512]; char *o; if (Q_strstr (key, "\\")) { ConMsg ("Can't use a key with a \\\n"); 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 (!Q_strcmp (key, pkey) ) { // Copies onto self, so okay to not use Q_strncpy??? Q_strcpy (start, s); // remove this part return; } if (!*s) return; } } void Info_RemovePrefixedKeys (char *start, char prefix) { char *s; char pkey[512]; char value[512]; char *o; s = start; while (1) { 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 (pkey[0] == prefix) { Info_RemoveKey (start, pkey); s = start; } if (!*s) return; } } bool Info_IsKeyImportant( const char *key ) { if ( key[0] == '*' ) return true; if ( !Q_strcmp( key, "name" ) ) return true; if ( !Q_strcmp( key, "model" ) ) return true; if ( !Q_strcmp( key, "rate" ) ) return true; if ( !Q_strcmp( key, "cl_updaterate" ) ) return true; if ( !Q_strcmp( key, "cl_lw" ) ) return true; if ( !Q_strcmp( key, "cl_lc" ) ) return true; if ( !Q_strcmp( key, "tracker" ) ) return true; return false; } char *Info_FindLargestKey( char *s, int maxsize ) { char key[256]; char value[256]; char *o; int l; static char largest_key[256]; int largest_size = 0; *largest_key = 0; if (*s == '\\') s++; while (*s) { int size = 0; o = key; while (*s && *s != '\\') *o++ = *s++; l = o - key; *o = 0; size = Q_strlen( key ); if (!*s) { return largest_key; } o = value; s++; while (*s && *s != '\\') *o++ = *s++; *o = 0; if (*s) s++; size += Q_strlen( value ); if ( (size > largest_size) && !Info_IsKeyImportant(key) ) { largest_size = size; Q_strncpy( largest_key, key, sizeof( largest_key ) ); } } return largest_key; } void Info_SetValueForStarKey ( char *s, const char *key, const char *value, int maxsize ) { char newArray[1024], *v; int c; if (Q_strstr (key, "\\") || Q_strstr (value, "\\") ) { ConMsg ("Can't use keys or values with a \\\n"); return; } if (Q_strstr (key, "\"") || Q_strstr (value, "\"") ) { ConMsg ("Can't use keys or values with a \"\n"); return; } if (Q_strlen(key) > MAX_KV_LEN || Q_strlen(value) > MAX_KV_LEN) { ConMsg ("Keys and values must be < %i characters.\n", MAX_KV_LEN + 1 ); return; } Info_RemoveKey (s, key); if (!value || !Q_strlen(value)) return; Q_snprintf (newArray, sizeof( newArray ), "\\%s\\%s", key, value); if ( (int)(Q_strlen(newArray) + Q_strlen(s)) >= maxsize) { // no more room in buffer to add key/value if ( Info_IsKeyImportant( key ) ) { // keep removing the largest key/values until we have room char *largekey; do { largekey = Info_FindLargestKey( s, maxsize ); Info_RemoveKey( s, largekey ); } while ( ((int)(Q_strlen(newArray) + Q_strlen(s)) >= maxsize) && *largekey != 0 ); if ( largekey[0] == 0 ) { // no room to add setting ConMsg ("Info string length exceeded\n"); return; } } else { // no room to add setting ConMsg ("Info string length exceeded\n"); return; } } // only copy ascii values s += Q_strlen(s); v = newArray; while (*v) { c = (unsigned char)*v++; // client only allows highbits on name if (stricmp(key, "name") != 0) { c &= 127; if (c < 32 || c > 127) continue; // auto lowercase team if (stricmp(key, "team") == 0) c = tolower(c); } if (c > 13) *s++ = c; } *s = 0; } void Info_SetValueForKey (char *s, const char *key, const char *value, int maxsize) { if (key[0] == '*') { ConMsg ("Can't set * keys\n"); return; } Info_SetValueForStarKey (s, key, value, maxsize); } void Info_Print ( const char *s ) { char key[512]; char value[512]; char *o; int l; if (*s == '\\') s++; while (*s) { o = key; while (*s && *s != '\\') *o++ = *s++; l = o - key; if (l < 20) { Q_memset (o, ' ', 20-l); key[20] = 0; } else *o = 0; ConMsg ("%s", key); if (!*s) { ConMsg ("MISSING VALUE\n"); return; } o = value; s++; while (*s && *s != '\\') *o++ = *s++; *o = 0; if (*s) s++; ConMsg ("%s\n", value); } } /* ============== Info_WriteVars ============== */ void Info_WriteVars( char *s, FileHandle_t fp ) { const ConVar *pcvar; char pkey[512]; static char value[4][512]; // use two buffers so compares // work without stomping on each other static int valueindex; char *o; valueindex = (valueindex + 1) % 4; if (*s == '\\') s++; while (1) { o = pkey; while (*s != '\\') { if (!*s) return; *o++ = *s++; } *o = 0; s++; o = value[valueindex]; while (*s != '\\' && *s) { if (!*s) return; *o++ = *s++; } *o = 0; pcvar = g_pCVar->FindVar( pkey ); if ( !pcvar && pkey[0] != '*' ) // Don't store out * keys { g_pFileSystem->FPrintf( fp, "setinfo \"%s\" \"%s\"\n", pkey, value[valueindex] ); } if (!*s) return; s++; } }