Source code of Windows XP (NT5)
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.

320 lines
12 KiB

  1. /***
  2. *w_map.c - W version of LCMapString.
  3. *
  4. * Copyright (c) 1993-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Use either LCMapStringA or LCMapStringW depending on which is available
  8. *
  9. *Revision History:
  10. * 09-14-93 CFW Module created.
  11. * 09-17-93 CFW Use unsigned chars.
  12. * 09-23-93 CFW Correct NLS API params and comments about same.
  13. * 10-07-93 CFW Optimize WideCharToMultiByte, use NULL default char.
  14. * 10-22-93 CFW Test for invalid MB chars using global preset flag.
  15. * 11-09-93 CFW Allow user to pass in code page.
  16. * 11-18-93 CFW Test for entry point function stubs.
  17. * 02-23-94 CFW Use W flavor whenever possible.
  18. * 03-31-94 CFW Include awint.h.
  19. * 07-26-94 CFW Bug fix #14730, LCMapString goes past NULLs.
  20. * 12-21-94 CFW Remove invalid MB chars NT 3.1 hack.
  21. * 12-27-94 CFW Call direct, all OS's have stubs.
  22. * 01-10-95 CFW Debug CRT allocs.
  23. * 02-15-97 RDK For narrow mapping, try W version first so Windows NT
  24. * can process nonANSI codepage correctly.
  25. * 03-16-97 RDK Added error flag to __crtLCMapStringA.
  26. * 05-09-97 GJF Split off from aw_map.c. Revised to use _alloca
  27. * instead of malloc. Also, reformatted.
  28. * 05-27-98 GJF Changed wcsncnt() so that it will never examine the
  29. * (cnt + 1)-th byte of the string.
  30. * 08-18-98 GJF Use _malloc_crt if _alloca fails.
  31. * 04-28-99 GJF Changed dwFlags arg value to 0 in WideCharToMultiByte
  32. * calls to avoid problems with codepage 1258 on NT 5.0.
  33. * 12-10-99 GB Added support for recovery from stack overflow around
  34. * _alloca().
  35. * 05-17-00 GB Use ERROR_CALL_NOT_IMPLEMENTED for existance of W API
  36. * 08-23-00 GB Fixed bug with non Ansi CP on Win9x.
  37. *
  38. *******************************************************************************/
  39. #include <cruntime.h>
  40. #include <internal.h>
  41. #include <stdlib.h>
  42. #include <setlocal.h>
  43. #include <locale.h>
  44. #include <awint.h>
  45. #include <dbgint.h>
  46. #include <malloc.h>
  47. #define USE_W 1
  48. #define USE_A 2
  49. /***
  50. *int __cdecl wcsncnt - count wide characters in a string, up to n.
  51. *
  52. *Purpose:
  53. * Internal local support function. Counts characters in string before
  54. * null. If null not found in n chars, then return n.
  55. *
  56. *Entry:
  57. * const wchar_t *string - start of string
  58. * int n - byte count
  59. *
  60. *Exit:
  61. * returns number of wide characaters from start of string to
  62. * null (exclusive), up to n.
  63. *
  64. *Exceptions:
  65. *
  66. *******************************************************************************/
  67. static int __cdecl wcsncnt (
  68. const wchar_t *string,
  69. int cnt
  70. )
  71. {
  72. int n = cnt;
  73. wchar_t *cp = (wchar_t *)string;
  74. while (n-- && *cp)
  75. cp++;
  76. return cnt - n - 1;
  77. }
  78. /***
  79. *int __cdecl __crtLCMapStringW - Get type information about a wide string.
  80. *
  81. *Purpose:
  82. * Internal support function. Assumes info in wide string format. Tries
  83. * to use NLS API call LCMapStringW if available and uses LCMapStringA
  84. * if it must. If neither are available it fails and returns 0.
  85. *
  86. *Entry:
  87. * LCID Locale - locale context for the comparison.
  88. * DWORD dwMapFlags - see NT\Chicago docs
  89. * LPCWSTR lpSrcStr - pointer to string to be mapped
  90. * int cchSrc - wide char (word) count of input string
  91. * (including NULL if any)
  92. * (-1 if NULL terminated)
  93. * LPWSTR lpDestStr - pointer to memory to store mapping
  94. * int cchDest - wide char (word) count of buffer (including NULL)
  95. * int code_page - for MB/WC conversion. If 0, use __lc_codepage
  96. *
  97. * NOTE: if LCMAP_SORTKEY is specified, then cchDest refers to number
  98. * of BYTES, not number of wide chars. The return string will be
  99. * a series of bytes with a NULL byte terminator.
  100. *
  101. *Exit:
  102. * Success: if LCMAP_SORKEY:
  103. * number of bytes written to lpDestStr (including NULL byte
  104. * terminator)
  105. * else
  106. * number of wide characters written to lpDestStr (including
  107. * NULL)
  108. * Failure: 0
  109. *
  110. *Exceptions:
  111. *
  112. *******************************************************************************/
  113. int __cdecl __crtLCMapStringW(
  114. LCID Locale,
  115. DWORD dwMapFlags,
  116. LPCWSTR lpSrcStr,
  117. int cchSrc,
  118. LPWSTR lpDestStr,
  119. int cchDest,
  120. int code_page
  121. )
  122. {
  123. static int f_use = 0;
  124. /*
  125. * Look for unstubbed 'preferred' flavor. Otherwise use available flavor.
  126. * Must actually call the function to ensure it's not a stub.
  127. */
  128. if (0 == f_use) {
  129. if (0 != LCMapStringW(0, LCMAP_LOWERCASE, L"\0", 1, NULL, 0))
  130. f_use = USE_W;
  131. else if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  132. f_use = USE_A;
  133. }
  134. /*
  135. * LCMapString will map past NULL. Must find NULL if in string
  136. * before cchSrc wide characters.
  137. */
  138. if (cchSrc > 0)
  139. cchSrc = wcsncnt(lpSrcStr, cchSrc);
  140. /* Use "W" version */
  141. if (USE_W == f_use) {
  142. return LCMapStringW( Locale, dwMapFlags, lpSrcStr, cchSrc,
  143. lpDestStr, cchDest );
  144. }
  145. /* Use "A" version */
  146. if (USE_A == f_use || f_use == 0) {
  147. int retval = 0;
  148. int inbuff_size;
  149. int outbuff_size;
  150. unsigned char *inbuffer;
  151. unsigned char *outbuffer;
  152. int malloc_flag1 = 0;
  153. int malloc_flag2 = 0;
  154. int AnsiCP = 0;
  155. /*
  156. * Convert string and return the requested information. Note that
  157. * we are converting to a multibyte string so there is not a
  158. * one-to-one correspondence between number of wide chars in the
  159. * input string and the number of *bytes* in the buffer. However,
  160. * there had *better be* a one-to-one correspondence between the
  161. * number of wide characters and the number of multibyte characters
  162. * (enforced by WC_SEPCHARS) in the buffer or the resulting mapped
  163. * string will be worthless to the user.
  164. *
  165. */
  166. /*
  167. * Use __lc_codepage for conversion if code_page not specified
  168. */
  169. if (0 == Locale)
  170. Locale = __lc_handle[LC_CTYPE];
  171. if (0 == code_page)
  172. code_page = __lc_codepage;
  173. /*
  174. * Always use Ansi codepage with Ansi WinAPI because they use
  175. * Ansi codepage
  176. */
  177. if ( code_page != (AnsiCP = __ansicp(Locale)))
  178. {
  179. if (AnsiCP != -1)
  180. code_page = AnsiCP;
  181. }
  182. /* find out how big a buffer we need (includes NULL if any) */
  183. if ( 0 == (inbuff_size = WideCharToMultiByte( code_page,
  184. 0,
  185. lpSrcStr,
  186. cchSrc,
  187. NULL,
  188. 0,
  189. NULL,
  190. NULL )) )
  191. return 0;
  192. /* allocate enough space for chars */
  193. __try {
  194. inbuffer = (unsigned char *)_alloca( inbuff_size * sizeof(char) );
  195. }
  196. __except(EXCEPTION_EXECUTE_HANDLER) {
  197. _resetstkoflw();
  198. inbuffer = NULL;
  199. }
  200. if ( inbuffer == NULL ) {
  201. if ( (inbuffer = (unsigned char *)_malloc_crt(inbuff_size * sizeof(char)))
  202. == NULL )
  203. return 0;
  204. malloc_flag1++;
  205. }
  206. /* do the conversion */
  207. if ( 0 == WideCharToMultiByte( code_page,
  208. 0,
  209. lpSrcStr,
  210. cchSrc,
  211. inbuffer,
  212. inbuff_size,
  213. NULL,
  214. NULL ) )
  215. goto error_cleanup;
  216. /* get size required for string mapping */
  217. if ( 0 == (outbuff_size = LCMapStringA( Locale,
  218. dwMapFlags,
  219. inbuffer,
  220. inbuff_size,
  221. NULL,
  222. 0 )) )
  223. goto error_cleanup;
  224. /* allocate enough space for chars and NULL */
  225. __try {
  226. outbuffer = (unsigned char *)_alloca( outbuff_size * sizeof(char) );
  227. }
  228. __except(EXCEPTION_EXECUTE_HANDLER) {
  229. _resetstkoflw();
  230. outbuffer = NULL;
  231. }
  232. if ( outbuffer == NULL ) {
  233. if ( (outbuffer = (unsigned char *)_malloc_crt(outbuff_size * sizeof(char)))
  234. == NULL )
  235. goto error_cleanup;
  236. malloc_flag2++;
  237. }
  238. /* do string mapping */
  239. if ( 0 == LCMapStringA( Locale,
  240. dwMapFlags,
  241. inbuffer,
  242. inbuff_size,
  243. outbuffer,
  244. outbuff_size ) )
  245. goto error_cleanup;
  246. if (dwMapFlags & LCMAP_SORTKEY) {
  247. /* outbuff_size > cchDest is allowed */
  248. retval = outbuff_size;
  249. if (0 != cchDest)
  250. /* SORTKEY returns BYTES, just copy */
  251. strncpy( (char *)lpDestStr,
  252. (char *)outbuffer,
  253. cchDest < outbuff_size ? cchDest : outbuff_size );
  254. }
  255. else {
  256. if (0 == cchDest) {
  257. /* get size required */
  258. if ( 0 == (retval = MultiByteToWideChar( code_page,
  259. MB_PRECOMPOSED,
  260. outbuffer,
  261. outbuff_size,
  262. NULL,
  263. 0 )) )
  264. goto error_cleanup;
  265. }
  266. else {
  267. /* convert mapping */
  268. if ( 0 == (retval = MultiByteToWideChar( code_page,
  269. MB_PRECOMPOSED,
  270. outbuffer,
  271. outbuff_size,
  272. lpDestStr,
  273. cchDest )) )
  274. goto error_cleanup;
  275. }
  276. }
  277. error_cleanup:
  278. if ( malloc_flag2 )
  279. _free_crt(outbuffer);
  280. if ( malloc_flag1 )
  281. _free_crt(inbuffer);
  282. return retval;
  283. }
  284. else /* f_use is neither USE_A nor USE_W */
  285. return 0;
  286. }