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.

572 lines
21 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include <limits.h>
  9. #include "tier0/dbg.h"
  10. #include "tier1/strtools.h"
  11. // This code was copied from steam
  12. #define DbgAssert Assert
  13. //-----------------------------------------------------------------------------
  14. // Purpose: determine if a uchar32 represents a valid Unicode code point
  15. //-----------------------------------------------------------------------------
  16. bool Q_IsValidUChar32( uchar32 uVal )
  17. {
  18. // Values > 0x10FFFF are explicitly invalid; ditto for UTF-16 surrogate halves,
  19. // values ending in FFFE or FFFF, or values in the 0x00FDD0-0x00FDEF reserved range
  20. return ( uVal < 0x110000u ) && ( (uVal - 0x00D800u) > 0x7FFu ) && ( (uVal & 0xFFFFu) < 0xFFFEu ) && ( ( uVal - 0x00FDD0u ) > 0x1Fu );
  21. }
  22. //-----------------------------------------------------------------------------
  23. // Purpose: return number of UTF-8 bytes required to encode a Unicode code point
  24. //-----------------------------------------------------------------------------
  25. int Q_UChar32ToUTF8Len( uchar32 uVal )
  26. {
  27. DbgAssert( Q_IsValidUChar32( uVal ) );
  28. if ( uVal <= 0x7F )
  29. return 1;
  30. if ( uVal <= 0x7FF )
  31. return 2;
  32. if ( uVal <= 0xFFFF )
  33. return 3;
  34. return 4;
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Purpose: return number of UTF-16 elements required to encode a Unicode code point
  38. //-----------------------------------------------------------------------------
  39. int Q_UChar32ToUTF16Len( uchar32 uVal )
  40. {
  41. DbgAssert( Q_IsValidUChar32( uVal ) );
  42. if ( uVal <= 0xFFFF )
  43. return 1;
  44. return 2;
  45. }
  46. //-----------------------------------------------------------------------------
  47. // Purpose: encode Unicode code point as UTF-8, returns number of bytes written
  48. //-----------------------------------------------------------------------------
  49. int Q_UChar32ToUTF8( uchar32 uVal, char *pUTF8Out )
  50. {
  51. DbgAssert( Q_IsValidUChar32( uVal ) );
  52. if ( uVal <= 0x7F )
  53. {
  54. pUTF8Out[0] = (unsigned char) uVal;
  55. return 1;
  56. }
  57. if ( uVal <= 0x7FF )
  58. {
  59. pUTF8Out[0] = (unsigned char)(uVal >> 6) | 0xC0;
  60. pUTF8Out[1] = (unsigned char)(uVal & 0x3F) | 0x80;
  61. return 2;
  62. }
  63. if ( uVal <= 0xFFFF )
  64. {
  65. pUTF8Out[0] = (unsigned char)(uVal >> 12) | 0xE0;
  66. pUTF8Out[1] = (unsigned char)((uVal >> 6) & 0x3F) | 0x80;
  67. pUTF8Out[2] = (unsigned char)(uVal & 0x3F) | 0x80;
  68. return 3;
  69. }
  70. pUTF8Out[0] = (unsigned char)((uVal >> 18) & 0x07) | 0xF0;
  71. pUTF8Out[1] = (unsigned char)((uVal >> 12) & 0x3F) | 0x80;
  72. pUTF8Out[2] = (unsigned char)((uVal >> 6) & 0x3F) | 0x80;
  73. pUTF8Out[3] = (unsigned char)(uVal & 0x3F) | 0x80;
  74. return 4;
  75. }
  76. //-----------------------------------------------------------------------------
  77. // Purpose: encode Unicode code point as UTF-16, returns number of elements written
  78. //-----------------------------------------------------------------------------
  79. int Q_UChar32ToUTF16( uchar32 uVal, uchar16 *pUTF16Out )
  80. {
  81. DbgAssert( Q_IsValidUChar32( uVal ) );
  82. if ( uVal <= 0xFFFF )
  83. {
  84. pUTF16Out[0] = (uchar16) uVal;
  85. return 1;
  86. }
  87. uVal -= 0x010000;
  88. pUTF16Out[0] = (uchar16)(uVal >> 10) | 0xD800;
  89. pUTF16Out[1] = (uchar16)(uVal & 0x3FF) | 0xDC00;
  90. return 2;
  91. }
  92. // Decode one character from a UTF-8 encoded string. Treats 6-byte CESU-8 sequences
  93. // as a single character, as if they were a correctly-encoded 4-byte UTF-8 sequence.
  94. int Q_UTF8ToUChar32( const char *pUTF8_, uchar32 &uValueOut, bool &bErrorOut )
  95. {
  96. const uint8 *pUTF8 = (const uint8 *)pUTF8_;
  97. int nBytes = 1;
  98. uint32 uValue = pUTF8[0];
  99. uint32 uMinValue = 0;
  100. // 0....... single byte
  101. if ( uValue < 0x80 )
  102. goto decodeFinishedNoCheck;
  103. // Expecting at least a two-byte sequence with 0xC0 <= first <= 0xF7 (110...... and 11110...)
  104. if ( (uValue - 0xC0u) > 0x37u || ( pUTF8[1] & 0xC0 ) != 0x80 )
  105. goto decodeError;
  106. uValue = (uValue << 6) - (0xC0 << 6) + pUTF8[1] - 0x80;
  107. nBytes = 2;
  108. uMinValue = 0x80;
  109. // 110..... two-byte lead byte
  110. if ( !( uValue & (0x20 << 6) ) )
  111. goto decodeFinished;
  112. // Expecting at least a three-byte sequence
  113. if ( ( pUTF8[2] & 0xC0 ) != 0x80 )
  114. goto decodeError;
  115. uValue = (uValue << 6) - (0x20 << 12) + pUTF8[2] - 0x80;
  116. nBytes = 3;
  117. uMinValue = 0x800;
  118. // 1110.... three-byte lead byte
  119. if ( !( uValue & (0x10 << 12) ) )
  120. goto decodeFinishedMaybeCESU8;
  121. // Expecting a four-byte sequence, longest permissible in UTF-8
  122. if ( ( pUTF8[3] & 0xC0 ) != 0x80 )
  123. goto decodeError;
  124. uValue = (uValue << 6) - (0x10 << 18) + pUTF8[3] - 0x80;
  125. nBytes = 4;
  126. uMinValue = 0x10000;
  127. // 11110... four-byte lead byte. fall through to finished.
  128. decodeFinished:
  129. if ( uValue >= uMinValue && Q_IsValidUChar32( uValue ) )
  130. {
  131. decodeFinishedNoCheck:
  132. uValueOut = uValue;
  133. bErrorOut = false;
  134. return nBytes;
  135. }
  136. decodeError:
  137. uValueOut = '?';
  138. bErrorOut = true;
  139. return nBytes;
  140. decodeFinishedMaybeCESU8:
  141. // Do we have a full UTF-16 surrogate pair that's been UTF-8 encoded afterwards?
  142. // That is, do we have 0xD800-0xDBFF followed by 0xDC00-0xDFFF? If so, decode it all.
  143. if ( ( uValue - 0xD800u ) < 0x400u && pUTF8[3] == 0xED && (uint8)( pUTF8[4] - 0xB0 ) < 0x10 && ( pUTF8[5] & 0xC0 ) == 0x80 )
  144. {
  145. uValue = 0x10000 + ( ( uValue - 0xD800u ) << 10 ) + ( (uint8)( pUTF8[4] - 0xB0 ) << 6 ) + pUTF8[5] - 0x80;
  146. nBytes = 6;
  147. uMinValue = 0x10000;
  148. }
  149. goto decodeFinished;
  150. }
  151. // Decode one character from a UTF-16 encoded string.
  152. int Q_UTF16ToUChar32( const uchar16 *pUTF16, uchar32 &uValueOut, bool &bErrorOut )
  153. {
  154. if ( Q_IsValidUChar32( pUTF16[0] ) )
  155. {
  156. uValueOut = pUTF16[0];
  157. bErrorOut = false;
  158. return 1;
  159. }
  160. else if ( (pUTF16[0] - 0xD800u) < 0x400u && (pUTF16[1] - 0xDC00u) < 0x400u )
  161. {
  162. // Valid surrogate pair, but maybe not encoding a valid Unicode code point...
  163. uchar32 uVal = 0x010000 + ((pUTF16[0] - 0xD800u) << 10) + (pUTF16[1] - 0xDC00);
  164. if ( Q_IsValidUChar32( uVal ) )
  165. {
  166. uValueOut = uVal;
  167. bErrorOut = false;
  168. return 2;
  169. }
  170. else
  171. {
  172. uValueOut = '?';
  173. bErrorOut = true;
  174. return 2;
  175. }
  176. }
  177. else
  178. {
  179. uValueOut = '?';
  180. bErrorOut = true;
  181. return 1;
  182. }
  183. }
  184. namespace // internal use only
  185. {
  186. // Identity transformations and validity tests for use with Q_UnicodeConvertT
  187. int Q_UTF32ToUChar32( const uchar32 *pUTF32, uchar32 &uVal, bool &bErr )
  188. {
  189. bErr = !Q_IsValidUChar32( *pUTF32 );
  190. uVal = bErr ? '?' : *pUTF32;
  191. return 1;
  192. }
  193. int Q_UChar32ToUTF32Len( uchar32 uVal )
  194. {
  195. return 1;
  196. }
  197. int Q_UChar32ToUTF32( uchar32 uVal, uchar32 *pUTF32 )
  198. {
  199. *pUTF32 = uVal;
  200. return 1;
  201. }
  202. // A generic Unicode processing loop: decode one character from input to uchar32, handle errors, encode uchar32 to output
  203. template < typename SrcType, typename DstType, bool bStopAtNull, int (&DecodeSrc)( const SrcType*, uchar32&, bool& ), int (&EncodeDstLen)( uchar32 ), int (&EncodeDst)( uchar32, DstType* ) >
  204. int Q_UnicodeConvertT( const SrcType *pIn, int nInChars, DstType *pOut, int nOutBytes, EStringConvertErrorPolicy ePolicy )
  205. {
  206. if ( !pIn )
  207. {
  208. // For now, assert and return 0. Once these are cleaned out a bit
  209. // we should remove this return and just leave in the assert...
  210. AssertMsg( pIn, "We shouldn't be passing in NULL!" );
  211. return 0;
  212. }
  213. int nOut = 0;
  214. if ( !pOut )
  215. {
  216. while ( bStopAtNull ? ( *pIn ) : ( nInChars-- > 0 ) )
  217. {
  218. uchar32 uVal;
  219. // Initialize in order to avoid /analyze warnings.
  220. bool bErr = false;
  221. pIn += DecodeSrc( pIn, uVal, bErr );
  222. nOut += EncodeDstLen( uVal );
  223. if ( bErr )
  224. {
  225. #ifdef _DEBUG
  226. AssertMsg( !(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence" );
  227. #endif
  228. if ( ePolicy & _STRINGCONVERTFLAG_SKIP )
  229. {
  230. nOut -= EncodeDstLen( uVal );
  231. }
  232. else if ( ePolicy & _STRINGCONVERTFLAG_FAIL )
  233. {
  234. pOut[0] = 0;
  235. return 0;
  236. }
  237. }
  238. }
  239. }
  240. else
  241. {
  242. int nOutElems = nOutBytes / sizeof( DstType );
  243. if ( nOutElems <= 0 )
  244. return 0;
  245. int nMaxOut = nOutElems - 1;
  246. while ( bStopAtNull ? ( *pIn ) : ( nInChars-- > 0 ) )
  247. {
  248. uchar32 uVal;
  249. // Initialize in order to avoid /analyze warnings.
  250. bool bErr = false;
  251. pIn += DecodeSrc( pIn, uVal, bErr );
  252. if ( nOut + EncodeDstLen( uVal ) > nMaxOut )
  253. break;
  254. nOut += EncodeDst( uVal, pOut + nOut );
  255. if ( bErr )
  256. {
  257. #ifdef _DEBUG
  258. AssertMsg( !(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence" );
  259. #endif
  260. if ( ePolicy & _STRINGCONVERTFLAG_SKIP )
  261. {
  262. nOut -= EncodeDstLen( uVal );
  263. }
  264. else if ( ePolicy & _STRINGCONVERTFLAG_FAIL )
  265. {
  266. pOut[0] = 0;
  267. return 0;
  268. }
  269. }
  270. }
  271. pOut[nOut] = 0;
  272. }
  273. return (nOut + 1) * sizeof( DstType );
  274. }
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Purpose: Returns true if UTF-8 string contains invalid sequences.
  278. //-----------------------------------------------------------------------------
  279. bool Q_UnicodeValidate( const char *pUTF8 )
  280. {
  281. bool bError = false;
  282. while ( *pUTF8 )
  283. {
  284. uchar32 uVal;
  285. // Our UTF-8 decoder silently fixes up 6-byte CESU-8 (improperly re-encoded UTF-16) sequences.
  286. // However, these are technically not valid UTF-8. So if we eat 6 bytes at once, it's an error.
  287. int nCharSize = Q_UTF8ToUChar32( pUTF8, uVal, bError );
  288. if ( bError || nCharSize == 6 )
  289. return false;
  290. pUTF8 += nCharSize;
  291. }
  292. return true;
  293. }
  294. //-----------------------------------------------------------------------------
  295. // Purpose: Returns true if UTF-16 string contains invalid sequences.
  296. //-----------------------------------------------------------------------------
  297. bool Q_UnicodeValidate( const uchar16 *pUTF16 )
  298. {
  299. bool bError = false;
  300. while ( *pUTF16 )
  301. {
  302. uchar32 uVal;
  303. pUTF16 += Q_UTF16ToUChar32( pUTF16, uVal, bError );
  304. if ( bError )
  305. return false;
  306. }
  307. return true;
  308. }
  309. //-----------------------------------------------------------------------------
  310. // Purpose: Returns true if UTF-32 string contains invalid sequences.
  311. //-----------------------------------------------------------------------------
  312. bool Q_UnicodeValidate( const uchar32 *pUTF32 )
  313. {
  314. while ( *pUTF32 )
  315. {
  316. if ( !Q_IsValidUChar32( *pUTF32++ ) )
  317. return false;
  318. ++pUTF32;
  319. }
  320. return true;
  321. }
  322. //-----------------------------------------------------------------------------
  323. // Purpose: Returns number of Unicode code points (aka glyphs / characters) encoded in the UTF-8 string
  324. //-----------------------------------------------------------------------------
  325. int Q_UnicodeLength( const char *pUTF8 )
  326. {
  327. int nChars = 0;
  328. while ( *pUTF8 )
  329. {
  330. bool bError;
  331. uchar32 uVal;
  332. pUTF8 += Q_UTF8ToUChar32( pUTF8, uVal, bError );
  333. ++nChars;
  334. }
  335. return nChars;
  336. }
  337. //-----------------------------------------------------------------------------
  338. // Purpose: Returns number of Unicode code points (aka glyphs / characters) encoded in the UTF-16 string
  339. //-----------------------------------------------------------------------------
  340. int Q_UnicodeLength( const uchar16 *pUTF16 )
  341. {
  342. int nChars = 0;
  343. while ( *pUTF16 )
  344. {
  345. bool bError;
  346. uchar32 uVal;
  347. pUTF16 += Q_UTF16ToUChar32( pUTF16, uVal, bError );
  348. ++nChars;
  349. }
  350. return nChars;
  351. }
  352. //-----------------------------------------------------------------------------
  353. // Purpose: Returns number of Unicode code points (aka glyphs / characters) encoded in the UTF-32 string
  354. //-----------------------------------------------------------------------------
  355. int Q_UnicodeLength( const uchar32 *pUTF32 )
  356. {
  357. int nChars = 0;
  358. while ( *pUTF32++ )
  359. ++nChars;
  360. return nChars;
  361. }
  362. //-----------------------------------------------------------------------------
  363. // Purpose: Advance a UTF-8 string pointer by a certain number of Unicode code points, stopping at end of string
  364. //-----------------------------------------------------------------------------
  365. char *Q_UnicodeAdvance( char *pUTF8, int nChars )
  366. {
  367. while ( nChars > 0 && *pUTF8 )
  368. {
  369. uchar32 uVal;
  370. bool bError;
  371. pUTF8 += Q_UTF8ToUChar32( pUTF8, uVal, bError );
  372. --nChars;
  373. }
  374. return pUTF8;
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Purpose: Advance a UTF-16 string pointer by a certain number of Unicode code points, stopping at end of string
  378. //-----------------------------------------------------------------------------
  379. uchar16 *Q_UnicodeAdvance( uchar16 *pUTF16, int nChars )
  380. {
  381. while ( nChars > 0 && *pUTF16 )
  382. {
  383. uchar32 uVal;
  384. bool bError;
  385. pUTF16 += Q_UTF16ToUChar32( pUTF16, uVal, bError );
  386. --nChars;
  387. }
  388. return pUTF16;
  389. }
  390. //-----------------------------------------------------------------------------
  391. // Purpose: Advance a UTF-32 string pointer by a certain number of Unicode code points, stopping at end of string
  392. //-----------------------------------------------------------------------------
  393. uchar32 *Q_UnicodeAdvance( uchar32 *pUTF32, int nChars )
  394. {
  395. while ( nChars > 0 && *pUTF32 )
  396. {
  397. ++pUTF32;
  398. --nChars;
  399. }
  400. return pUTF32;
  401. }
  402. //-----------------------------------------------------------------------------
  403. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  404. //-----------------------------------------------------------------------------
  405. int Q_UTF8ToUTF16( const char *pUTF8, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  406. {
  407. return Q_UnicodeConvertT< char, uchar16, true, Q_UTF8ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF8, 0, pUTF16, cubDestSizeInBytes, ePolicy );
  408. }
  409. //-----------------------------------------------------------------------------
  410. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  411. //-----------------------------------------------------------------------------
  412. int Q_UTF8ToUTF32( const char *pUTF8, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  413. {
  414. return Q_UnicodeConvertT< char, uchar32, true, Q_UTF8ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF8, 0, pUTF32, cubDestSizeInBytes, ePolicy );
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  418. //-----------------------------------------------------------------------------
  419. int Q_UTF16ToUTF8( const uchar16 *pUTF16, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  420. {
  421. return Q_UnicodeConvertT< uchar16, char, true, Q_UTF16ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF16, 0, pUTF8, cubDestSizeInBytes, ePolicy );
  422. }
  423. //-----------------------------------------------------------------------------
  424. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  425. //-----------------------------------------------------------------------------
  426. int Q_UTF16ToUTF32( const uchar16 *pUTF16, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  427. {
  428. return Q_UnicodeConvertT< uchar16, uchar32, true, Q_UTF16ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF16, 0, pUTF32, cubDestSizeInBytes, ePolicy );
  429. }
  430. //-----------------------------------------------------------------------------
  431. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  432. //-----------------------------------------------------------------------------
  433. int Q_UTF32ToUTF8( const uchar32 *pUTF32, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  434. {
  435. return Q_UnicodeConvertT< uchar32, char, true, Q_UTF32ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF32, 0, pUTF8, cubDestSizeInBytes, ePolicy );
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  439. //-----------------------------------------------------------------------------
  440. int Q_UTF32ToUTF16( const uchar32 *pUTF32, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  441. {
  442. return Q_UnicodeConvertT< uchar32, uchar16, true, Q_UTF32ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF32, 0, pUTF16, cubDestSizeInBytes, ePolicy );
  443. }
  444. //-----------------------------------------------------------------------------
  445. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  446. //-----------------------------------------------------------------------------
  447. int Q_UTF32ToUTF32( const uchar32 *pUTF32Source, uchar32 *pUTF32Dest, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  448. {
  449. return Q_UnicodeConvertT< uchar32, uchar32, true, Q_UTF32ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF32Source, 0, pUTF32Dest, cubDestSizeInBytes, ePolicy );
  450. }
  451. //-----------------------------------------------------------------------------
  452. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  453. //-----------------------------------------------------------------------------
  454. int Q_UTF8CharsToUTF16( const char *pUTF8, int nElements, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  455. {
  456. return Q_UnicodeConvertT< char, uchar16, false, Q_UTF8ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF8, nElements, pUTF16, cubDestSizeInBytes, ePolicy );
  457. }
  458. //-----------------------------------------------------------------------------
  459. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  460. //-----------------------------------------------------------------------------
  461. int Q_UTF8CharsToUTF32( const char *pUTF8, int nElements, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  462. {
  463. return Q_UnicodeConvertT< char, uchar32, false, Q_UTF8ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF8, nElements, pUTF32, cubDestSizeInBytes, ePolicy );
  464. }
  465. //-----------------------------------------------------------------------------
  466. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  467. //-----------------------------------------------------------------------------
  468. int Q_UTF16CharsToUTF8( const uchar16 *pUTF16, int nElements, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  469. {
  470. return Q_UnicodeConvertT< uchar16, char, false, Q_UTF16ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF16, nElements, pUTF8, cubDestSizeInBytes, ePolicy );
  471. }
  472. //-----------------------------------------------------------------------------
  473. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  474. //-----------------------------------------------------------------------------
  475. int Q_UTF16CharsToUTF32( const uchar16 *pUTF16, int nElements, uchar32 *pUTF32, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  476. {
  477. return Q_UnicodeConvertT< uchar16, uchar32, false, Q_UTF16ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF16, nElements, pUTF32, cubDestSizeInBytes, ePolicy );
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  481. //-----------------------------------------------------------------------------
  482. int Q_UTF32CharsToUTF8( const uchar32 *pUTF32, int nElements, char *pUTF8, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  483. {
  484. return Q_UnicodeConvertT< uchar32, char, false, Q_UTF32ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF32, nElements, pUTF8, cubDestSizeInBytes, ePolicy );
  485. }
  486. //-----------------------------------------------------------------------------
  487. // Purpose: Perform conversion. Returns number of *bytes* required if output pointer is NULL.
  488. //-----------------------------------------------------------------------------
  489. int Q_UTF32CharsToUTF16( const uchar32 *pUTF32, int nElements, uchar16 *pUTF16, int cubDestSizeInBytes, EStringConvertErrorPolicy ePolicy )
  490. {
  491. return Q_UnicodeConvertT< uchar32, uchar16, false, Q_UTF32ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF32, nElements, pUTF16, cubDestSizeInBytes, ePolicy );
  492. }
  493. //-----------------------------------------------------------------------------
  494. // Purpose: Repair a UTF-8 string by removing or replacing invalid seqeuences. Returns non-zero on success.
  495. //-----------------------------------------------------------------------------
  496. int Q_UnicodeRepair( char *pUTF8, EStringConvertErrorPolicy ePolicy )
  497. {
  498. return Q_UnicodeConvertT< char, char, true, Q_UTF8ToUChar32, Q_UChar32ToUTF8Len, Q_UChar32ToUTF8 >( pUTF8, 0, pUTF8, INT_MAX, ePolicy );
  499. }
  500. //-----------------------------------------------------------------------------
  501. // Purpose: Repair a UTF-16 string by removing or replacing invalid seqeuences. Returns non-zero on success.
  502. //-----------------------------------------------------------------------------
  503. int Q_UnicodeRepair( uchar16 *pUTF16, EStringConvertErrorPolicy ePolicy )
  504. {
  505. return Q_UnicodeConvertT< uchar16, uchar16, true, Q_UTF16ToUChar32, Q_UChar32ToUTF16Len, Q_UChar32ToUTF16 >( pUTF16, 0, pUTF16, INT_MAX/sizeof(uchar16), ePolicy );
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Purpose: Repair a UTF-32 string by removing or replacing invalid seqeuences. Returns non-zero on success.
  509. //-----------------------------------------------------------------------------
  510. int Q_UnicodeRepair( uchar32 *pUTF32, EStringConvertErrorPolicy ePolicy )
  511. {
  512. return Q_UnicodeConvertT< uchar32, uchar32, true, Q_UTF32ToUChar32, Q_UChar32ToUTF32Len, Q_UChar32ToUTF32 >( pUTF32, 0, pUTF32, INT_MAX/sizeof(uchar32), ePolicy );
  513. }