Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2632 lines
58 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose: String Tools
  4. //
  5. //===========================================================================//
  6. // These are redefined in the project settings to prevent anyone from using them.
  7. // We in this module are of a higher caste and thus are privileged in their use.
  8. #ifdef strncpy
  9. #undef strncpy
  10. #endif
  11. #ifdef _snprintf
  12. #undef _snprintf
  13. #endif
  14. #if defined( sprintf )
  15. #undef sprintf
  16. #endif
  17. #if defined( vsprintf )
  18. #undef vsprintf
  19. #endif
  20. #ifdef _vsnprintf
  21. #ifdef _WIN32
  22. #undef _vsnprintf
  23. #endif
  24. #endif
  25. #ifdef vsnprintf
  26. #ifndef _WIN32
  27. #undef vsnprintf
  28. #endif
  29. #endif
  30. #if defined( strcat )
  31. #undef strcat
  32. #endif
  33. #ifdef strncat
  34. #undef strncat
  35. #endif
  36. // NOTE: I have to include stdio + stdarg first so vsnprintf gets compiled in
  37. #include <stdio.h>
  38. #include <stdarg.h>
  39. #include "tier0/basetypes.h"
  40. #include "tier0/platform.h"
  41. #ifdef stricmp
  42. #undef stricmp
  43. #endif
  44. #ifdef POSIX
  45. #ifndef _PS3
  46. #include <iconv.h>
  47. #endif // _PS3
  48. #include <ctype.h>
  49. #include <unistd.h>
  50. #include <stdlib.h>
  51. #define stricmp strcasecmp
  52. #elif _WIN32
  53. #include <direct.h>
  54. #if !defined( _X360 )
  55. #define WIN32_LEAN_AND_MEAN
  56. #include <windows.h>
  57. #endif
  58. #endif
  59. #ifdef _WIN32
  60. #ifndef CP_UTF8
  61. #define CP_UTF8 65001
  62. #endif
  63. #endif
  64. #include "tier0/dbg.h"
  65. #include "tier1/strtools.h"
  66. #include <string.h>
  67. #include <stdlib.h>
  68. #include "tier1/utldict.h"
  69. #if defined( _X360 )
  70. #include "xbox/xbox_win32stubs.h"
  71. #elif defined( _PS3 )
  72. #include "ps3_pathinfo.h"
  73. #include <cell/l10n.h> // for UCS-2 to UTF-8 conversion
  74. #endif
  75. #include "tier0/vprof.h"
  76. #include "tier0/memdbgon.h"
  77. #ifndef NDEBUG
  78. static volatile char const *pDebugString;
  79. #define DEBUG_LINK_CHECK pDebugString = "tier1.lib built debug!"
  80. #else
  81. #define DEBUG_LINK_CHECK
  82. #endif
  83. void _V_memset (void *dest, int fill, int count)
  84. {
  85. DEBUG_LINK_CHECK;
  86. Assert( count >= 0 );
  87. AssertValidWritePtr( dest, count );
  88. memset(dest,fill,count);
  89. }
  90. void _V_memcpy (void *dest, const void *src, int count)
  91. {
  92. Assert( count >= 0 );
  93. AssertValidReadPtr( src, count );
  94. AssertValidWritePtr( dest, count );
  95. memcpy( dest, src, count );
  96. }
  97. void _V_memmove(void *dest, const void *src, int count)
  98. {
  99. Assert( count >= 0 );
  100. AssertValidReadPtr( src, count );
  101. AssertValidWritePtr( dest, count );
  102. memmove( dest, src, count );
  103. }
  104. int _V_memcmp (const void *m1, const void *m2, int count)
  105. {
  106. DEBUG_LINK_CHECK;
  107. Assert( count >= 0 );
  108. AssertValidReadPtr( m1, count );
  109. AssertValidReadPtr( m2, count );
  110. return memcmp( m1, m2, count );
  111. }
  112. int _V_strlen(const char *str)
  113. {
  114. AssertValidStringPtr(str);
  115. #ifdef POSIX
  116. if ( !str )
  117. return 0;
  118. #endif
  119. return strlen( str );
  120. }
  121. void _V_strcpy (char *dest, const char *src)
  122. {
  123. DEBUG_LINK_CHECK;
  124. AssertValidWritePtr(dest);
  125. AssertValidStringPtr(src);
  126. strcpy( dest, src );
  127. }
  128. int _V_wcslen(const wchar_t *pwch)
  129. {
  130. return wcslen( pwch );
  131. }
  132. char *_V_strrchr(const char *s, char c)
  133. {
  134. AssertValidStringPtr( s );
  135. int len = V_strlen(s);
  136. s += len;
  137. while (len--)
  138. if (*--s == c) return (char *)s;
  139. return 0;
  140. }
  141. int _V_strcmp (const char *s1, const char *s2)
  142. {
  143. AssertValidStringPtr( s1 );
  144. AssertValidStringPtr( s2 );
  145. VPROF_2( "V_strcmp", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, BUDGETFLAG_ALL );
  146. return strcmp( s1, s2 );
  147. }
  148. int _V_wcscmp (const wchar_t *s1, const wchar_t *s2)
  149. {
  150. while (1)
  151. {
  152. if (*s1 != *s2)
  153. return -1; // strings not equal
  154. if (!*s1)
  155. return 0; // strings are equal
  156. s1++;
  157. s2++;
  158. }
  159. return -1;
  160. }
  161. #define TOLOWERC( x ) (( ( x >= 'A' ) && ( x <= 'Z' ) )?( x + 32 ) : x )
  162. int _V_stricmp( const char *s1, const char *s2 )
  163. {
  164. VPROF_2( "V_stricmp", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, BUDGETFLAG_ALL );
  165. #ifdef POSIX
  166. if ( s1 == NULL && s2 == NULL )
  167. return 0;
  168. if ( s1 == NULL )
  169. return -1;
  170. if ( s2 == NULL )
  171. return 1;
  172. return stricmp( s1, s2 );
  173. #else
  174. uint8 const *pS1 = ( uint8 const * ) s1;
  175. uint8 const *pS2 = ( uint8 const * ) s2;
  176. for(;;)
  177. {
  178. int c1 = *( pS1++ );
  179. int c2 = *( pS2++ );
  180. if ( c1 == c2 )
  181. {
  182. if ( !c1 ) return 0;
  183. }
  184. else
  185. {
  186. if ( ! c2 )
  187. {
  188. return c1 - c2;
  189. }
  190. c1 = TOLOWERC( c1 );
  191. c2 = TOLOWERC( c2 );
  192. if ( c1 != c2 )
  193. {
  194. return c1 - c2;
  195. }
  196. }
  197. c1 = *( pS1++ );
  198. c2 = *( pS2++ );
  199. if ( c1 == c2 )
  200. {
  201. if ( !c1 ) return 0;
  202. }
  203. else
  204. {
  205. if ( ! c2 )
  206. {
  207. return c1 - c2;
  208. }
  209. c1 = TOLOWERC( c1 );
  210. c2 = TOLOWERC( c2 );
  211. if ( c1 != c2 )
  212. {
  213. return c1 - c2;
  214. }
  215. }
  216. }
  217. #endif
  218. }
  219. // A special high-performance case-insensitive compare function
  220. // returns 0 if strings match exactly
  221. // returns >0 if strings match in a case-insensitive way, but do not match exactly
  222. // returns <0 if strings do not match even in a case-insensitive way
  223. int _V_stricmp_NegativeForUnequal( const char *s1, const char *s2 )
  224. {
  225. VPROF_2( "V_stricmp", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, BUDGETFLAG_ALL );
  226. uint8 const *pS1 = ( uint8 const * ) s1;
  227. uint8 const *pS2 = ( uint8 const * ) s2;
  228. int iExactMatchResult = 1;
  229. for(;;)
  230. {
  231. int c1 = *( pS1++ );
  232. int c2 = *( pS2++ );
  233. if ( c1 == c2 )
  234. {
  235. // strings are case-insensitive equal, coerce accumulated
  236. // case-difference to 0/1 and return it
  237. if ( !c1 ) return !iExactMatchResult;
  238. }
  239. else
  240. {
  241. if ( ! c2 )
  242. {
  243. // c2=0 and != c1 => not equal
  244. return -1;
  245. }
  246. iExactMatchResult = 0;
  247. c1 = TOLOWERC( c1 );
  248. c2 = TOLOWERC( c2 );
  249. if ( c1 != c2 )
  250. {
  251. // strings are not equal
  252. return -1;
  253. }
  254. }
  255. c1 = *( pS1++ );
  256. c2 = *( pS2++ );
  257. if ( c1 == c2 )
  258. {
  259. // strings are case-insensitive equal, coerce accumulated
  260. // case-difference to 0/1 and return it
  261. if ( !c1 ) return !iExactMatchResult;
  262. }
  263. else
  264. {
  265. if ( ! c2 )
  266. {
  267. // c2=0 and != c1 => not equal
  268. return -1;
  269. }
  270. iExactMatchResult = 0;
  271. c1 = TOLOWERC( c1 );
  272. c2 = TOLOWERC( c2 );
  273. if ( c1 != c2 )
  274. {
  275. // strings are not equal
  276. return -1;
  277. }
  278. }
  279. }
  280. }
  281. char *_V_strstr( const char *s1, const char *search )
  282. {
  283. AssertValidStringPtr( s1 );
  284. AssertValidStringPtr( search );
  285. #if defined( _X360 )
  286. return (char *)strstr( (char *)s1, search );
  287. #else
  288. return (char *)strstr( s1, search );
  289. #endif
  290. }
  291. char *_V_strupr (char *start)
  292. {
  293. AssertValidStringPtr( start );
  294. return strupr( start );
  295. }
  296. char *_V_strlower (char *start)
  297. {
  298. AssertValidStringPtr( start );
  299. return strlwr(start);
  300. }
  301. wchar_t *_V_wcsupr (const char* file, int line, wchar_t *start)
  302. {
  303. return _wcsupr( start );
  304. }
  305. wchar_t *_V_wcslower (const char* file, int line, wchar_t *start)
  306. {
  307. return _wcslwr(start);
  308. }
  309. int V_strncmp (const char *s1, const char *s2, int count)
  310. {
  311. Assert( count >= 0 );
  312. AssertValidStringPtr( s1, count );
  313. AssertValidStringPtr( s2, count );
  314. VPROF_2( "V_strcmp", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, BUDGETFLAG_ALL );
  315. while ( count-- > 0 )
  316. {
  317. if ( *s1 != *s2 )
  318. return *s1 < *s2 ? -1 : 1; // string different
  319. if ( *s1 == '\0' )
  320. return 0; // null terminator hit - strings the same
  321. s1++;
  322. s2++;
  323. }
  324. return 0; // count characters compared the same
  325. }
  326. char *V_strnlwr(char *s, size_t count)
  327. {
  328. Assert( count >= 0 );
  329. AssertValidStringPtr( s, count );
  330. char* pRet = s;
  331. if ( !s || !count )
  332. return s;
  333. while ( -- count > 0 )
  334. {
  335. if ( !*s )
  336. return pRet; // reached end of string
  337. *s = tolower( *s );
  338. ++s;
  339. }
  340. *s = 0; // null-terminate original string at "count-1"
  341. return pRet;
  342. }
  343. int V_strncasecmp (const char *s1, const char *s2, int n)
  344. {
  345. Assert( n >= 0 );
  346. AssertValidStringPtr( s1 );
  347. AssertValidStringPtr( s2 );
  348. VPROF_2( "V_strcmp", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, BUDGETFLAG_ALL );
  349. while ( n-- > 0 )
  350. {
  351. int c1 = *s1++;
  352. int c2 = *s2++;
  353. if (c1 != c2)
  354. {
  355. if (c1 >= 'a' && c1 <= 'z')
  356. c1 -= ('a' - 'A');
  357. if (c2 >= 'a' && c2 <= 'z')
  358. c2 -= ('a' - 'A');
  359. if (c1 != c2)
  360. return c1 < c2 ? -1 : 1;
  361. }
  362. if ( c1 == '\0' )
  363. return 0; // null terminator hit - strings the same
  364. }
  365. return 0; // n characters compared the same
  366. }
  367. int V_strcasecmp( const char *s1, const char *s2 )
  368. {
  369. AssertValidStringPtr( s1 );
  370. AssertValidStringPtr( s2 );
  371. VPROF_2( "V_strcmp", VPROF_BUDGETGROUP_OTHER_UNACCOUNTED, false, BUDGETFLAG_ALL );
  372. return V_stricmp( s1, s2 );
  373. }
  374. int V_strnicmp (const char *s1, const char *s2, int n)
  375. {
  376. DEBUG_LINK_CHECK;
  377. Assert( n >= 0 );
  378. AssertValidStringPtr(s1);
  379. AssertValidStringPtr(s2);
  380. return V_strncasecmp( s1, s2, n );
  381. }
  382. const char *StringAfterPrefix( const char *str, const char *prefix )
  383. {
  384. AssertValidStringPtr( str );
  385. AssertValidStringPtr( prefix );
  386. do
  387. {
  388. if ( !*prefix )
  389. return str;
  390. }
  391. while ( tolower( *str++ ) == tolower( *prefix++ ) );
  392. return NULL;
  393. }
  394. const char *StringAfterPrefixCaseSensitive( const char *str, const char *prefix )
  395. {
  396. AssertValidStringPtr( str );
  397. AssertValidStringPtr( prefix );
  398. do
  399. {
  400. if ( !*prefix )
  401. return str;
  402. }
  403. while ( *str++ == *prefix++ );
  404. return NULL;
  405. }
  406. uint64 V_atoui64( const char *str )
  407. {
  408. AssertValidStringPtr( str );
  409. uint64 val;
  410. uint64 c;
  411. Assert( str );
  412. val = 0;
  413. //
  414. // check for hex
  415. //
  416. if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
  417. {
  418. str += 2;
  419. while (1)
  420. {
  421. c = *str++;
  422. if (c >= '0' && c <= '9')
  423. val = (val<<4) + c - '0';
  424. else if (c >= 'a' && c <= 'f')
  425. val = (val<<4) + c - 'a' + 10;
  426. else if (c >= 'A' && c <= 'F')
  427. val = (val<<4) + c - 'A' + 10;
  428. else
  429. return val;
  430. }
  431. }
  432. //
  433. // check for character
  434. //
  435. if (str[0] == '\'')
  436. {
  437. return str[1];
  438. }
  439. //
  440. // assume decimal
  441. //
  442. while (1)
  443. {
  444. c = *str++;
  445. if (c <'0' || c > '9')
  446. return val;
  447. val = val*10 + c - '0';
  448. }
  449. return 0;
  450. }
  451. int64 V_atoi64( const char *str )
  452. {
  453. AssertValidStringPtr( str );
  454. int64 val;
  455. int64 sign;
  456. int64 c;
  457. Assert( str );
  458. if (*str == '-')
  459. {
  460. sign = -1;
  461. str++;
  462. }
  463. else
  464. sign = 1;
  465. val = 0;
  466. //
  467. // check for hex
  468. //
  469. if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
  470. {
  471. str += 2;
  472. while (1)
  473. {
  474. c = *str++;
  475. if (c >= '0' && c <= '9')
  476. val = (val<<4) + c - '0';
  477. else if (c >= 'a' && c <= 'f')
  478. val = (val<<4) + c - 'a' + 10;
  479. else if (c >= 'A' && c <= 'F')
  480. val = (val<<4) + c - 'A' + 10;
  481. else
  482. return val*sign;
  483. }
  484. }
  485. //
  486. // check for character
  487. //
  488. if (str[0] == '\'')
  489. {
  490. return sign * str[1];
  491. }
  492. //
  493. // assume decimal
  494. //
  495. while (1)
  496. {
  497. c = *str++;
  498. if (c <'0' || c > '9')
  499. return val*sign;
  500. val = val*10 + c - '0';
  501. }
  502. return 0;
  503. }
  504. int V_atoi( const char *str )
  505. {
  506. return (int)V_atoi64( str );
  507. }
  508. float V_atof (const char *str)
  509. {
  510. DEBUG_LINK_CHECK;
  511. AssertValidStringPtr( str );
  512. double val;
  513. int sign;
  514. int c;
  515. int decimal, total;
  516. if (*str == '-')
  517. {
  518. sign = -1;
  519. str++;
  520. }
  521. else
  522. sign = 1;
  523. val = 0;
  524. //
  525. // check for hex
  526. //
  527. if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
  528. {
  529. str += 2;
  530. while (1)
  531. {
  532. c = *str++;
  533. if (c >= '0' && c <= '9')
  534. val = (val*16) + c - '0';
  535. else if (c >= 'a' && c <= 'f')
  536. val = (val*16) + c - 'a' + 10;
  537. else if (c >= 'A' && c <= 'F')
  538. val = (val*16) + c - 'A' + 10;
  539. else
  540. return val*sign;
  541. }
  542. }
  543. //
  544. // check for character
  545. //
  546. if (str[0] == '\'')
  547. {
  548. return sign * str[1];
  549. }
  550. //
  551. // assume decimal
  552. //
  553. decimal = -1;
  554. total = 0;
  555. int exponent = 0;
  556. while (1)
  557. {
  558. c = *str++;
  559. if (c == '.')
  560. {
  561. decimal = total;
  562. continue;
  563. }
  564. if (c <'0' || c > '9')
  565. {
  566. if ( c == 'e' )
  567. {
  568. exponent = V_atoi(str);
  569. }
  570. break;
  571. }
  572. val = val*10 + c - '0';
  573. total++;
  574. }
  575. if ( exponent != 0 )
  576. {
  577. val *= pow( 10.0, exponent );
  578. }
  579. if (decimal == -1)
  580. return val*sign;
  581. while (total > decimal)
  582. {
  583. val /= 10;
  584. total--;
  585. }
  586. return val*sign;
  587. }
  588. //-----------------------------------------------------------------------------
  589. // Normalizes a float string in place.
  590. //
  591. // (removes leading zeros, trailing zeros after the decimal point, and the decimal point itself where possible)
  592. //-----------------------------------------------------------------------------
  593. void V_normalizeFloatString( char* pFloat )
  594. {
  595. // If we have a decimal point, remove trailing zeroes:
  596. if( strchr( pFloat,'.' ) )
  597. {
  598. int len = V_strlen(pFloat);
  599. while( len > 1 && pFloat[len - 1] == '0' )
  600. {
  601. pFloat[len - 1] = '\0';
  602. len--;
  603. }
  604. if( len > 1 && pFloat[ len - 1 ] == '.' )
  605. {
  606. pFloat[len - 1] = '\0';
  607. len--;
  608. }
  609. }
  610. // TODO: Strip leading zeros
  611. }
  612. FORCEINLINE unsigned char tolower_fast(unsigned char c)
  613. {
  614. if ( (c >= 'A') && (c <= 'Z') )
  615. return c + ('a' - 'A');
  616. return c;
  617. }
  618. //-----------------------------------------------------------------------------
  619. // Finds a string in another string with a case insensitive test
  620. //-----------------------------------------------------------------------------
  621. char const* V_stristr( char const* pStr, char const* pSearch )
  622. {
  623. AssertValidStringPtr(pStr);
  624. AssertValidStringPtr(pSearch);
  625. if (!pStr || !pSearch)
  626. return 0;
  627. char const* pLetter = pStr;
  628. // Check the entire string
  629. while (*pLetter != 0)
  630. {
  631. // Skip over non-matches
  632. if (tolower_fast((unsigned char)*pLetter) == tolower_fast((unsigned char)*pSearch))
  633. {
  634. // Check for match
  635. char const* pMatch = pLetter + 1;
  636. char const* pTest = pSearch + 1;
  637. while (*pTest != 0)
  638. {
  639. // We've run off the end; don't bother.
  640. if (*pMatch == 0)
  641. return 0;
  642. if (tolower_fast((unsigned char)*pMatch) != tolower_fast((unsigned char)*pTest))
  643. break;
  644. ++pMatch;
  645. ++pTest;
  646. }
  647. // Found a match!
  648. if (*pTest == 0)
  649. return pLetter;
  650. }
  651. ++pLetter;
  652. }
  653. return 0;
  654. }
  655. char* V_stristr( char* pStr, char const* pSearch )
  656. {
  657. AssertValidStringPtr( pStr );
  658. AssertValidStringPtr( pSearch );
  659. return (char*)V_stristr( (char const*)pStr, pSearch );
  660. }
  661. //-----------------------------------------------------------------------------
  662. // Finds a string in another string with a case insensitive test w/ length validation
  663. //-----------------------------------------------------------------------------
  664. char const* V_strnistr( char const* pStr, char const* pSearch, int n )
  665. {
  666. AssertValidStringPtr(pStr);
  667. AssertValidStringPtr(pSearch);
  668. if (!pStr || !pSearch)
  669. return 0;
  670. char const* pLetter = pStr;
  671. // Check the entire string
  672. while (*pLetter != 0)
  673. {
  674. if ( n <= 0 )
  675. return 0;
  676. // Skip over non-matches
  677. if (tolower_fast(*pLetter) == tolower_fast(*pSearch))
  678. {
  679. int n1 = n - 1;
  680. // Check for match
  681. char const* pMatch = pLetter + 1;
  682. char const* pTest = pSearch + 1;
  683. while (*pTest != 0)
  684. {
  685. if ( n1 <= 0 )
  686. return 0;
  687. // We've run off the end; don't bother.
  688. if (*pMatch == 0)
  689. return 0;
  690. if (tolower_fast(*pMatch) != tolower_fast(*pTest))
  691. break;
  692. ++pMatch;
  693. ++pTest;
  694. --n1;
  695. }
  696. // Found a match!
  697. if (*pTest == 0)
  698. return pLetter;
  699. }
  700. ++pLetter;
  701. --n;
  702. }
  703. return 0;
  704. }
  705. const char* V_strnchr( const char* pStr, char c, int n )
  706. {
  707. char const* pLetter = pStr;
  708. char const* pLast = pStr + n;
  709. // Check the entire string
  710. while ( (pLetter < pLast) && (*pLetter != 0) )
  711. {
  712. if (*pLetter == c)
  713. return pLetter;
  714. ++pLetter;
  715. }
  716. return NULL;
  717. }
  718. void V_strncpy( char *pDest, char const *pSrc, int maxLen )
  719. {
  720. Assert( maxLen >= 0 );
  721. AssertValidWritePtr( pDest, maxLen );
  722. AssertValidStringPtr( pSrc );
  723. DEBUG_LINK_CHECK;
  724. strncpy( pDest, pSrc, maxLen );
  725. if ( maxLen > 0 )
  726. {
  727. pDest[maxLen-1] = 0;
  728. }
  729. }
  730. void V_wcsncpy( wchar_t *pDest, wchar_t const *pSrc, int maxLenInBytes )
  731. {
  732. Assert( maxLenInBytes >= 0 );
  733. AssertValidWritePtr( pDest, maxLenInBytes );
  734. AssertValidReadPtr( pSrc );
  735. int maxLen = maxLenInBytes / sizeof(wchar_t);
  736. wcsncpy( pDest, pSrc, maxLen );
  737. if( maxLen )
  738. {
  739. pDest[maxLen-1] = 0;
  740. }
  741. }
  742. int V_snwprintf( wchar_t *pDest, int maxLenInNumWideCharacters, const wchar_t *pFormat, ... )
  743. {
  744. Assert( maxLenInNumWideCharacters >= 0 );
  745. AssertValidWritePtr( pDest, maxLenInNumWideCharacters );
  746. AssertValidReadPtr( pFormat );
  747. va_list marker;
  748. va_start( marker, pFormat );
  749. #ifdef _WIN32
  750. int len = _vsnwprintf( pDest, maxLenInNumWideCharacters, pFormat, marker );
  751. #elif POSIX
  752. int len = vswprintf( pDest, maxLenInNumWideCharacters, pFormat, marker );
  753. #else
  754. #error "define vsnwprintf type."
  755. #endif
  756. va_end( marker );
  757. // Len < 0 represents an overflow
  758. if ( ( len < 0 ) ||
  759. ( maxLenInNumWideCharacters > 0 && len >= maxLenInNumWideCharacters ) )
  760. {
  761. len = maxLenInNumWideCharacters;
  762. pDest[maxLenInNumWideCharacters-1] = 0;
  763. }
  764. return len;
  765. }
  766. int V_snprintf( char *pDest, int maxLen, char const *pFormat, ... )
  767. {
  768. Assert( maxLen >= 0 );
  769. AssertValidWritePtr( pDest, maxLen );
  770. AssertValidStringPtr( pFormat );
  771. va_list marker;
  772. va_start( marker, pFormat );
  773. #ifdef _WIN32
  774. int len = _vsnprintf( pDest, maxLen, pFormat, marker );
  775. #elif POSIX
  776. int len = vsnprintf( pDest, maxLen, pFormat, marker );
  777. #else
  778. #error "define vsnprintf type."
  779. #endif
  780. va_end( marker );
  781. // Len < 0 represents an overflow
  782. if( len < 0 )
  783. {
  784. len = maxLen;
  785. pDest[maxLen-1] = 0;
  786. }
  787. return len;
  788. }
  789. int V_vsnprintf( char *pDest, int maxLen, char const *pFormat, va_list params )
  790. {
  791. Assert( maxLen > 0 );
  792. AssertValidWritePtr( pDest, maxLen );
  793. AssertValidStringPtr( pFormat );
  794. int len = _vsnprintf( pDest, maxLen, pFormat, params );
  795. if( len < 0 )
  796. {
  797. len = maxLen;
  798. pDest[maxLen-1] = 0;
  799. }
  800. return len;
  801. }
  802. int V_vsnprintfRet( char *pDest, int maxLen, const char *pFormat, va_list params, bool *pbTruncated )
  803. {
  804. Assert( maxLen > 0 );
  805. AssertValidWritePtr( pDest, maxLen );
  806. AssertValidStringPtr( pFormat );
  807. int len = _vsnprintf( pDest, maxLen, pFormat, params );
  808. if ( pbTruncated )
  809. {
  810. *pbTruncated = len < 0;
  811. }
  812. if( len < 0 )
  813. {
  814. len = maxLen;
  815. pDest[maxLen-1] = 0;
  816. }
  817. return len;
  818. }
  819. //-----------------------------------------------------------------------------
  820. // Purpose: If COPY_ALL_CHARACTERS == max_chars_to_copy then we try to add the whole pSrc to the end of pDest, otherwise
  821. // we copy only as many characters as are specified in max_chars_to_copy (or the # of characters in pSrc if thats's less).
  822. // Input : *pDest - destination buffer
  823. // *pSrc - string to append
  824. // destBufferSize - sizeof the buffer pointed to by pDest
  825. // max_chars_to_copy - COPY_ALL_CHARACTERS in pSrc or max # to copy
  826. // Output : char * the copied buffer
  827. //-----------------------------------------------------------------------------
  828. char *V_strncat(char *pDest, const char *pSrc, size_t maxLenInBytes, int max_chars_to_copy )
  829. {
  830. DEBUG_LINK_CHECK;
  831. size_t charstocopy = (size_t)0;
  832. Assert( maxLenInBytes >= 0 );
  833. AssertValidStringPtr( pDest);
  834. AssertValidStringPtr( pSrc );
  835. size_t len = strlen(pDest);
  836. size_t srclen = strlen( pSrc );
  837. if ( max_chars_to_copy <= COPY_ALL_CHARACTERS )
  838. {
  839. charstocopy = srclen;
  840. }
  841. else
  842. {
  843. charstocopy = (size_t)MIN( max_chars_to_copy, (int)srclen );
  844. }
  845. if ( len + charstocopy >= maxLenInBytes )
  846. {
  847. charstocopy = maxLenInBytes - len - 1;
  848. }
  849. if ( !charstocopy )
  850. {
  851. return pDest;
  852. }
  853. char *pOut = strncat( pDest, pSrc, charstocopy );
  854. pOut[maxLenInBytes-1] = 0;
  855. return pOut;
  856. }
  857. //-----------------------------------------------------------------------------
  858. // Purpose: If COPY_ALL_CHARACTERS == max_chars_to_copy then we try to add the whole pSrc to the end of pDest, otherwise
  859. // we copy only as many characters as are specified in max_chars_to_copy (or the # of characters in pSrc if thats's less).
  860. // Input : *pDest - destination buffer
  861. // *pSrc - string to append
  862. // maxLenInCharacters - sizeof the buffer in characters pointed to by pDest
  863. // max_chars_to_copy - COPY_ALL_CHARACTERS in pSrc or max # to copy
  864. // Output : char * the copied buffer
  865. //-----------------------------------------------------------------------------
  866. wchar_t *V_wcsncat( wchar_t *pDest, const wchar_t *pSrc, int maxLenInBytes, int max_chars_to_copy )
  867. {
  868. DEBUG_LINK_CHECK;
  869. size_t charstocopy = (size_t)0;
  870. Assert( maxLenInBytes >= 0 );
  871. int maxLenInCharacters = maxLenInBytes / sizeof( wchar_t );
  872. size_t len = wcslen(pDest);
  873. size_t srclen = wcslen( pSrc );
  874. if ( max_chars_to_copy <= COPY_ALL_CHARACTERS )
  875. {
  876. charstocopy = srclen;
  877. }
  878. else
  879. {
  880. charstocopy = (size_t)MIN( max_chars_to_copy, (int)srclen );
  881. }
  882. if ( len + charstocopy >= (size_t)maxLenInCharacters )
  883. {
  884. charstocopy = maxLenInCharacters - len - 1;
  885. }
  886. if ( !charstocopy )
  887. {
  888. return pDest;
  889. }
  890. wchar_t *pOut = wcsncat( pDest, pSrc, charstocopy );
  891. pOut[maxLenInCharacters-1] = 0;
  892. return pOut;
  893. }
  894. //-----------------------------------------------------------------------------
  895. // Purpose: Converts value into x.xx MB/ x.xx KB, x.xx bytes format, including commas
  896. // Input : value -
  897. // 2 -
  898. // false -
  899. // Output : char
  900. //-----------------------------------------------------------------------------
  901. #define NUM_PRETIFYMEM_BUFFERS 8
  902. char *V_pretifymem( float value, int digitsafterdecimal /*= 2*/, bool usebinaryonek /*= false*/ )
  903. {
  904. static char output[ NUM_PRETIFYMEM_BUFFERS ][ 32 ];
  905. static int current;
  906. float onekb = usebinaryonek ? 1024.0f : 1000.0f;
  907. float onemb = onekb * onekb;
  908. char *out = output[ current ];
  909. current = ( current + 1 ) & ( NUM_PRETIFYMEM_BUFFERS -1 );
  910. char suffix[ 8 ];
  911. // First figure out which bin to use
  912. if ( value > onemb )
  913. {
  914. value /= onemb;
  915. V_snprintf( suffix, sizeof( suffix ), " MB" );
  916. }
  917. else if ( value > onekb )
  918. {
  919. value /= onekb;
  920. V_snprintf( suffix, sizeof( suffix ), " KB" );
  921. }
  922. else
  923. {
  924. V_snprintf( suffix, sizeof( suffix ), " bytes" );
  925. }
  926. char val[ 32 ];
  927. // Clamp to >= 0
  928. digitsafterdecimal = MAX( digitsafterdecimal, 0 );
  929. // If it's basically integral, don't do any decimals
  930. if ( FloatMakePositive( value - (int)value ) < 0.00001 )
  931. {
  932. V_snprintf( val, sizeof( val ), "%i%s", (int)value, suffix );
  933. }
  934. else
  935. {
  936. char fmt[ 32 ];
  937. // Otherwise, create a format string for the decimals
  938. V_snprintf( fmt, sizeof( fmt ), "%%.%if%s", digitsafterdecimal, suffix );
  939. V_snprintf( val, sizeof( val ), fmt, value );
  940. }
  941. // Copy from in to out
  942. char *i = val;
  943. char *o = out;
  944. // Search for decimal or if it was integral, find the space after the raw number
  945. char *dot = strstr( i, "." );
  946. if ( !dot )
  947. {
  948. dot = strstr( i, " " );
  949. }
  950. // Compute position of dot
  951. int pos = dot - i;
  952. // Don't put a comma if it's <= 3 long
  953. pos -= 3;
  954. while ( *i )
  955. {
  956. // If pos is still valid then insert a comma every third digit, except if we would be
  957. // putting one in the first spot
  958. if ( pos >= 0 && !( pos % 3 ) )
  959. {
  960. // Never in first spot
  961. if ( o != out )
  962. {
  963. *o++ = ',';
  964. }
  965. }
  966. // Count down comma position
  967. pos--;
  968. // Copy rest of data as normal
  969. *o++ = *i++;
  970. }
  971. // Terminate
  972. *o = 0;
  973. return out;
  974. }
  975. //-----------------------------------------------------------------------------
  976. // Purpose: Returns a string representation of an integer with commas
  977. // separating the 1000s (ie, 37,426,421)
  978. // Input : value - Value to convert
  979. // Output : Pointer to a static buffer containing the output
  980. //-----------------------------------------------------------------------------
  981. #define NUM_PRETIFYNUM_BUFFERS 8
  982. char *V_pretifynum( int64 value )
  983. {
  984. static char output[ NUM_PRETIFYMEM_BUFFERS ][ 32 ];
  985. static int current;
  986. char *out = output[ current ];
  987. current = ( current + 1 ) & ( NUM_PRETIFYMEM_BUFFERS -1 );
  988. *out = 0;
  989. // Render the leading -, if necessary
  990. if ( value < 0 )
  991. {
  992. char *pchRender = out + V_strlen( out );
  993. V_snprintf( pchRender, 32, "-" );
  994. value = -value;
  995. }
  996. // Render quadrillions
  997. if ( value >= 1000000000000ll )
  998. {
  999. char *pchRender = out + V_strlen( out );
  1000. V_snprintf( pchRender, 32, "%d,", ( int ) ( value / 1000000000000ll ) );
  1001. }
  1002. // Render trillions
  1003. if ( value >= 1000000000000ll )
  1004. {
  1005. char *pchRender = out + V_strlen( out );
  1006. V_snprintf( pchRender, 32, "%d,", ( int ) ( value / 1000000000000ll ) );
  1007. }
  1008. // Render billions
  1009. if ( value >= 1000000000 )
  1010. {
  1011. char *pchRender = out + V_strlen( out );
  1012. V_snprintf( pchRender, 32, "%d,", ( int ) ( value / 1000000000 ) );
  1013. }
  1014. // Render millions
  1015. if ( value >= 1000000 )
  1016. {
  1017. char *pchRender = out + V_strlen( out );
  1018. if ( value >= 1000000000 )
  1019. V_snprintf( pchRender, 32, "%03d,", ( int ) ( value / 1000000 ) % 1000 );
  1020. else
  1021. V_snprintf( pchRender, 32, "%d,", ( int ) ( value / 1000000 ) % 1000 );
  1022. }
  1023. // Render thousands
  1024. if ( value >= 1000 )
  1025. {
  1026. char *pchRender = out + V_strlen( out );
  1027. if ( value >= 1000000 )
  1028. V_snprintf( pchRender, 32, "%03d,", ( int ) ( value / 1000 ) % 1000 );
  1029. else
  1030. V_snprintf( pchRender, 32, "%d,", ( int ) ( value / 1000 ) % 1000 );
  1031. }
  1032. // Render units
  1033. char *pchRender = out + V_strlen( out );
  1034. if ( value > 1000 )
  1035. V_snprintf( pchRender, 32, "%03d", ( int ) ( value % 1000 ) );
  1036. else
  1037. V_snprintf( pchRender, 32, "%d", ( int ) ( value % 1000 ) );
  1038. return out;
  1039. }
  1040. //-----------------------------------------------------------------------------
  1041. // Purpose: Returns the 4 bit nibble for a hex character
  1042. // Input : c -
  1043. // Output : unsigned char
  1044. //-----------------------------------------------------------------------------
  1045. static unsigned char V_nibble( char c )
  1046. {
  1047. if ( ( c >= '0' ) &&
  1048. ( c <= '9' ) )
  1049. {
  1050. return (unsigned char)(c - '0');
  1051. }
  1052. if ( ( c >= 'A' ) &&
  1053. ( c <= 'F' ) )
  1054. {
  1055. return (unsigned char)(c - 'A' + 0x0a);
  1056. }
  1057. if ( ( c >= 'a' ) &&
  1058. ( c <= 'f' ) )
  1059. {
  1060. return (unsigned char)(c - 'a' + 0x0a);
  1061. }
  1062. return '0';
  1063. }
  1064. //-----------------------------------------------------------------------------
  1065. // Purpose:
  1066. // Input : *in -
  1067. // numchars -
  1068. // *out -
  1069. // maxoutputbytes -
  1070. //-----------------------------------------------------------------------------
  1071. void V_hextobinary( char const *in, int numchars, byte *out, int maxoutputbytes )
  1072. {
  1073. int len = V_strlen( in );
  1074. numchars = MIN( len, numchars );
  1075. // Make sure it's even
  1076. numchars = ( numchars ) & ~0x1;
  1077. // Must be an even # of input characters (two chars per output byte)
  1078. Assert( numchars >= 2 );
  1079. memset( out, 0x00, maxoutputbytes );
  1080. byte *p;
  1081. int i;
  1082. p = out;
  1083. for ( i = 0;
  1084. ( i < numchars ) && ( ( p - out ) < maxoutputbytes );
  1085. i+=2, p++ )
  1086. {
  1087. *p = ( V_nibble( in[i] ) << 4 ) | V_nibble( in[i+1] );
  1088. }
  1089. }
  1090. //-----------------------------------------------------------------------------
  1091. // Purpose:
  1092. // Input : *in -
  1093. // inputbytes -
  1094. // *out -
  1095. // outsize -
  1096. //-----------------------------------------------------------------------------
  1097. void V_binarytohex( const byte *in, int inputbytes, char *out, int outsize )
  1098. {
  1099. Assert( outsize >= 1 );
  1100. char doublet[10];
  1101. int i;
  1102. out[0]=0;
  1103. for ( i = 0; i < inputbytes; i++ )
  1104. {
  1105. unsigned char c = in[i];
  1106. V_snprintf( doublet, sizeof( doublet ), "%02x", c );
  1107. V_strncat( out, doublet, outsize, COPY_ALL_CHARACTERS );
  1108. }
  1109. }
  1110. #define PATHSEPARATOR(c) ((c) == '\\' || (c) == '/')
  1111. //-----------------------------------------------------------------------------
  1112. // Purpose: Extracts the base name of a file (no path, no extension, assumes '/' or '\' as path separator)
  1113. // Input : *in -
  1114. // *out -
  1115. // maxlen -
  1116. //-----------------------------------------------------------------------------
  1117. void V_FileBase( const char *in, char *out, int maxlen )
  1118. {
  1119. Assert( maxlen >= 1 );
  1120. Assert( in );
  1121. Assert( out );
  1122. if ( !in || !in[ 0 ] )
  1123. {
  1124. *out = 0;
  1125. return;
  1126. }
  1127. int len, start, end;
  1128. len = V_strlen( in );
  1129. // scan backward for '.'
  1130. end = len - 1;
  1131. while ( end&& in[end] != '.' && !PATHSEPARATOR( in[end] ) )
  1132. {
  1133. end--;
  1134. }
  1135. if ( in[end] != '.' ) // no '.', copy to end
  1136. {
  1137. end = len-1;
  1138. }
  1139. else
  1140. {
  1141. end--; // Found ',', copy to left of '.'
  1142. }
  1143. // Scan backward for '/'
  1144. start = len-1;
  1145. while ( start >= 0 && !PATHSEPARATOR( in[start] ) )
  1146. {
  1147. start--;
  1148. }
  1149. if ( start < 0 || !PATHSEPARATOR( in[start] ) )
  1150. {
  1151. start = 0;
  1152. }
  1153. else
  1154. {
  1155. start++;
  1156. }
  1157. // Length of new sting
  1158. len = end - start + 1;
  1159. int maxcopy = MIN( len + 1, maxlen );
  1160. // Copy partial string
  1161. V_strncpy( out, &in[start], maxcopy );
  1162. }
  1163. //-----------------------------------------------------------------------------
  1164. // Purpose:
  1165. // Input : *ppath -
  1166. //-----------------------------------------------------------------------------
  1167. void V_StripTrailingSlash( char *ppath )
  1168. {
  1169. Assert( ppath );
  1170. int len = V_strlen( ppath );
  1171. if ( len > 0 )
  1172. {
  1173. if ( PATHSEPARATOR( ppath[ len - 1 ] ) )
  1174. {
  1175. ppath[ len - 1 ] = 0;
  1176. }
  1177. }
  1178. }
  1179. //-----------------------------------------------------------------------------
  1180. // Purpose:
  1181. // Input : *in -
  1182. // *out -
  1183. // outSize -
  1184. //-----------------------------------------------------------------------------
  1185. void V_StripExtension( const char *in, char *out, int outSize )
  1186. {
  1187. // Find the last dot. If it's followed by a dot or a slash, then it's part of a
  1188. // directory specifier like ../../somedir/./blah.
  1189. // scan backward for '.'
  1190. int end = V_strlen( in ) - 1;
  1191. while ( end > 0 && in[end] != '.' && !PATHSEPARATOR( in[end] ) )
  1192. {
  1193. --end;
  1194. }
  1195. if (end > 0 && !PATHSEPARATOR( in[end] ) && end < outSize)
  1196. {
  1197. int nChars = MIN( end, outSize-1 );
  1198. if ( out != in )
  1199. {
  1200. memcpy( out, in, nChars );
  1201. }
  1202. out[nChars] = 0;
  1203. }
  1204. else
  1205. {
  1206. // nothing found
  1207. if ( out != in )
  1208. {
  1209. V_strncpy( out, in, outSize );
  1210. }
  1211. }
  1212. }
  1213. //-----------------------------------------------------------------------------
  1214. // Purpose:
  1215. // Input : *path -
  1216. // *extension -
  1217. // pathStringLength -
  1218. //-----------------------------------------------------------------------------
  1219. void V_DefaultExtension( char *path, const char *extension, int pathStringLength )
  1220. {
  1221. Assert( path );
  1222. Assert( pathStringLength >= 1 );
  1223. Assert( extension );
  1224. char *src;
  1225. // if path doesn't have a .EXT, append extension
  1226. // (extension should include the .)
  1227. src = path + V_strlen(path) - 1;
  1228. while ( !PATHSEPARATOR( *src ) && ( src > path ) )
  1229. {
  1230. if (*src == '.')
  1231. {
  1232. // it has an extension
  1233. return;
  1234. }
  1235. src--;
  1236. }
  1237. // Concatenate the desired extension
  1238. char pTemp[MAX_PATH];
  1239. if ( extension[0] != '.' )
  1240. {
  1241. pTemp[0] = '.';
  1242. V_strncpy( &pTemp[1], extension, sizeof(pTemp) - 1 );
  1243. extension = pTemp;
  1244. }
  1245. V_strncat( path, extension, pathStringLength, COPY_ALL_CHARACTERS );
  1246. }
  1247. //-----------------------------------------------------------------------------
  1248. // Purpose: Force extension...
  1249. // Input : *path -
  1250. // *extension -
  1251. // pathStringLength -
  1252. //-----------------------------------------------------------------------------
  1253. void V_SetExtension( char *path, const char *extension, int pathStringLength )
  1254. {
  1255. V_StripExtension( path, path, pathStringLength );
  1256. V_DefaultExtension( path, extension, pathStringLength );
  1257. }
  1258. //-----------------------------------------------------------------------------
  1259. // Purpose: Remove final filename from string
  1260. // Input : *path -
  1261. // Output : void V_StripFilename
  1262. //-----------------------------------------------------------------------------
  1263. void V_StripFilename (char *path)
  1264. {
  1265. int length;
  1266. length = V_strlen( path )-1;
  1267. if ( length <= 0 )
  1268. return;
  1269. while ( length > 0 &&
  1270. !PATHSEPARATOR( path[length] ) )
  1271. {
  1272. length--;
  1273. }
  1274. path[ length ] = 0;
  1275. }
  1276. #ifdef _WIN32
  1277. #define CORRECT_PATH_SEPARATOR '\\'
  1278. #define INCORRECT_PATH_SEPARATOR '/'
  1279. #elif POSIX
  1280. #define CORRECT_PATH_SEPARATOR '/'
  1281. #define INCORRECT_PATH_SEPARATOR '\\'
  1282. #endif
  1283. //-----------------------------------------------------------------------------
  1284. // Purpose: Changes all '/' or '\' characters into separator
  1285. // Input : *pname -
  1286. // separator -
  1287. //-----------------------------------------------------------------------------
  1288. void V_FixSlashes( char *pname, char separator /* = CORRECT_PATH_SEPARATOR */ )
  1289. {
  1290. while ( *pname )
  1291. {
  1292. if ( *pname == INCORRECT_PATH_SEPARATOR || *pname == CORRECT_PATH_SEPARATOR )
  1293. {
  1294. *pname = separator;
  1295. }
  1296. pname++;
  1297. }
  1298. }
  1299. //-----------------------------------------------------------------------------
  1300. // Purpose: This function fixes cases of filenames like materials\\blah.vmt or somepath\otherpath\\ and removes the extra double slash.
  1301. //-----------------------------------------------------------------------------
  1302. void V_FixDoubleSlashes( char *pStr )
  1303. {
  1304. int len = V_strlen( pStr );
  1305. for ( int i=1; i < len-1; i++ )
  1306. {
  1307. if ( (pStr[i] == '/' || pStr[i] == '\\') && (pStr[i+1] == '/' || pStr[i+1] == '\\') )
  1308. {
  1309. // This means there's a double slash somewhere past the start of the filename. That
  1310. // can happen in Hammer if they use a material in the root directory. You'll get a filename
  1311. // that looks like 'materials\\blah.vmt'
  1312. V_memmove( &pStr[i], &pStr[i+1], len - i );
  1313. --len;
  1314. }
  1315. }
  1316. }
  1317. //-----------------------------------------------------------------------------
  1318. // Purpose: Strip off the last directory from dirName
  1319. // Input : *dirName -
  1320. // maxlen -
  1321. // Output : Returns true on success, false on failure.
  1322. //-----------------------------------------------------------------------------
  1323. bool V_StripLastDir( char *dirName, int maxlen )
  1324. {
  1325. if( dirName[0] == 0 ||
  1326. !V_stricmp( dirName, "./" ) ||
  1327. !V_stricmp( dirName, ".\\" ) )
  1328. return false;
  1329. int len = V_strlen( dirName );
  1330. Assert( len < maxlen );
  1331. // skip trailing slash
  1332. if ( PATHSEPARATOR( dirName[len-1] ) )
  1333. {
  1334. len--;
  1335. }
  1336. bool bHitColon = false;
  1337. while ( len > 0 )
  1338. {
  1339. if ( PATHSEPARATOR( dirName[len-1] ) )
  1340. {
  1341. dirName[len] = 0;
  1342. V_FixSlashes( dirName, CORRECT_PATH_SEPARATOR );
  1343. return true;
  1344. }
  1345. else if ( dirName[len-1] == ':' )
  1346. {
  1347. bHitColon = true;
  1348. }
  1349. len--;
  1350. }
  1351. // If we hit a drive letter, then we're done.
  1352. // Ex: If they passed in c:\, then V_StripLastDir should return "" and false.
  1353. if ( bHitColon )
  1354. {
  1355. dirName[0] = 0;
  1356. return false;
  1357. }
  1358. // Allow it to return an empty string and true. This can happen if something like "tf2/" is passed in.
  1359. // The correct behavior is to strip off the last directory ("tf2") and return true.
  1360. if ( len == 0 && !bHitColon )
  1361. {
  1362. V_snprintf( dirName, maxlen, ".%c", CORRECT_PATH_SEPARATOR );
  1363. return true;
  1364. }
  1365. return true;
  1366. }
  1367. //-----------------------------------------------------------------------------
  1368. // Purpose: Returns a pointer to the beginning of the unqualified file name
  1369. // (no path information)
  1370. // Input: in - file name (may be unqualified, relative or absolute path)
  1371. // Output: pointer to unqualified file name
  1372. //-----------------------------------------------------------------------------
  1373. const char * V_UnqualifiedFileName( const char * in )
  1374. {
  1375. if ( !in || !in[0] )
  1376. return in;
  1377. // back up until the character after the first path separator we find,
  1378. // or the beginning of the string
  1379. const char * out = in + strlen( in ) - 1;
  1380. while ( ( out > in ) && ( !PATHSEPARATOR( *( out-1 ) ) ) )
  1381. out--;
  1382. return out;
  1383. }
  1384. char *V_UnqualifiedFileName( char *in )
  1385. {
  1386. return const_cast<char *>( V_UnqualifiedFileName( const_cast<const char *>(in) ) );
  1387. }
  1388. //-----------------------------------------------------------------------------
  1389. // Purpose: Composes a path and filename together, inserting a path separator
  1390. // if need be
  1391. // Input: path - path to use
  1392. // filename - filename to use
  1393. // dest - buffer to compose result in
  1394. // destSize - size of destination buffer
  1395. //-----------------------------------------------------------------------------
  1396. void V_ComposeFileName( const char *path, const char *filename, char *dest, int destSize )
  1397. {
  1398. V_strncpy( dest, path, destSize );
  1399. V_FixSlashes( dest );
  1400. V_AppendSlash( dest, destSize );
  1401. V_strncat( dest, filename, destSize, COPY_ALL_CHARACTERS );
  1402. V_FixSlashes( dest );
  1403. }
  1404. //-----------------------------------------------------------------------------
  1405. // Purpose:
  1406. // Input : *path -
  1407. // *dest -
  1408. // destSize -
  1409. // Output : void V_ExtractFilePath
  1410. //-----------------------------------------------------------------------------
  1411. bool V_ExtractFilePath (const char *path, char *dest, int destSize )
  1412. {
  1413. Assert( destSize >= 1 );
  1414. if ( destSize < 1 )
  1415. {
  1416. return false;
  1417. }
  1418. // Last char
  1419. int len = V_strlen(path);
  1420. const char *src = path + (len ? len-1 : 0);
  1421. // back up until a \ or the start
  1422. while ( src != path && !PATHSEPARATOR( *(src-1) ) )
  1423. {
  1424. src--;
  1425. }
  1426. int copysize = MIN( src - path, destSize - 1 );
  1427. memcpy( dest, path, copysize );
  1428. dest[copysize] = 0;
  1429. return copysize != 0 ? true : false;
  1430. }
  1431. //-----------------------------------------------------------------------------
  1432. // Purpose:
  1433. // Input : *path -
  1434. // *dest -
  1435. // destSize -
  1436. // Output : void V_ExtractFileExtension
  1437. //-----------------------------------------------------------------------------
  1438. void V_ExtractFileExtension( const char *path, char *dest, int destSize )
  1439. {
  1440. *dest = 0;
  1441. const char * extension = V_GetFileExtension( path );
  1442. if ( NULL != extension )
  1443. V_strncpy( dest, extension, destSize );
  1444. }
  1445. //-----------------------------------------------------------------------------
  1446. // Purpose: Returns a pointer to the file extension within a file name string
  1447. // Input: in - file name
  1448. // Output: pointer to beginning of extension (after the "."), or NULL
  1449. // if there is no extension
  1450. //-----------------------------------------------------------------------------
  1451. const char * V_GetFileExtension( const char * path )
  1452. {
  1453. const char *src;
  1454. src = path + strlen(path) - 1;
  1455. //
  1456. // back up until a . or the start
  1457. //
  1458. while (src != path && !PATHSEPARATOR( *src ) && *(src-1) != '.' )
  1459. src--;
  1460. // check to see if the '.' is part of a pathname
  1461. if (src == path || PATHSEPARATOR( *src ) )
  1462. {
  1463. return NULL; // no extension
  1464. }
  1465. return src;
  1466. }
  1467. //-----------------------------------------------------------------------------
  1468. // Purpose: Returns a pointer to the filename part of a path string
  1469. // Input: in - file name
  1470. // Output: pointer to beginning of filename (after the "/"). If there were no /,
  1471. // output is identical to input
  1472. //-----------------------------------------------------------------------------
  1473. const char *V_GetFileName( const char *pPath )
  1474. {
  1475. if ( !pPath || !pPath[0] )
  1476. return pPath;
  1477. const char *pSrc;
  1478. pSrc = pPath + strlen( pPath ) - 1;
  1479. // back up until a / or the start
  1480. while ( pSrc > pPath && !PATHSEPARATOR( *( pSrc-1 ) ) )
  1481. --pSrc;
  1482. return pSrc;
  1483. }
  1484. bool V_RemoveDotSlashes( char *pFilename, char separator )
  1485. {
  1486. // Remove '//' or '\\'
  1487. char *pIn = pFilename;
  1488. char *pOut = pFilename;
  1489. bool bPrevPathSep = false;
  1490. while ( *pIn )
  1491. {
  1492. bool bIsPathSep = PATHSEPARATOR( *pIn );
  1493. if ( !bIsPathSep || !bPrevPathSep )
  1494. {
  1495. *pOut++ = *pIn;
  1496. }
  1497. bPrevPathSep = bIsPathSep;
  1498. ++pIn;
  1499. }
  1500. *pOut = 0;
  1501. // Get rid of "./"'s
  1502. pIn = pFilename;
  1503. pOut = pFilename;
  1504. while ( *pIn )
  1505. {
  1506. // The logic on the second line is preventing it from screwing up "../"
  1507. if ( pIn[0] == '.' && PATHSEPARATOR( pIn[1] ) &&
  1508. (pIn == pFilename || pIn[-1] != '.') )
  1509. {
  1510. pIn += 2;
  1511. }
  1512. else
  1513. {
  1514. *pOut = *pIn;
  1515. ++pIn;
  1516. ++pOut;
  1517. }
  1518. }
  1519. *pOut = 0;
  1520. // Get rid of a trailing "/." (needless).
  1521. int len = strlen( pFilename );
  1522. if ( len > 2 && pFilename[len-1] == '.' && PATHSEPARATOR( pFilename[len-2] ) )
  1523. {
  1524. pFilename[len-2] = 0;
  1525. }
  1526. // Each time we encounter a "..", back up until we've read the previous directory name,
  1527. // then get rid of it.
  1528. pIn = pFilename;
  1529. while ( *pIn )
  1530. {
  1531. if ( pIn[0] == '.' &&
  1532. pIn[1] == '.' &&
  1533. (pIn == pFilename || PATHSEPARATOR(pIn[-1])) && // Preceding character must be a slash.
  1534. (pIn[2] == 0 || PATHSEPARATOR(pIn[2])) ) // Following character must be a slash or the end of the string.
  1535. {
  1536. char *pEndOfDots = pIn + 2;
  1537. char *pStart = pIn - 2;
  1538. // Ok, now scan back for the path separator that starts the preceding directory.
  1539. while ( 1 )
  1540. {
  1541. if ( pStart < pFilename )
  1542. return false;
  1543. if ( PATHSEPARATOR( *pStart ) )
  1544. break;
  1545. --pStart;
  1546. }
  1547. // Now slide the string down to get rid of the previous directory and the ".."
  1548. memmove( pStart, pEndOfDots, strlen( pEndOfDots ) + 1 );
  1549. // Start over.
  1550. pIn = pFilename;
  1551. }
  1552. else
  1553. {
  1554. ++pIn;
  1555. }
  1556. }
  1557. V_FixSlashes( pFilename, separator );
  1558. return true;
  1559. }
  1560. void V_AppendSlash( char *pStr, int strSize )
  1561. {
  1562. int len = V_strlen( pStr );
  1563. if ( len > 0 && !PATHSEPARATOR(pStr[len-1]) )
  1564. {
  1565. if ( len+1 >= strSize )
  1566. Error( "V_AppendSlash: ran out of space on %s.", pStr );
  1567. pStr[len] = CORRECT_PATH_SEPARATOR;
  1568. pStr[len+1] = 0;
  1569. }
  1570. }
  1571. void V_MakeAbsolutePath( char *pOut, int outLen, const char *pPath, const char *pStartingDir )
  1572. {
  1573. if ( V_IsAbsolutePath( pPath ) )
  1574. {
  1575. // pPath is not relative.. just copy it.
  1576. V_strncpy( pOut, pPath, outLen );
  1577. }
  1578. else
  1579. {
  1580. // Make sure the starting directory is absolute..
  1581. if ( pStartingDir && V_IsAbsolutePath( pStartingDir ) )
  1582. {
  1583. V_strncpy( pOut, pStartingDir, outLen );
  1584. }
  1585. else
  1586. {
  1587. #ifdef _PS3
  1588. {
  1589. V_strncpy( pOut, g_pPS3PathInfo->GameImagePath(), outLen );
  1590. }
  1591. #else
  1592. {
  1593. if ( !_getcwd( pOut, outLen ) )
  1594. Error( "V_MakeAbsolutePath: _getcwd failed." );
  1595. }
  1596. #endif
  1597. if ( pStartingDir )
  1598. {
  1599. V_AppendSlash( pOut, outLen );
  1600. V_strncat( pOut, pStartingDir, outLen, COPY_ALL_CHARACTERS );
  1601. }
  1602. }
  1603. // Concatenate the paths.
  1604. V_AppendSlash( pOut, outLen );
  1605. V_strncat( pOut, pPath, outLen, COPY_ALL_CHARACTERS );
  1606. }
  1607. if ( !V_RemoveDotSlashes( pOut ) )
  1608. Error( "V_MakeAbsolutePath: tried to \"..\" past the root." );
  1609. V_FixSlashes( pOut );
  1610. }
  1611. //-----------------------------------------------------------------------------
  1612. // Makes a relative path
  1613. //-----------------------------------------------------------------------------
  1614. bool V_MakeRelativePath( const char *pFullPath, const char *pDirectory, char *pRelativePath, int nBufLen )
  1615. {
  1616. pRelativePath[0] = 0;
  1617. const char *pPath = pFullPath;
  1618. const char *pDir = pDirectory;
  1619. // Strip out common parts of the path
  1620. const char *pLastCommonPath = NULL;
  1621. const char *pLastCommonDir = NULL;
  1622. while ( *pPath && ( tolower( *pPath ) == tolower( *pDir ) ||
  1623. ( PATHSEPARATOR( *pPath ) && ( PATHSEPARATOR( *pDir ) || (*pDir == 0) ) ) ) )
  1624. {
  1625. if ( PATHSEPARATOR( *pPath ) )
  1626. {
  1627. pLastCommonPath = pPath + 1;
  1628. pLastCommonDir = pDir + 1;
  1629. }
  1630. if ( *pDir == 0 )
  1631. {
  1632. --pLastCommonDir;
  1633. break;
  1634. }
  1635. ++pDir; ++pPath;
  1636. }
  1637. // Nothing in common
  1638. if ( !pLastCommonPath )
  1639. return false;
  1640. // For each path separator remaining in the dir, need a ../
  1641. int nOutLen = 0;
  1642. bool bLastCharWasSeparator = true;
  1643. for ( ; *pLastCommonDir; ++pLastCommonDir )
  1644. {
  1645. if ( PATHSEPARATOR( *pLastCommonDir ) )
  1646. {
  1647. pRelativePath[nOutLen++] = '.';
  1648. pRelativePath[nOutLen++] = '.';
  1649. pRelativePath[nOutLen++] = CORRECT_PATH_SEPARATOR;
  1650. bLastCharWasSeparator = true;
  1651. }
  1652. else
  1653. {
  1654. bLastCharWasSeparator = false;
  1655. }
  1656. }
  1657. // Deal with relative paths not specified with a trailing slash
  1658. if ( !bLastCharWasSeparator )
  1659. {
  1660. pRelativePath[nOutLen++] = '.';
  1661. pRelativePath[nOutLen++] = '.';
  1662. pRelativePath[nOutLen++] = CORRECT_PATH_SEPARATOR;
  1663. }
  1664. // Copy the remaining part of the relative path over, fixing the path separators
  1665. for ( ; *pLastCommonPath; ++pLastCommonPath )
  1666. {
  1667. if ( PATHSEPARATOR( *pLastCommonPath ) )
  1668. {
  1669. pRelativePath[nOutLen++] = CORRECT_PATH_SEPARATOR;
  1670. }
  1671. else
  1672. {
  1673. pRelativePath[nOutLen++] = *pLastCommonPath;
  1674. }
  1675. // Check for overflow
  1676. if ( nOutLen == nBufLen - 1 )
  1677. break;
  1678. }
  1679. pRelativePath[nOutLen] = 0;
  1680. return true;
  1681. }
  1682. //-----------------------------------------------------------------------------
  1683. // small helper function shared by lots of modules
  1684. //-----------------------------------------------------------------------------
  1685. bool V_IsAbsolutePath( const char *pStr )
  1686. {
  1687. bool bIsAbsolute = ( pStr[0] && pStr[1] == ':' ) || pStr[0] == '/' || pStr[0] == '\\';
  1688. if ( IsX360() && !bIsAbsolute )
  1689. {
  1690. bIsAbsolute = ( V_stristr( pStr, ":" ) != NULL );
  1691. }
  1692. return bIsAbsolute;
  1693. }
  1694. //-----------------------------------------------------------------------------
  1695. // Fixes up a file name, removing dot slashes, fixing slashes, converting to lowercase, etc.
  1696. //-----------------------------------------------------------------------------
  1697. void V_FixupPathName( char *pOut, size_t nOutLen, const char *pPath )
  1698. {
  1699. V_strncpy( pOut, pPath, nOutLen );
  1700. V_FixSlashes( pOut );
  1701. V_RemoveDotSlashes( pOut );
  1702. V_FixDoubleSlashes( pOut );
  1703. V_strlower( pOut );
  1704. }
  1705. // Copies at most nCharsToCopy bytes from pIn into pOut.
  1706. // Returns false if it would have overflowed pOut's buffer.
  1707. static bool CopyToMaxChars( char *pOut, int outSize, const char *pIn, int nCharsToCopy )
  1708. {
  1709. if ( outSize == 0 )
  1710. return false;
  1711. int iOut = 0;
  1712. while ( *pIn && nCharsToCopy > 0 )
  1713. {
  1714. if ( iOut == (outSize-1) )
  1715. {
  1716. pOut[iOut] = 0;
  1717. return false;
  1718. }
  1719. pOut[iOut] = *pIn;
  1720. ++iOut;
  1721. ++pIn;
  1722. --nCharsToCopy;
  1723. }
  1724. pOut[iOut] = 0;
  1725. return true;
  1726. }
  1727. // Returns true if it completed successfully.
  1728. // If it would overflow pOut, it fills as much as it can and returns false.
  1729. bool V_StrSubst(
  1730. const char *pIn,
  1731. const char *pMatch,
  1732. const char *pReplaceWith,
  1733. char *pOut,
  1734. int outLen,
  1735. bool bCaseSensitive
  1736. )
  1737. {
  1738. int replaceFromLen = strlen( pMatch );
  1739. int replaceToLen = strlen( pReplaceWith );
  1740. const char *pInStart = pIn;
  1741. char *pOutPos = pOut;
  1742. pOutPos[0] = 0;
  1743. while ( 1 )
  1744. {
  1745. int nRemainingOut = outLen - (pOutPos - pOut);
  1746. const char *pTestPos = ( bCaseSensitive ? strstr( pInStart, pMatch ) : V_stristr( pInStart, pMatch ) );
  1747. if ( pTestPos )
  1748. {
  1749. // Found an occurence of pMatch. First, copy whatever leads up to the string.
  1750. int copyLen = pTestPos - pInStart;
  1751. if ( !CopyToMaxChars( pOutPos, nRemainingOut, pInStart, copyLen ) )
  1752. return false;
  1753. // Did we hit the end of the output string?
  1754. if ( copyLen > nRemainingOut-1 )
  1755. return false;
  1756. pOutPos += strlen( pOutPos );
  1757. nRemainingOut = outLen - (pOutPos - pOut);
  1758. // Now add the replacement string.
  1759. if ( !CopyToMaxChars( pOutPos, nRemainingOut, pReplaceWith, replaceToLen ) )
  1760. return false;
  1761. pInStart += copyLen + replaceFromLen;
  1762. pOutPos += replaceToLen;
  1763. }
  1764. else
  1765. {
  1766. // We're at the end of pIn. Copy whatever remains and get out.
  1767. int copyLen = strlen( pInStart );
  1768. V_strncpy( pOutPos, pInStart, nRemainingOut );
  1769. return ( copyLen <= nRemainingOut-1 );
  1770. }
  1771. }
  1772. }
  1773. char* AllocString( const char *pStr, int nMaxChars )
  1774. {
  1775. int allocLen;
  1776. if ( nMaxChars == -1 )
  1777. allocLen = strlen( pStr ) + 1;
  1778. else
  1779. allocLen = MIN( (int)strlen(pStr), nMaxChars ) + 1;
  1780. char *pOut = new char[allocLen];
  1781. V_strncpy( pOut, pStr, allocLen );
  1782. return pOut;
  1783. }
  1784. void V_SplitString2( const char *pString, const char **pSeparators, int nSeparators, CUtlVector<char*> &outStrings )
  1785. {
  1786. outStrings.Purge();
  1787. const char *pCurPos = pString;
  1788. while ( 1 )
  1789. {
  1790. int iFirstSeparator = -1;
  1791. const char *pFirstSeparator = 0;
  1792. for ( int i=0; i < nSeparators; i++ )
  1793. {
  1794. const char *pTest = V_stristr( pCurPos, pSeparators[i] );
  1795. if ( pTest && (!pFirstSeparator || pTest < pFirstSeparator) )
  1796. {
  1797. iFirstSeparator = i;
  1798. pFirstSeparator = pTest;
  1799. }
  1800. }
  1801. if ( pFirstSeparator )
  1802. {
  1803. // Split on this separator and continue on.
  1804. int separatorLen = strlen( pSeparators[iFirstSeparator] );
  1805. if ( pFirstSeparator > pCurPos )
  1806. {
  1807. outStrings.AddToTail( AllocString( pCurPos, pFirstSeparator-pCurPos ) );
  1808. }
  1809. pCurPos = pFirstSeparator + separatorLen;
  1810. }
  1811. else
  1812. {
  1813. // Copy the rest of the string
  1814. if ( strlen( pCurPos ) )
  1815. {
  1816. outStrings.AddToTail( AllocString( pCurPos, -1 ) );
  1817. }
  1818. return;
  1819. }
  1820. }
  1821. }
  1822. void V_SplitString( const char *pString, const char *pSeparator, CUtlVector<char*> &outStrings )
  1823. {
  1824. V_SplitString2( pString, &pSeparator, 1, outStrings );
  1825. }
  1826. bool V_GetCurrentDirectory( char *pOut, int maxLen )
  1827. {
  1828. #if defined( _PS3 )
  1829. Assert( 0 );
  1830. return false; // not supported
  1831. #else // !_PS3
  1832. return _getcwd( pOut, maxLen ) == pOut;
  1833. #endif // _PS3
  1834. }
  1835. bool V_SetCurrentDirectory( const char *pDirName )
  1836. {
  1837. #if defined( _PS3 )
  1838. Assert( 0 );
  1839. return false; // not supported
  1840. #else // !_PS3
  1841. return _chdir( pDirName ) == 0;
  1842. #endif // _PS3
  1843. }
  1844. // This function takes a slice out of pStr and stores it in pOut.
  1845. // It follows the Python slice convention:
  1846. // Negative numbers wrap around the string (-1 references the last character).
  1847. // Numbers are clamped to the end of the string.
  1848. void V_StrSlice( const char *pStr, int firstChar, int lastCharNonInclusive, char *pOut, int outSize )
  1849. {
  1850. if ( outSize == 0 )
  1851. return;
  1852. int length = strlen( pStr );
  1853. // Fixup the string indices.
  1854. if ( firstChar < 0 )
  1855. {
  1856. firstChar = length - (-firstChar % length);
  1857. }
  1858. else if ( firstChar >= length )
  1859. {
  1860. pOut[0] = 0;
  1861. return;
  1862. }
  1863. if ( lastCharNonInclusive < 0 )
  1864. {
  1865. lastCharNonInclusive = length - (-lastCharNonInclusive % length);
  1866. }
  1867. else if ( lastCharNonInclusive > length )
  1868. {
  1869. lastCharNonInclusive %= length;
  1870. }
  1871. if ( lastCharNonInclusive <= firstChar )
  1872. {
  1873. pOut[0] = 0;
  1874. return;
  1875. }
  1876. int copyLen = lastCharNonInclusive - firstChar;
  1877. if ( copyLen <= (outSize-1) )
  1878. {
  1879. memcpy( pOut, &pStr[firstChar], copyLen );
  1880. pOut[copyLen] = 0;
  1881. }
  1882. else
  1883. {
  1884. memcpy( pOut, &pStr[firstChar], outSize-1 );
  1885. pOut[outSize-1] = 0;
  1886. }
  1887. }
  1888. void V_StrLeft( const char *pStr, int nChars, char *pOut, int outSize )
  1889. {
  1890. if ( nChars == 0 )
  1891. {
  1892. if ( outSize != 0 )
  1893. pOut[0] = 0;
  1894. return;
  1895. }
  1896. V_StrSlice( pStr, 0, nChars, pOut, outSize );
  1897. }
  1898. void V_StrRight( const char *pStr, int nChars, char *pOut, int outSize )
  1899. {
  1900. int len = strlen( pStr );
  1901. if ( nChars >= len )
  1902. {
  1903. V_strncpy( pOut, pStr, outSize );
  1904. }
  1905. else
  1906. {
  1907. V_StrSlice( pStr, -nChars, strlen( pStr ), pOut, outSize );
  1908. }
  1909. }
  1910. //-----------------------------------------------------------------------------
  1911. // Convert multibyte to wchar + back
  1912. //-----------------------------------------------------------------------------
  1913. void V_strtowcs( const char *pString, int nInSize, wchar_t *pWString, int nOutSize )
  1914. {
  1915. #ifdef _WIN32
  1916. if ( !MultiByteToWideChar( CP_UTF8, 0, pString, nInSize, pWString, nOutSize ) )
  1917. {
  1918. *pWString = L'\0';
  1919. }
  1920. #elif POSIX
  1921. if ( mbstowcs( pWString, pString, nOutSize / sizeof(wchar_t) ) <= 0 )
  1922. {
  1923. *pWString = 0;
  1924. }
  1925. #endif
  1926. }
  1927. void V_wcstostr( const wchar_t *pWString, int nInSize, char *pString, int nOutSize )
  1928. {
  1929. #ifdef _WIN32
  1930. if ( !WideCharToMultiByte( CP_UTF8, 0, pWString, nInSize, pString, nOutSize, NULL, NULL ) )
  1931. {
  1932. *pString = '\0';
  1933. }
  1934. #elif POSIX
  1935. if ( wcstombs( pString, pWString, nOutSize ) <= 0 )
  1936. {
  1937. *pString = '\0';
  1938. }
  1939. #endif
  1940. }
  1941. //--------------------------------------------------------------------------------
  1942. // backslashification
  1943. //--------------------------------------------------------------------------------
  1944. static char s_BackSlashMap[]="\tt\nn\rr\"\"\\\\";
  1945. char *V_AddBackSlashesToSpecialChars( char const *pSrc )
  1946. {
  1947. // first, count how much space we are going to need
  1948. int nSpaceNeeded = 0;
  1949. for( char const *pScan = pSrc; *pScan; pScan++ )
  1950. {
  1951. nSpaceNeeded++;
  1952. for(char const *pCharSet=s_BackSlashMap; *pCharSet; pCharSet += 2 )
  1953. {
  1954. if ( *pCharSet == *pScan )
  1955. nSpaceNeeded++; // we need to store a bakslash
  1956. }
  1957. }
  1958. char *pRet = new char[ nSpaceNeeded + 1 ]; // +1 for null
  1959. char *pOut = pRet;
  1960. for( char const *pScan = pSrc; *pScan; pScan++ )
  1961. {
  1962. bool bIsSpecial = false;
  1963. for(char const *pCharSet=s_BackSlashMap; *pCharSet; pCharSet += 2 )
  1964. {
  1965. if ( *pCharSet == *pScan )
  1966. {
  1967. *( pOut++ ) = '\\';
  1968. *( pOut++ ) = pCharSet[1];
  1969. bIsSpecial = true;
  1970. break;
  1971. }
  1972. }
  1973. if (! bIsSpecial )
  1974. {
  1975. *( pOut++ ) = *pScan;
  1976. }
  1977. }
  1978. *( pOut++ ) = 0;
  1979. return pRet;
  1980. }
  1981. void V_StringToIntArray( int *pVector, int count, const char *pString )
  1982. {
  1983. char *pstr, *pfront, tempString[128];
  1984. int j;
  1985. V_strncpy( tempString, pString, sizeof(tempString) );
  1986. pstr = pfront = tempString;
  1987. for ( j = 0; j < count; j++ ) // lifted from pr_edict.c
  1988. {
  1989. pVector[j] = atoi( pfront );
  1990. while ( *pstr && *pstr != ' ' )
  1991. pstr++;
  1992. if (!*pstr)
  1993. break;
  1994. pstr++;
  1995. pfront = pstr;
  1996. }
  1997. for ( j++; j < count; j++ )
  1998. {
  1999. pVector[j] = 0;
  2000. }
  2001. }
  2002. void V_StringToColor32( color32 *color, const char *pString )
  2003. {
  2004. int tmp[4];
  2005. V_StringToIntArray( tmp, 4, pString );
  2006. color->r = tmp[0];
  2007. color->g = tmp[1];
  2008. color->b = tmp[2];
  2009. color->a = tmp[3];
  2010. }
  2011. // 3d memory copy
  2012. void CopyMemory3D( void *pDest, void const *pSrc,
  2013. int nNumCols, int nNumRows, int nNumSlices, // dimensions of copy
  2014. int nSrcBytesPerRow, int nSrcBytesPerSlice, // strides for source.
  2015. int nDestBytesPerRow, int nDestBytesPerSlice // strides for dest
  2016. )
  2017. {
  2018. if ( nNumSlices && nNumRows && nNumCols )
  2019. {
  2020. uint8 *pDestAdr = reinterpret_cast<uint8 *>( pDest );
  2021. uint8 const *pSrcAdr = reinterpret_cast<uint8 const *>( pSrc );
  2022. // first check for optimized cases
  2023. if ( ( nNumCols == nSrcBytesPerRow ) && ( nNumCols == nDestBytesPerRow ) ) // no row-to-row stride?
  2024. {
  2025. int n2DSize = nNumCols * nNumRows;
  2026. if ( nSrcBytesPerSlice == nDestBytesPerSlice ) // can we do one memcpy?
  2027. {
  2028. memcpy( pDestAdr, pSrcAdr, n2DSize * nNumSlices );
  2029. }
  2030. else
  2031. {
  2032. // there might be some slice-to-slice stride
  2033. do
  2034. {
  2035. memcpy( pDestAdr, pSrcAdr, n2DSize );
  2036. pDestAdr += nDestBytesPerSlice;
  2037. pSrcAdr += nSrcBytesPerSlice;
  2038. } while( nNumSlices-- );
  2039. }
  2040. }
  2041. else
  2042. {
  2043. // there is row-by-row stride - we have to do the full nested loop
  2044. do
  2045. {
  2046. int nRowCtr = nNumRows;
  2047. uint8 const *pSrcRow = pSrcAdr;
  2048. uint8 *pDestRow = pDestAdr;
  2049. do
  2050. {
  2051. memcpy( pDestRow, pSrcRow, nNumCols );
  2052. pDestRow += nDestBytesPerRow;
  2053. pSrcRow += nSrcBytesPerRow;
  2054. } while( --nRowCtr );
  2055. pSrcAdr += nSrcBytesPerSlice;
  2056. pDestAdr += nDestBytesPerSlice;
  2057. } while( nNumSlices-- );
  2058. }
  2059. }
  2060. }
  2061. void V_TranslateLineFeedsToUnix( char *pStr )
  2062. {
  2063. char *pIn = pStr;
  2064. char *pOut = pStr;
  2065. while ( *pIn )
  2066. {
  2067. if ( pIn[0] == '\r' && pIn[1] == '\n' )
  2068. {
  2069. ++pIn;
  2070. }
  2071. *pOut++ = *pIn++;
  2072. }
  2073. *pOut = 0;
  2074. }
  2075. static char s_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
  2076. int HexToValue( char hex )
  2077. {
  2078. if( hex >= '0' && hex <= '9' )
  2079. {
  2080. return hex - '0';
  2081. }
  2082. if( hex >= 'A' && hex <= 'F' )
  2083. {
  2084. return hex - 'A' + 10;
  2085. }
  2086. if( hex >= 'a' && hex <= 'f' )
  2087. {
  2088. return hex - 'a' + 10;
  2089. }
  2090. // report error here
  2091. return -1;
  2092. }
  2093. bool V_StringToBin( const char*pString, void *pBin, uint nBinSize )
  2094. {
  2095. if ( (uint)V_strlen( pString ) != nBinSize * 2 )
  2096. {
  2097. return false;
  2098. }
  2099. for ( uint i = 0; i < nBinSize; ++i )
  2100. {
  2101. int high = HexToValue( pString[i*2+0] );
  2102. int low = HexToValue( pString[i*2+1] ) ;
  2103. if( high < 0 || low < 0 )
  2104. {
  2105. return false;
  2106. }
  2107. ( ( uint8* )pBin )[i] = uint8( ( high << 4 ) | low );
  2108. }
  2109. return true;
  2110. }
  2111. bool V_BinToString( char*pString, void *pBin, uint nBinSize )
  2112. {
  2113. for ( uint i = 0; i < nBinSize; ++i )
  2114. {
  2115. pString[i*2+0] = s_hex[( ( uint8* )pBin )[i] >> 4 ];
  2116. pString[i*2+1] = s_hex[( ( uint8* )pBin )[i] & 0xF];
  2117. }
  2118. pString[nBinSize*2] = '\0';
  2119. return true;
  2120. }
  2121. // The following characters are not allowed to begin a line for Asian language line-breaking
  2122. // purposes. They include the right parenthesis/bracket, space character, period, exclamation,
  2123. // question mark, and a number of language-specific characters for Chinese, Japanese, and Korean
  2124. static const wchar_t wszCantBeginLine[] =
  2125. {
  2126. 0x0020, 0x0021, 0x0025, 0x0029, 0x002c, 0x002e, 0x003a, 0x003b,
  2127. 0x003e, 0x003f, 0x005d, 0x007d, 0x00a2, 0x00a8, 0x00b0, 0x00b7,
  2128. 0x00bb, 0x02c7, 0x02c9, 0x2010, 0x2013, 0x2014, 0x2015, 0x2016,
  2129. 0x2019, 0x201d, 0x201e, 0x201f, 0x2020, 0x2021, 0x2022, 0x2025,
  2130. 0x2026, 0x2027, 0x203a, 0x203c, 0x2047, 0x2048, 0x2049, 0x2103,
  2131. 0x2236, 0x2574, 0x3001, 0x3002, 0x3003, 0x3005, 0x3006, 0x3009,
  2132. 0x300b, 0x300d, 0x300f, 0x3011, 0x3015, 0x3017, 0x3019, 0x301b,
  2133. 0x301c, 0x301e, 0x301f, 0x303b, 0x3041, 0x3043, 0x3045, 0x3047,
  2134. 0x3049, 0x3063, 0x3083, 0x3085, 0x3087, 0x308e, 0x3095, 0x3096,
  2135. 0x30a0, 0x30a1, 0x30a3, 0x30a5, 0x30a7, 0x30a9, 0x30c3, 0x30e3,
  2136. 0x30e5, 0x30e7, 0x30ee, 0x30f5, 0x30f6, 0x30fb, 0x30fd, 0x30fe,
  2137. 0x30fc, 0x31f0, 0x31f1, 0x31f2, 0x31f3, 0x31f4, 0x31f5, 0x31f6,
  2138. 0x31f7, 0x31f8, 0x31f9, 0x31fa, 0x31fb, 0x31fc, 0x31fd, 0x31fe,
  2139. 0x31ff, 0xfe30, 0xfe31, 0xfe32, 0xfe33, 0xfe36, 0xfe38, 0xfe3a,
  2140. 0xfe3c, 0xfe3e, 0xfe40, 0xfe42, 0xfe44, 0xfe4f, 0xfe50, 0xfe51,
  2141. 0xfe52, 0xfe53, 0xfe54, 0xfe55, 0xfe56, 0xfe57, 0xfe58, 0xfe5a,
  2142. 0xfe5c, 0xfe5e, 0xff01, 0xff02, 0xff05, 0xff07, 0xff09, 0xff0c,
  2143. 0xff0e, 0xff1a, 0xff1b, 0xff1f, 0xff3d, 0xff40, 0xff5c, 0xff5d,
  2144. 0xff5e, 0xff60, 0xff64
  2145. };
  2146. // The following characters are not allowed to end a line for Asian Language line-breaking
  2147. // purposes. They include left parenthesis/bracket, currency symbols, and an number
  2148. // of language-specific characters for Chinese, Japanese, and Korean
  2149. static const wchar_t wszCantEndLine[] =
  2150. {
  2151. 0x0024, 0x0028, 0x002a, 0x003c, 0x005b, 0x005c, 0x007b, 0x00a3,
  2152. 0x00a5, 0x00ab, 0x00ac, 0x00b7, 0x02c6, 0x2018, 0x201c, 0x201f,
  2153. 0x2035, 0x2039, 0x3005, 0x3007, 0x3008, 0x300a, 0x300c, 0x300e,
  2154. 0x3010, 0x3014, 0x3016, 0x3018, 0x301a, 0x301d, 0xfe34, 0xfe35,
  2155. 0xfe37, 0xfe39, 0xfe3b, 0xfe3d, 0xfe3f, 0xfe41, 0xfe43, 0xfe59,
  2156. 0xfe5b, 0xfe5d, 0xff04, 0xff08, 0xff0e, 0xff3b, 0xff5b, 0xff5f,
  2157. 0xffe1, 0xffe5, 0xffe6
  2158. };
  2159. // Can't break between some repeated punctuation patterns ("--", "...", "<asian period repeated>")
  2160. static const wchar_t wszCantBreakRepeated[] =
  2161. {
  2162. 0x002d, 0x002e, 0x3002
  2163. };
  2164. bool AsianWordWrap::CanEndLine( wchar_t wcCandidate )
  2165. {
  2166. for( int i = 0; i < SIZE_OF_ARRAY( wszCantEndLine ); ++i )
  2167. {
  2168. if( wcCandidate == wszCantEndLine[i] )
  2169. return false;
  2170. }
  2171. return true;
  2172. }
  2173. bool AsianWordWrap::CanBeginLine( wchar_t wcCandidate )
  2174. {
  2175. for( int i = 0; i < SIZE_OF_ARRAY( wszCantBeginLine ); ++i )
  2176. {
  2177. if( wcCandidate == wszCantBeginLine[i] )
  2178. return false;
  2179. }
  2180. return true;
  2181. }
  2182. bool AsianWordWrap::CanBreakRepeated( wchar_t wcCandidate )
  2183. {
  2184. for( int i = 0; i < SIZE_OF_ARRAY( wszCantBreakRepeated ); ++i )
  2185. {
  2186. if( wcCandidate == wszCantBreakRepeated[i] )
  2187. return false;
  2188. }
  2189. return true;
  2190. }
  2191. #if defined( _PS3 ) || defined( LINUX )
  2192. inline int __cdecl iswascii(wchar_t c) { return ((unsigned)(c) < 0x80); } // not defined in wctype.h on the PS3
  2193. #endif
  2194. // Used to determine if we can break a line between the first two characters passed
  2195. bool AsianWordWrap::CanBreakAfter( const wchar_t* wsz )
  2196. {
  2197. if( wsz == NULL || wsz[0] == '\0' || wsz[1] == '\0' )
  2198. {
  2199. return false;
  2200. }
  2201. wchar_t first_char = wsz[0];
  2202. wchar_t second_char = wsz[1];
  2203. if( ( iswascii( first_char ) && iswascii( second_char ) ) // If not both CJK, return early
  2204. || ( iswalnum( first_char ) && iswalnum( second_char ) ) ) // both characters are alphanumeric - Don't split a number or a word!
  2205. {
  2206. return false;
  2207. }
  2208. if( !CanEndLine( first_char ) )
  2209. {
  2210. return false;
  2211. }
  2212. if( !CanBeginLine( second_char) )
  2213. {
  2214. return false;
  2215. }
  2216. // don't allow line wrapping in the middle of "--" or "..."
  2217. if( ( first_char == second_char ) && ( !CanBreakRepeated( first_char ) ) )
  2218. {
  2219. return false;
  2220. }
  2221. // If no rules would prevent us from breaking, assume it's safe to break here
  2222. return true;
  2223. }
  2224. // We use this function to determine where it is permissible to break lines
  2225. // of text while wrapping them. On some platforms, the native iswspace() function
  2226. // returns FALSE for the "non-breaking space" characters 0x00a0 and 0x202f, and so we don't
  2227. // break on them. On others (including the X360 and PC), iswspace returns TRUE for them.
  2228. // We get rid of the platform dependency by defining this wrapper which returns false
  2229. // for &nbsp; and calls through to the library function for everything else.
  2230. int isbreakablewspace( wchar_t ch )
  2231. {
  2232. // 0x00a0 and 0x202f are the wide and narrow non-breaking space UTF-16 values, respectively
  2233. return ch != 0x00a0 && ch != 0x202f && iswspace(ch);
  2234. }