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.

399 lines
15 KiB

  1. /***
  2. *a_map.c - A 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 Renamed and moved __crtLCMapStringW into a separate
  27. * file. Revised to use _alloca instead of malloc. Also,
  28. * reformatted.
  29. * 05-27-98 GJF Changed strncnt() so that it will never examine the
  30. * (cnt + 1)-th byte of the string.
  31. * 08-18-98 GJF Use _malloc_crt if _alloca fails.
  32. * 04-28-99 GJF Changed dwFlags arg value to 0 in WideCharToMultiByte
  33. * calls to avoid problems with codepage 1258 on NT 5.0.
  34. * 12-10-99 GB Added support for recovery from stack overflow around
  35. * _alloca().
  36. * 05-17-00 GB Use ERROR_CALL_NOT_IMPLEMENTED for existance of W API
  37. * 08-23-00 GB Fixed bug with non Ansi CP on Win9x.
  38. * 07-07-01 BWT Fix error path (set ret=FALSE before branching, not after)
  39. *
  40. *******************************************************************************/
  41. #include <cruntime.h>
  42. #include <internal.h>
  43. #include <stdlib.h>
  44. #include <setlocal.h>
  45. #include <locale.h>
  46. #include <awint.h>
  47. #include <dbgint.h>
  48. #include <malloc.h>
  49. #define USE_W 1
  50. #define USE_A 2
  51. /***
  52. *int __cdecl strncnt - count characters in a string, up to n.
  53. *
  54. *Purpose:
  55. * Internal local support function. Counts characters in string before
  56. * null. If null is not found in n chars, then return n.
  57. *
  58. *Entry:
  59. * const char *string - start of string
  60. * int n - byte count
  61. *
  62. *Exit:
  63. * returns number of bytes from start of string to
  64. * null (exclusive), up to n.
  65. *
  66. *Exceptions:
  67. *
  68. *******************************************************************************/
  69. static int __cdecl strncnt (
  70. const char *string,
  71. int cnt
  72. )
  73. {
  74. int n = cnt;
  75. char *cp = (char *)string;
  76. while (n-- && *cp)
  77. cp++;
  78. return cnt - n - 1;
  79. }
  80. /***
  81. *int __cdecl __crtLCMapStringA - Get type information about an ANSI string.
  82. *
  83. *Purpose:
  84. * Internal support function. Assumes info in ANSI string format. Tries
  85. * to use NLS API call LCMapStringA if available and uses LCMapStringW
  86. * if it must. If neither are available it fails and returns 0.
  87. *
  88. *Entry:
  89. * LCID Locale - locale context for the comparison.
  90. * DWORD dwMapFlags - see NT\Chicago docs
  91. * LPCSTR lpSrcStr - pointer to string to be mapped
  92. * int cchSrc - wide char (word) count of input string
  93. * (including NULL if any)
  94. * (-1 if NULL terminated)
  95. * LPSTR lpDestStr - pointer to memory to store mapping
  96. * int cchDest - char (byte) count of buffer (including NULL)
  97. * int code_page - for MB/WC conversion. If 0, use __lc_codepage
  98. * BOOL bError - TRUE if MB_ERR_INVALID_CHARS set on call to
  99. * MultiByteToWideChar when GetStringTypeW used.
  100. *
  101. *Exit:
  102. * Success: number of chars written to lpDestStr (including NULL)
  103. * Failure: 0
  104. *
  105. *Exceptions:
  106. *
  107. *******************************************************************************/
  108. int __cdecl __crtLCMapStringA(
  109. LCID Locale,
  110. DWORD dwMapFlags,
  111. LPCSTR lpSrcStr,
  112. int cchSrc,
  113. LPSTR lpDestStr,
  114. int cchDest,
  115. int code_page,
  116. BOOL bError
  117. )
  118. {
  119. static int f_use = 0;
  120. /*
  121. * Look for unstubbed 'preferred' flavor. Otherwise use available flavor.
  122. * Must actually call the function to ensure it's not a stub.
  123. * (Always try wide version first so WinNT can process codepage correctly.)
  124. */
  125. if (0 == f_use) {
  126. if (0 != LCMapStringW(0, LCMAP_LOWERCASE, L"\0", 1, NULL, 0))
  127. f_use = USE_W;
  128. else if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  129. f_use = USE_A;
  130. }
  131. /*
  132. * LCMapString will map past NULL. Must find NULL if in string
  133. * before cchSrc characters.
  134. */
  135. if (cchSrc > 0)
  136. cchSrc = strncnt(lpSrcStr, cchSrc);
  137. /* Use "A" version */
  138. if (USE_A == f_use || f_use == 0) {
  139. char *cbuffer = NULL;
  140. char *cbuffer1 = NULL;
  141. int ret;
  142. int malloc_flag1 = 0;
  143. int AnsiCP;
  144. int buff_size;
  145. if (0 == Locale)
  146. Locale = __lc_handle[LC_CTYPE];
  147. if (0 == code_page)
  148. code_page = __lc_codepage;
  149. if ( -1 == (AnsiCP = __ansicp(Locale)))
  150. return FALSE;
  151. /* LCMapStringA uses ANSI code page to map the string. Check if
  152. * codepage is ansi, if not convert the input string to ansi
  153. * codepage then map to a temporary string and then convert temp
  154. * string to DestStr.
  155. */
  156. if ( AnsiCP != code_page)
  157. {
  158. cbuffer = __convertcp(code_page, AnsiCP, lpSrcStr, &cchSrc, NULL, 0);
  159. if (cbuffer == NULL)
  160. return FALSE;
  161. lpSrcStr = cbuffer;
  162. if (0 == (buff_size = LCMapStringA( Locale,
  163. dwMapFlags,
  164. lpSrcStr,
  165. cchSrc,
  166. 0,
  167. 0 )))
  168. {
  169. ret = FALSE;
  170. goto cleanupA;
  171. }
  172. __try{
  173. cbuffer1 = (char *)_alloca(sizeof(char) * buff_size);
  174. memset(cbuffer1, 0, sizeof(char) * buff_size);
  175. } __except (EXCEPTION_EXECUTE_HANDLER) {
  176. _resetstkoflw();
  177. cbuffer1 = NULL;
  178. }
  179. if ( cbuffer1 == NULL ) {
  180. if ( (cbuffer1 = (char *)_malloc_crt(sizeof(char) * buff_size)) == NULL)
  181. {
  182. ret = FALSE;
  183. goto cleanupA;
  184. }
  185. (void)memset( cbuffer1, 0, sizeof(char) * buff_size);
  186. malloc_flag1++;
  187. }
  188. if (0 == (buff_size = LCMapStringA( Locale,
  189. dwMapFlags,
  190. lpSrcStr,
  191. cchSrc,
  192. cbuffer1,
  193. buff_size)))
  194. {
  195. ret = FALSE;
  196. } else {
  197. if ( NULL == __convertcp(AnsiCP,
  198. code_page,
  199. cbuffer1,
  200. &buff_size,
  201. lpDestStr,
  202. cchDest))
  203. ret = FALSE;
  204. else
  205. ret = TRUE;
  206. }
  207. cleanupA:
  208. if(malloc_flag1)
  209. _free_crt(cbuffer1);
  210. } else
  211. {
  212. ret = LCMapStringA( Locale, dwMapFlags, lpSrcStr, cchSrc,
  213. lpDestStr, cchDest );
  214. }
  215. if ( cbuffer != NULL)
  216. _free_crt(cbuffer);
  217. return ret;
  218. }
  219. /* Use "W" version */
  220. if (USE_W == f_use)
  221. {
  222. int retval = 0;
  223. int inbuff_size;
  224. int outbuff_size;
  225. wchar_t *inwbuffer;
  226. wchar_t *outwbuffer;
  227. int malloc_flag1 = 0;
  228. int malloc_flag2 = 0;
  229. /*
  230. * Convert string and return the requested information. Note that
  231. * we are converting to a wide string so there is not a
  232. * one-to-one correspondence between number of wide chars in the
  233. * input string and the number of *bytes* in the buffer. However,
  234. * there had *better be* a one-to-one correspondence between the
  235. * number of wide characters and the number of multibyte characters
  236. * or the resulting mapped string will be worthless to the user.
  237. */
  238. /*
  239. * Use __lc_codepage for conversion if code_page not specified
  240. */
  241. if (0 == code_page)
  242. code_page = __lc_codepage;
  243. /* find out how big a buffer we need (includes NULL if any) */
  244. if ( 0 == (inbuff_size =
  245. MultiByteToWideChar( code_page,
  246. bError ? MB_PRECOMPOSED |
  247. MB_ERR_INVALID_CHARS :
  248. MB_PRECOMPOSED,
  249. lpSrcStr,
  250. cchSrc,
  251. NULL,
  252. 0 )) )
  253. return 0;
  254. /* allocate enough space for wide chars */
  255. __try {
  256. inwbuffer = (wchar_t *)_alloca( inbuff_size * sizeof(wchar_t) );
  257. }
  258. __except(EXCEPTION_EXECUTE_HANDLER) {
  259. _resetstkoflw();
  260. inwbuffer = NULL;
  261. }
  262. if ( inwbuffer == NULL ) {
  263. if ( (inwbuffer = (wchar_t *)_malloc_crt(inbuff_size * sizeof(wchar_t)))
  264. == NULL )
  265. return 0;
  266. malloc_flag1++;
  267. }
  268. /* do the conversion */
  269. if ( 0 == MultiByteToWideChar( code_page,
  270. MB_PRECOMPOSED,
  271. lpSrcStr,
  272. cchSrc,
  273. inwbuffer,
  274. inbuff_size) )
  275. goto error_cleanup;
  276. /* get size required for string mapping */
  277. if ( 0 == (retval = LCMapStringW( Locale,
  278. dwMapFlags,
  279. inwbuffer,
  280. inbuff_size,
  281. NULL,
  282. 0 )) )
  283. goto error_cleanup;
  284. if (dwMapFlags & LCMAP_SORTKEY) {
  285. /* retval is size in BYTES */
  286. if (0 != cchDest) {
  287. if (retval > cchDest)
  288. goto error_cleanup;
  289. /* do string mapping */
  290. if ( 0 == LCMapStringW( Locale,
  291. dwMapFlags,
  292. inwbuffer,
  293. inbuff_size,
  294. (LPWSTR)lpDestStr,
  295. cchDest ) )
  296. goto error_cleanup;
  297. }
  298. }
  299. else {
  300. /* retval is size in wide chars */
  301. outbuff_size = retval;
  302. /* allocate enough space for wide chars (includes NULL if any) */
  303. __try {
  304. outwbuffer = (wchar_t *)_alloca( outbuff_size * sizeof(wchar_t) );
  305. }
  306. __except(EXCEPTION_EXECUTE_HANDLER) {
  307. _resetstkoflw();
  308. outwbuffer = NULL;
  309. }
  310. if ( outwbuffer == NULL ) {
  311. if ( (outwbuffer = (wchar_t *)_malloc_crt(outbuff_size * sizeof(wchar_t)))
  312. == NULL )
  313. goto error_cleanup;
  314. malloc_flag2++;
  315. }
  316. /* do string mapping */
  317. if ( 0 == LCMapStringW( Locale,
  318. dwMapFlags,
  319. inwbuffer,
  320. inbuff_size,
  321. outwbuffer,
  322. outbuff_size ) )
  323. goto error_cleanup;
  324. if (0 == cchDest) {
  325. /* get size required */
  326. if ( 0 == (retval =
  327. WideCharToMultiByte( code_page,
  328. 0,
  329. outwbuffer,
  330. outbuff_size,
  331. NULL,
  332. 0,
  333. NULL,
  334. NULL )) )
  335. goto error_cleanup;
  336. }
  337. else {
  338. /* convert mapping */
  339. if ( 0 == (retval =
  340. WideCharToMultiByte( code_page,
  341. 0,
  342. outwbuffer,
  343. outbuff_size,
  344. lpDestStr,
  345. cchDest,
  346. NULL,
  347. NULL )) )
  348. goto error_cleanup;
  349. }
  350. }
  351. error_cleanup:
  352. if ( malloc_flag2 )
  353. _free_crt(outwbuffer);
  354. if ( malloc_flag1 )
  355. _free_crt(inwbuffer);
  356. return retval;
  357. }
  358. else /* f_use is neither USE_A nor USE_W */
  359. return 0;
  360. }