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.

260 lines
7.9 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. #if defined( WIN32 ) && !defined( _X360 )
  3. #include <windows.h>
  4. #elif defined( POSIX )
  5. #include <iconv.h>
  6. #endif
  7. #include "tier1/ilocalize.h"
  8. #include "utlstring.h"
  9. #pragma warning( disable: 4018 ) // '<' : signed/unsigned mismatch
  10. //-----------------------------------------------------------------------------
  11. // Purpose: converts an english string to unicode
  12. //-----------------------------------------------------------------------------
  13. int ILocalize::ConvertANSIToUnicode(const char *ansi, wchar_t *unicode, int unicodeBufferSizeInBytes)
  14. {
  15. #ifdef POSIX
  16. // Q_UTF8ToUnicode returns the number of bytes. This function is expected to return the number of chars.
  17. return Q_UTF8ToUnicode(ansi, unicode, unicodeBufferSizeInBytes) / sizeof( wchar_t );
  18. #else
  19. int chars = MultiByteToWideChar(CP_UTF8, 0, ansi, -1, unicode, unicodeBufferSizeInBytes / sizeof(wchar_t));
  20. unicode[(unicodeBufferSizeInBytes / sizeof(wchar_t)) - 1] = 0;
  21. return chars;
  22. #endif
  23. }
  24. //-----------------------------------------------------------------------------
  25. // Purpose: converts an unicode string to an english string
  26. //-----------------------------------------------------------------------------
  27. int ILocalize::ConvertUnicodeToANSI(const wchar_t *unicode, char *ansi, int ansiBufferSize)
  28. {
  29. #ifdef POSIX
  30. return Q_UnicodeToUTF8(unicode, ansi, ansiBufferSize);
  31. #else
  32. int result = WideCharToMultiByte(CP_UTF8, 0, unicode, -1, ansi, ansiBufferSize, NULL, NULL);
  33. ansi[ansiBufferSize - 1] = 0;
  34. return result;
  35. #endif
  36. }
  37. //-----------------------------------------------------------------------------
  38. // Purpose: construct string helper
  39. //-----------------------------------------------------------------------------
  40. template < typename T >
  41. void ConstructStringVArgsInternal_Impl(T *unicodeOutput, int unicodeBufferSizeInBytes, const T *formatString, int numFormatParameters, va_list argList)
  42. {
  43. static const int k_cMaxFormatStringArguments = 9; // We only look one character ahead and start at %s1
  44. Assert( numFormatParameters <= k_cMaxFormatStringArguments );
  45. // Safety check
  46. if ( unicodeOutput == NULL || unicodeBufferSizeInBytes < 1 )
  47. {
  48. return;
  49. }
  50. if ( !formatString || numFormatParameters > k_cMaxFormatStringArguments )
  51. {
  52. unicodeOutput[0] = 0;
  53. return;
  54. }
  55. int unicodeBufferSize = unicodeBufferSizeInBytes / sizeof(T);
  56. const T *searchPos = formatString;
  57. T *outputPos = unicodeOutput;
  58. T *argParams[k_cMaxFormatStringArguments];
  59. for ( int i = 0; i < numFormatParameters; i++ )
  60. {
  61. argParams[i] = va_arg( argList, T* );
  62. }
  63. //assumes we can't have %s10
  64. //assume both are 0 terminated?
  65. int formatLength = StringFuncs<T>::Length( formatString );
  66. while ( searchPos[0] != '\0' && unicodeBufferSize > 1 )
  67. {
  68. if ( formatLength >= 3 && searchPos[0] == '%' && searchPos[1] == 's' )
  69. {
  70. //this is an escape sequence - %s1, %s2 etc, up to %s9
  71. int argindex = ( searchPos[2] ) - '0' - 1; // 0 for %s1, 1 for %s2, etc.
  72. if ( argindex < 0 || argindex > k_cMaxFormatStringArguments )
  73. {
  74. Warning( "Bad format string in CLocalizeStringTable::ConstructString\n" );
  75. *outputPos = '\0';
  76. return;
  77. }
  78. if ( argindex < numFormatParameters )
  79. {
  80. T const *param = argParams[argindex];
  81. if ( param == NULL )
  82. param = StringFuncs<T>::NullDebugString();
  83. int paramSize = StringFuncs<T>::Length(param);
  84. if (paramSize >= unicodeBufferSize)
  85. {
  86. paramSize = unicodeBufferSize - 1;
  87. }
  88. memcpy(outputPos, param, paramSize * sizeof(T));
  89. unicodeBufferSize -= paramSize;
  90. outputPos += paramSize;
  91. searchPos += 3;
  92. formatLength -= 3;
  93. }
  94. else
  95. {
  96. AssertMsg( argindex < numFormatParameters, "ConstructStringVArgsInternal_Impl() - Found a %%s# escape sequence whose index was more than the number of args." );
  97. //copy it over, char by char
  98. *outputPos = *searchPos;
  99. outputPos++;
  100. unicodeBufferSize--;
  101. searchPos++;
  102. formatLength--;
  103. }
  104. }
  105. else
  106. {
  107. //copy it over, char by char
  108. *outputPos = *searchPos;
  109. outputPos++;
  110. unicodeBufferSize--;
  111. searchPos++;
  112. formatLength--;
  113. }
  114. }
  115. // ensure null termination
  116. Assert( outputPos - unicodeOutput < unicodeBufferSizeInBytes/sizeof(T) );
  117. *outputPos = L'\0';
  118. }
  119. void ILocalize::ConstructStringVArgsInternal(char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, int numFormatParameters, va_list argList)
  120. {
  121. ConstructStringVArgsInternal_Impl<char>( unicodeOutput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList );
  122. }
  123. void ILocalize::ConstructStringVArgsInternal(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, int numFormatParameters, va_list argList)
  124. {
  125. ConstructStringVArgsInternal_Impl<wchar_t>( unicodeOutput, unicodeBufferSizeInBytes, formatString, numFormatParameters, argList );
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Purpose: construct string helper
  129. //-----------------------------------------------------------------------------
  130. template < typename T >
  131. const T *GetTypedKeyValuesString( KeyValues *pKeyValues, const char *pKeyName );
  132. template < >
  133. const char *GetTypedKeyValuesString<char>( KeyValues *pKeyValues, const char *pKeyName )
  134. {
  135. return pKeyValues->GetString( pKeyName, "[unknown]" );
  136. }
  137. template < >
  138. const wchar_t *GetTypedKeyValuesString<wchar_t>( KeyValues *pKeyValues, const char *pKeyName )
  139. {
  140. return pKeyValues->GetWString( pKeyName, L"[unknown]" );
  141. }
  142. template < typename T >
  143. void ConstructStringKeyValuesInternal_Impl( T *unicodeOutput, int unicodeBufferSizeInBytes, const T *formatString, KeyValues *localizationVariables )
  144. {
  145. T *outputPos = unicodeOutput;
  146. //assumes we can't have %s10
  147. //assume both are 0 terminated?
  148. int unicodeBufferSize = unicodeBufferSizeInBytes / sizeof(T);
  149. while ( *formatString != '\0' && unicodeBufferSize > 1 )
  150. {
  151. bool shouldAdvance = true;
  152. if ( *formatString == '%' )
  153. {
  154. // this is an escape sequence that specifies a variable name
  155. if ( formatString[1] == 's' && formatString[2] >= '0' && formatString[2] <= '9' )
  156. {
  157. // old style escape sequence, ignore
  158. }
  159. else if ( formatString[1] == '%' )
  160. {
  161. // just a '%' char, just write the second one
  162. formatString++;
  163. }
  164. else if ( localizationVariables )
  165. {
  166. // get out the variable name
  167. const T *varStart = formatString + 1;
  168. const T *varEnd = StringFuncs<T>::FindChar( varStart, '%' );
  169. if ( varEnd && *varEnd == '%' )
  170. {
  171. shouldAdvance = false;
  172. // assume variable names must be ascii, do a quick convert
  173. char variableName[32];
  174. char *vset = variableName;
  175. for ( const T *pws = varStart; pws < varEnd && (vset < variableName + sizeof(variableName) - 1); ++pws, ++vset )
  176. {
  177. *vset = (char)*pws;
  178. }
  179. *vset = 0;
  180. // look up the variable name
  181. const T *value = GetTypedKeyValuesString<T>( localizationVariables, variableName );
  182. int paramSize = StringFuncs<T>::Length( value );
  183. if (paramSize >= unicodeBufferSize)
  184. {
  185. paramSize = MAX( 0, unicodeBufferSize - 1 );
  186. }
  187. StringFuncs<T>::Copy( outputPos, value, paramSize );
  188. unicodeBufferSize -= paramSize;
  189. outputPos += paramSize;
  190. formatString = varEnd + 1;
  191. }
  192. }
  193. }
  194. if (shouldAdvance)
  195. {
  196. //copy it over, char by char
  197. *outputPos = *formatString;
  198. outputPos++;
  199. unicodeBufferSize--;
  200. formatString++;
  201. }
  202. }
  203. // ensure null termination
  204. *outputPos = '\0';
  205. }
  206. void ILocalize::ConstructStringKeyValuesInternal(char *unicodeOutput, int unicodeBufferSizeInBytes, const char *formatString, KeyValues *localizationVariables)
  207. {
  208. ConstructStringKeyValuesInternal_Impl<char>( unicodeOutput, unicodeBufferSizeInBytes, formatString, localizationVariables );
  209. }
  210. void ILocalize::ConstructStringKeyValuesInternal(wchar_t *unicodeOutput, int unicodeBufferSizeInBytes, const wchar_t *formatString, KeyValues *localizationVariables)
  211. {
  212. ConstructStringKeyValuesInternal_Impl<wchar_t>( unicodeOutput, unicodeBufferSizeInBytes, formatString, localizationVariables );
  213. }