q_shared.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. // q_shared.c -- stateless support routines that are included in each code dll
  19. #include "q_shared.hpp"
  20. /*
  21. ============================================================================
  22. GROWLISTS
  23. ============================================================================
  24. */
  25. // malloc / free all in one place for debugging
  26. extern "C" void *Com_Allocate( int bytes );
  27. extern "C" void Com_Dealloc( void *ptr );
  28. void Com_InitGrowList( growList_t *list, int maxElements ) {
  29. list->maxElements = maxElements;
  30. list->currentElements = 0;
  31. list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
  32. }
  33. int Com_AddToGrowList( growList_t *list, void *data ) {
  34. void **old;
  35. if ( list->currentElements != list->maxElements ) {
  36. list->elements[list->currentElements] = data;
  37. return list->currentElements++;
  38. }
  39. // grow, reallocate and move
  40. old = list->elements;
  41. if ( list->maxElements < 0 ) {
  42. Com_Error( ERR_FATAL, "Com_AddToGrowList: maxElements = %i", list->maxElements );
  43. }
  44. if ( list->maxElements == 0 ) {
  45. // initialize the list to hold 100 elements
  46. Com_InitGrowList( list, 100 );
  47. return Com_AddToGrowList( list, data );
  48. }
  49. list->maxElements *= 2;
  50. Com_DPrintf( "Resizing growlist to %i maxElements\n", list->maxElements );
  51. list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
  52. if ( !list->elements ) {
  53. Com_Error( ERR_DROP, "Growlist alloc failed" );
  54. }
  55. memcpy( list->elements, old, list->currentElements * sizeof( void * ) );
  56. Com_Dealloc( old );
  57. return Com_AddToGrowList( list, data );
  58. }
  59. void *Com_GrowListElement( const growList_t *list, int index ) {
  60. if ( index < 0 || index >= list->currentElements ) {
  61. Com_Error( ERR_DROP, "Com_GrowListElement: %i out of range of %i",
  62. index, list->currentElements );
  63. }
  64. return list->elements[index];
  65. }
  66. int Com_IndexForGrowListElement( const growList_t *list, const void *element ) {
  67. int i;
  68. for ( i = 0 ; i < list->currentElements ; i++ ) {
  69. if ( list->elements[i] == element ) {
  70. return i;
  71. }
  72. }
  73. return -1;
  74. }
  75. //============================================================================
  76. float Com_Clamp( float min, float max, float value ) {
  77. if ( value < min ) {
  78. return min;
  79. }
  80. if ( value > max ) {
  81. return max;
  82. }
  83. return value;
  84. }
  85. /*
  86. ============
  87. Com_StringContains
  88. ============
  89. */
  90. const char *Com_StringContains( const char *str1, const char *str2, int casesensitive) {
  91. int len, i, j;
  92. len = strlen(str1) - strlen(str2);
  93. for (i = 0; i <= len; i++, str1++) {
  94. for (j = 0; str2[j]; j++) {
  95. if (casesensitive) {
  96. if (str1[j] != str2[j]) {
  97. break;
  98. }
  99. }
  100. else {
  101. if (toupper(str1[j]) != toupper(str2[j])) {
  102. break;
  103. }
  104. }
  105. }
  106. if (!str2[j]) {
  107. return str1;
  108. }
  109. }
  110. return NULL;
  111. }
  112. /*
  113. ============
  114. Com_Filter
  115. ============
  116. */
  117. int Com_Filter( const char *filter, const char *name, int casesensitive)
  118. {
  119. char buf[MAX_TOKEN_CHARS];
  120. const char *ptr;
  121. int i, found;
  122. while(*filter) {
  123. if (*filter == '*') {
  124. filter++;
  125. for (i = 0; *filter; i++) {
  126. if (*filter == '*' || *filter == '?') break;
  127. buf[i] = *filter;
  128. filter++;
  129. }
  130. buf[i] = '\0';
  131. if (strlen(buf)) {
  132. ptr = Com_StringContains(name, buf, casesensitive);
  133. if (!ptr) return qfalse;
  134. name = ptr + strlen(buf);
  135. }
  136. }
  137. else if (*filter == '?') {
  138. filter++;
  139. name++;
  140. }
  141. else if (*filter == '[' && *(filter+1) == '[') {
  142. filter++;
  143. }
  144. else if (*filter == '[') {
  145. filter++;
  146. found = qfalse;
  147. while(*filter && !found) {
  148. if (*filter == ']' && *(filter+1) != ']') break;
  149. if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {
  150. if (casesensitive) {
  151. if (*name >= *filter && *name <= *(filter+2)) found = qtrue;
  152. }
  153. else {
  154. if (toupper(*name) >= toupper(*filter) &&
  155. toupper(*name) <= toupper(*(filter+2))) found = qtrue;
  156. }
  157. filter += 3;
  158. }
  159. else {
  160. if (casesensitive) {
  161. if (*filter == *name) found = qtrue;
  162. }
  163. else {
  164. if (toupper(*filter) == toupper(*name)) found = qtrue;
  165. }
  166. filter++;
  167. }
  168. }
  169. if (!found) return qfalse;
  170. while(*filter) {
  171. if (*filter == ']' && *(filter+1) != ']') break;
  172. filter++;
  173. }
  174. filter++;
  175. name++;
  176. }
  177. else {
  178. if (casesensitive) {
  179. if (*filter != *name) return qfalse;
  180. }
  181. else {
  182. if (toupper(*filter) != toupper(*name)) return qfalse;
  183. }
  184. filter++;
  185. name++;
  186. }
  187. }
  188. return qtrue;
  189. }
  190. /*
  191. ================
  192. Com_HashString
  193. ================
  194. */
  195. int Com_HashString( const char *fname ) {
  196. int i;
  197. long hash;
  198. char letter;
  199. hash = 0;
  200. i = 0;
  201. while (fname[i] != '\0') {
  202. letter = tolower(fname[i]);
  203. if (letter =='.') break; // don't include extension
  204. if (letter =='\\') letter = '/'; // damn path names
  205. hash+=(long)(letter)*(i+119);
  206. i++;
  207. }
  208. hash &= (FILE_HASH_SIZE-1);
  209. return hash;
  210. }
  211. /*
  212. ============
  213. Com_SkipPath
  214. ============
  215. */
  216. char *Com_SkipPath (char *pathname)
  217. {
  218. char *last;
  219. last = pathname;
  220. while (*pathname)
  221. {
  222. if (*pathname=='/')
  223. last = pathname+1;
  224. pathname++;
  225. }
  226. return last;
  227. }
  228. /*
  229. ============
  230. Com_StripExtension
  231. ============
  232. */
  233. void Com_StripExtension( const char *in, char *out ) {
  234. while ( *in && *in != '.' ) {
  235. *out++ = *in++;
  236. }
  237. *out = 0;
  238. }
  239. /*
  240. ==================
  241. Com_DefaultExtension
  242. ==================
  243. */
  244. void Com_DefaultExtension (char *path, int maxSize, const char *extension ) {
  245. char oldPath[MAX_QPATH];
  246. char *src;
  247. //
  248. // if path doesn't have a .EXT, append extension
  249. // (extension should include the .)
  250. //
  251. src = path + strlen(path) - 1;
  252. while (*src != '/' && src != path) {
  253. if ( *src == '.' ) {
  254. return; // it has an extension
  255. }
  256. src--;
  257. }
  258. Q_strncpyz( oldPath, path, sizeof( oldPath ) );
  259. Com_sprintf( path, maxSize, "%s%s", oldPath, extension );
  260. }
  261. /*
  262. ============================================================================
  263. BYTE ORDER FUNCTIONS
  264. ============================================================================
  265. */
  266. // can't just use function pointers, or dll linkage can
  267. // mess up when qcommon is included in multiple places
  268. static short (*_BigShort) (short l);
  269. static short (*_LittleShort) (short l);
  270. static int (*_BigLong) (int l);
  271. static int (*_LittleLong) (int l);
  272. static float (*_BigFloat) (float l);
  273. static float (*_LittleFloat) (float l);
  274. short BigShort(short l){return _BigShort(l);}
  275. short LittleShort(short l) {return _LittleShort(l);}
  276. int BigLong (int l) {return _BigLong(l);}
  277. int LittleLong (int l) {return _LittleLong(l);}
  278. float BigFloat (float l) {return _BigFloat(l);}
  279. float LittleFloat (float l) {return _LittleFloat(l);}
  280. short ShortSwap (short l)
  281. {
  282. byte b1,b2;
  283. b1 = l&255;
  284. b2 = (l>>8)&255;
  285. return (b1<<8) + b2;
  286. }
  287. short ShortNoSwap (short l)
  288. {
  289. return l;
  290. }
  291. int LongSwap (int l)
  292. {
  293. byte b1,b2,b3,b4;
  294. b1 = l&255;
  295. b2 = (l>>8)&255;
  296. b3 = (l>>16)&255;
  297. b4 = (l>>24)&255;
  298. return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
  299. }
  300. int LongNoSwap (int l)
  301. {
  302. return l;
  303. }
  304. float FloatSwap (float f)
  305. {
  306. union
  307. {
  308. float f;
  309. byte b[4];
  310. } dat1, dat2;
  311. dat1.f = f;
  312. dat2.b[0] = dat1.b[3];
  313. dat2.b[1] = dat1.b[2];
  314. dat2.b[2] = dat1.b[1];
  315. dat2.b[3] = dat1.b[0];
  316. return dat2.f;
  317. }
  318. float FloatNoSwap (float f)
  319. {
  320. return f;
  321. }
  322. /*
  323. ================
  324. Swap_Init
  325. ================
  326. */
  327. void Swap_Init (void)
  328. {
  329. byte swaptest[2] = {1,0};
  330. // set the byte swapping variables in a portable manner
  331. if ( *(short *)swaptest == 1)
  332. {
  333. _BigShort = ShortSwap;
  334. _LittleShort = ShortNoSwap;
  335. _BigLong = LongSwap;
  336. _LittleLong = LongNoSwap;
  337. _BigFloat = FloatSwap;
  338. _LittleFloat = FloatNoSwap;
  339. }
  340. else
  341. {
  342. _BigShort = ShortNoSwap;
  343. _LittleShort = ShortSwap;
  344. _BigLong = LongNoSwap;
  345. _LittleLong = LongSwap;
  346. _BigFloat = FloatNoSwap;
  347. _LittleFloat = FloatSwap;
  348. }
  349. }
  350. /*
  351. ===============
  352. Com_ParseInfos
  353. ===============
  354. */
  355. int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ) {
  356. const char *token;
  357. int count;
  358. char key[MAX_TOKEN_CHARS];
  359. count = 0;
  360. while ( 1 ) {
  361. token = Com_Parse( &buf );
  362. if ( !token[0] ) {
  363. break;
  364. }
  365. if ( strcmp( token, "{" ) ) {
  366. Com_Printf( "Missing { in info file\n" );
  367. break;
  368. }
  369. if ( count == max ) {
  370. Com_Printf( "Max infos exceeded\n" );
  371. break;
  372. }
  373. infos[count][0] = 0;
  374. while ( 1 ) {
  375. token = Com_Parse( &buf );
  376. if ( !token[0] ) {
  377. Com_Printf( "Unexpected end of info file\n" );
  378. break;
  379. }
  380. if ( !strcmp( token, "}" ) ) {
  381. break;
  382. }
  383. Q_strncpyz( key, token, sizeof( key ) );
  384. token = Com_ParseOnLine( &buf );
  385. if ( !token[0] ) {
  386. token = "<NULL>";
  387. }
  388. Info_SetValueForKey( infos[count], key, token );
  389. }
  390. count++;
  391. }
  392. return count;
  393. }
  394. /*
  395. ============================================================================
  396. LIBRARY REPLACEMENT FUNCTIONS
  397. ============================================================================
  398. */
  399. int Q_isprint( int c )
  400. {
  401. if ( c >= 0x20 && c <= 0x7E )
  402. return ( 1 );
  403. return ( 0 );
  404. }
  405. int Q_islower( int c )
  406. {
  407. if (c >= 'a' && c <= 'z')
  408. return ( 1 );
  409. return ( 0 );
  410. }
  411. int Q_isupper( int c )
  412. {
  413. if (c >= 'A' && c <= 'Z')
  414. return ( 1 );
  415. return ( 0 );
  416. }
  417. int Q_isalpha( int c )
  418. {
  419. if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
  420. return ( 1 );
  421. return ( 0 );
  422. }
  423. char* Q_strrchr( const char* string, int c )
  424. {
  425. char cc = c;
  426. char *s;
  427. char *sp=(char *)0;
  428. s = (char*)string;
  429. while (*s)
  430. {
  431. if (*s == cc)
  432. sp = s;
  433. s++;
  434. }
  435. if (cc == 0)
  436. sp = s;
  437. return sp;
  438. }
  439. /*
  440. =============
  441. Q_strncpyz
  442. Safe strncpy that ensures a trailing zero
  443. =============
  444. */
  445. void Q_strncpyz( char *dest, const char *src, int destsize ) {
  446. if ( !src ) {
  447. Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
  448. }
  449. if ( destsize < 1 ) {
  450. Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
  451. }
  452. strncpy( dest, src, destsize-1 );
  453. dest[destsize-1] = 0;
  454. }
  455. int Q_stricmpn (const char *s1, const char *s2, int n) {
  456. int c1, c2;
  457. do {
  458. c1 = *s1++;
  459. c2 = *s2++;
  460. if (!n--) {
  461. return 0; // strings are equal until end point
  462. }
  463. if (c1 != c2) {
  464. if (c1 >= 'a' && c1 <= 'z') {
  465. c1 -= ('a' - 'A');
  466. }
  467. if (c2 >= 'a' && c2 <= 'z') {
  468. c2 -= ('a' - 'A');
  469. }
  470. if (c1 != c2) {
  471. return c1 < c2 ? -1 : 1;
  472. }
  473. }
  474. } while (c1);
  475. return 0; // strings are equal
  476. }
  477. int Q_strncmp (const char *s1, const char *s2, int n) {
  478. int c1, c2;
  479. do {
  480. c1 = *s1++;
  481. c2 = *s2++;
  482. if (!n--) {
  483. return 0; // strings are equal until end point
  484. }
  485. if (c1 != c2) {
  486. return c1 < c2 ? -1 : 1;
  487. }
  488. } while (c1);
  489. return 0; // strings are equal
  490. }
  491. int Q_stricmp (const char *s1, const char *s2) {
  492. return Q_stricmpn (s1, s2, 99999);
  493. }
  494. char *Q_strlwr( char *s1 ) {
  495. char *s;
  496. s = s1;
  497. while ( *s ) {
  498. *s = tolower(*s);
  499. s++;
  500. }
  501. return s1;
  502. }
  503. char *Q_strupr( char *s1 ) {
  504. char *s;
  505. s = s1;
  506. while ( *s ) {
  507. *s = toupper(*s);
  508. s++;
  509. }
  510. return s1;
  511. }
  512. // never goes past bounds or leaves without a terminating 0
  513. void Q_strcat( char *dest, int size, const char *src ) {
  514. int l1;
  515. l1 = strlen( dest );
  516. if ( l1 >= size ) {
  517. Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
  518. }
  519. Q_strncpyz( dest + l1, src, size - l1 );
  520. }
  521. int Q_PrintStrlen( const char *string ) {
  522. int len;
  523. const char *p;
  524. if( !string ) {
  525. return 0;
  526. }
  527. len = 0;
  528. p = string;
  529. while( *p ) {
  530. if( Q_IsColorString( p ) ) {
  531. p += 2;
  532. continue;
  533. }
  534. p++;
  535. len++;
  536. }
  537. return len;
  538. }
  539. char *Q_CleanStr( char *string ) {
  540. char* d;
  541. char* s;
  542. int c;
  543. s = string;
  544. d = string;
  545. while ((c = *s) != 0 ) {
  546. if ( Q_IsColorString( s ) ) {
  547. s++;
  548. }
  549. else if ( c >= 0x20 && c <= 0x7E ) {
  550. *d++ = c;
  551. }
  552. s++;
  553. }
  554. *d = '\0';
  555. return string;
  556. }
  557. void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
  558. int len;
  559. va_list argptr;
  560. char bigbuffer[32000]; // big, but small enough to fit in PPC stack
  561. va_start (argptr,fmt);
  562. len = vsprintf (bigbuffer,fmt,argptr);
  563. va_end (argptr);
  564. if ( len >= sizeof( bigbuffer ) ) {
  565. Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
  566. }
  567. if (len >= size) {
  568. Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
  569. }
  570. Q_strncpyz (dest, bigbuffer, size );
  571. }
  572. /*
  573. ============
  574. va
  575. does a varargs printf into a temp buffer, so I don't need to have
  576. varargs versions of all text functions.
  577. FIXME: make this buffer size safe someday
  578. ============
  579. */
  580. char * QDECL va( char *format, ... ) {
  581. va_list argptr;
  582. static char string[2][32000]; // in case va is called by nested functions
  583. static int index = 0;
  584. char *buf;
  585. buf = string[index & 1];
  586. index++;
  587. va_start (argptr, format);
  588. vsprintf (buf, format,argptr);
  589. va_end (argptr);
  590. return buf;
  591. }
  592. /*
  593. =====================================================================
  594. INFO STRINGS
  595. =====================================================================
  596. */
  597. /*
  598. ===============
  599. Info_ValueForKey
  600. Searches the string for the given
  601. key and returns the associated value, or an empty string.
  602. FIXME: overflow check?
  603. ===============
  604. */
  605. char *Info_ValueForKey( const char *s, const char *key ) {
  606. char pkey[MAX_INFO_KEY];
  607. static char value[2][MAX_INFO_VALUE]; // use two buffers so compares
  608. // work without stomping on each other
  609. static int valueindex = 0;
  610. char *o;
  611. if ( !s || !key ) {
  612. return "";
  613. }
  614. if ( strlen( s ) >= MAX_INFO_STRING ) {
  615. Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
  616. }
  617. valueindex ^= 1;
  618. if (*s == '\\')
  619. s++;
  620. while (1)
  621. {
  622. o = pkey;
  623. while (*s != '\\')
  624. {
  625. if (!*s)
  626. return "";
  627. *o++ = *s++;
  628. }
  629. *o = 0;
  630. s++;
  631. o = value[valueindex];
  632. while (*s != '\\' && *s)
  633. {
  634. *o++ = *s++;
  635. }
  636. *o = 0;
  637. if (!Q_stricmp (key, pkey) )
  638. return value[valueindex];
  639. if (!*s)
  640. break;
  641. s++;
  642. }
  643. return "";
  644. }
  645. /*
  646. ===================
  647. Info_NextPair
  648. Used to itterate through all the key/value pairs in an info string
  649. ===================
  650. */
  651. void Info_NextPair( const char *(*head), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ) {
  652. char *o;
  653. const char *s;
  654. s = *head;
  655. if ( *s == '\\' ) {
  656. s++;
  657. }
  658. key[0] = 0;
  659. value[0] = 0;
  660. o = key;
  661. while ( *s != '\\' ) {
  662. if ( !*s ) {
  663. *o = 0;
  664. *head = s;
  665. return;
  666. }
  667. *o++ = *s++;
  668. }
  669. *o = 0;
  670. s++;
  671. o = value;
  672. while ( *s != '\\' && *s ) {
  673. *o++ = *s++;
  674. }
  675. *o = 0;
  676. *head = s;
  677. }
  678. /*
  679. ===================
  680. Info_RemoveKey
  681. ===================
  682. */
  683. void Info_RemoveKey( char *s, const char *key ) {
  684. char *start;
  685. char pkey[MAX_INFO_KEY];
  686. char value[MAX_INFO_VALUE];
  687. char *o;
  688. if ( strlen( s ) >= MAX_INFO_STRING ) {
  689. Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
  690. }
  691. if (strchr (key, '\\')) {
  692. return;
  693. }
  694. while (1)
  695. {
  696. start = s;
  697. if (*s == '\\')
  698. s++;
  699. o = pkey;
  700. while (*s != '\\')
  701. {
  702. if (!*s)
  703. return;
  704. *o++ = *s++;
  705. }
  706. *o = 0;
  707. s++;
  708. o = value;
  709. while (*s != '\\' && *s)
  710. {
  711. if (!*s)
  712. return;
  713. *o++ = *s++;
  714. }
  715. *o = 0;
  716. if (!strcmp (key, pkey) )
  717. {
  718. strcpy (start, s); // remove this part
  719. return;
  720. }
  721. if (!*s)
  722. return;
  723. }
  724. }
  725. /*
  726. ==================
  727. Info_Validate
  728. Some characters are illegal in info strings because they
  729. can mess up the server's parsing
  730. ==================
  731. */
  732. qboolean Info_Validate( const char *s ) {
  733. if ( strchr( s, '\"' ) ) {
  734. return qfalse;
  735. }
  736. if ( strchr( s, ';' ) ) {
  737. return qfalse;
  738. }
  739. return qtrue;
  740. }
  741. /*
  742. ==================
  743. Info_SetValueForKey
  744. Changes or adds a key/value pair
  745. ==================
  746. */
  747. void Info_SetValueForKey( char *s, const char *key, const char *value ) {
  748. char newi[MAX_INFO_STRING];
  749. if ( strlen( s ) >= MAX_INFO_STRING ) {
  750. Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
  751. }
  752. if (strchr (key, '\\') || strchr (value, '\\'))
  753. {
  754. Com_Printf ("Can't use keys or values with a \\\n");
  755. return;
  756. }
  757. if (strchr (key, ';') || strchr (value, ';'))
  758. {
  759. Com_Printf ("Can't use keys or values with a semicolon\n");
  760. return;
  761. }
  762. if (strchr (key, '\"') || strchr (value, '\"'))
  763. {
  764. Com_Printf ("Can't use keys or values with a \"\n");
  765. return;
  766. }
  767. Info_RemoveKey (s, key);
  768. if (!value || !strlen(value))
  769. return;
  770. Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
  771. if (strlen(newi) + strlen(s) > MAX_INFO_STRING)
  772. {
  773. Com_Printf ("Info string length exceeded\n");
  774. return;
  775. }
  776. strcat (s, newi);
  777. }
  778. //====================================================================
  779. /*
  780. ===============
  781. ParseHex
  782. ===============
  783. */
  784. int ParseHex( const char *text ) {
  785. int value;
  786. int c;
  787. value = 0;
  788. while ( ( c = *text++ ) != 0 ) {
  789. if ( c >= '0' && c <= '9' ) {
  790. value = value * 16 + c - '0';
  791. continue;
  792. }
  793. if ( c >= 'a' && c <= 'f' ) {
  794. value = value * 16 + 10 + c - 'a';
  795. continue;
  796. }
  797. if ( c >= 'A' && c <= 'F' ) {
  798. value = value * 16 + 10 + c - 'A';
  799. continue;
  800. }
  801. }
  802. return value;
  803. }