PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/splines/q_shared.cpp

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