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.

360 lines
12 KiB

  1. /***
  2. *wcstombs.c - Convert wide char string to multibyte char string.
  3. *
  4. * Copyright (c) 1990-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * Convert a wide char string into the equivalent multibyte char string.
  8. *
  9. *Revision History:
  10. * 08-24-90 KRS Module created.
  11. * 01-14-91 KRS Added _WINSTATIC for Windows DLL. Fix wctomb() call.
  12. * 03-18-91 KRS Fix check for NUL.
  13. * 03-20-91 KRS Ported from 16-bit tree.
  14. * 10-16-91 ETC Locale support under _INTL switch.
  15. * 12-09-91 ETC Updated nlsapi; added multithread.
  16. * 08-20-92 KRS Activated NLSAPI support.
  17. * 08-22-92 SRW Allow INTL definition to be conditional for building ntcrt.lib
  18. * 09-02-92 SRW Get _INTL definition via ..\crt32.def
  19. * 01-06-93 CFW Added (count < n) to outer loop - avoid bad wctomb calls
  20. * 01-07-93 KRS Major code cleanup. Fix error return, comments.
  21. * 04-06-93 SKS Replace _CRTAPI* with _cdecl
  22. * 05-03-93 CFW Return pointer == NULL, return size, plus massive cleanup.
  23. * 06-01-93 CFW Minor optimization and beautify.
  24. * 06-02-93 SRW ignore _INTL if _NTSUBSET_ defined.
  25. * 09-15-93 CFW Use ANSI conformant "__" names.
  26. * 09-28-93 GJF Merged NT SDK and Cuda versions.
  27. * 01-14-94 SRW if _NTSUBSET_ defined call Rtl functions
  28. * 02-07-94 CFW POSIXify.
  29. * 08-03-94 CFW Optimize for SBCS.
  30. * 09-06-94 CFW Remove _INTL switch.
  31. * 11-22-94 CFW WideCharToMultiByte will compare past NULL.
  32. * 01-07-95 CFW Mac merge cleanup.
  33. * 02-06-95 CFW assert -> _ASSERTE.
  34. * 03-13-95 CFW Fix wcsncnt counting.
  35. * 04-19-95 CFW Rearrange & fix non-Win32 version.
  36. * 09-26-95 GJF New locking macro, and scheme, for functions which
  37. * reference the locale.
  38. * 12-07-95 SKS Fix misspelling of _NTSUBSET_ (final _ was missing)
  39. * 04-01-96 BWT POSIX work.
  40. * 06-25-96 GJF Removed DLL_FOR_WIN32S. Replaced defined(_WIN32) with
  41. * !defined(_MAC). Polished the format a bit.
  42. * 02-27-98 RKP Added 64 bit support.
  43. * 06-23-98 GJF Revised multithread support based on threadlocinfo
  44. * struct.
  45. * 08-27-98 GJF Introduced __wcstombs_mt.
  46. * 12-15-98 GJF Changes for 64-bit size_t.
  47. * 04-28-99 GJF Changed dwFlags arg value to 0 in WideCharToMultiByte
  48. * calls to avoid problems with codepage 1258 on NT 5.0.
  49. * 05-17-99 PML Remove all Macintosh support.
  50. *
  51. *******************************************************************************/
  52. #if defined(_NTSUBSET_) || defined(_POSIX_)
  53. #include <nt.h>
  54. #include <ntrtl.h>
  55. #include <nturtl.h>
  56. #endif
  57. #include <cruntime.h>
  58. #include <stdlib.h>
  59. #include <limits.h>
  60. #include <internal.h>
  61. #include <mtdll.h>
  62. #include <dbgint.h>
  63. #include <errno.h>
  64. #include <locale.h>
  65. #include <setlocal.h>
  66. /***
  67. *int __cdecl wcsncnt - count wide characters in a string, up to n.
  68. *
  69. *Purpose:
  70. * Internal local support function. Counts characters in string including NULL.
  71. * If NULL not found in n chars, then return n.
  72. *
  73. *Entry:
  74. * const wchar_t *string - start of string
  75. * size_t n - character count
  76. *
  77. *Exit:
  78. * returns number of wide characters from start of string to
  79. * NULL (inclusive), up to n.
  80. *
  81. *Exceptions:
  82. *
  83. *******************************************************************************/
  84. static size_t __cdecl wcsncnt (
  85. const wchar_t *string,
  86. size_t cnt
  87. )
  88. {
  89. size_t n = cnt+1;
  90. wchar_t *cp = (wchar_t *)string;
  91. while (--n && *cp)
  92. cp++;
  93. if (n && !*cp)
  94. return cp - string + 1;
  95. return cnt;
  96. }
  97. /***
  98. *size_t wcstombs() - Convert wide char string to multibyte char string.
  99. *
  100. *Purpose:
  101. * Convert a wide char string into the equivalent multibyte char string,
  102. * according to the LC_CTYPE category of the current locale.
  103. * [ANSI].
  104. *
  105. * NOTE: Currently, the C libraries support the "C" locale only.
  106. * Non-C locale support now available under _INTL switch.
  107. *Entry:
  108. * char *s = pointer to destination multibyte char string
  109. * const wchar_t *pwc = pointer to source wide character string
  110. * size_t n = maximum number of bytes to store in s
  111. *
  112. *Exit:
  113. * If s != NULL, returns (size_t)-1 (if a wchar cannot be converted)
  114. * Otherwise: Number of bytes modified (<=n), not including
  115. * the terminating NUL, if any.
  116. *
  117. *Exceptions:
  118. * Returns (size_t)-1 if s is NULL or invalid mb character encountered.
  119. *
  120. *******************************************************************************/
  121. size_t __cdecl wcstombs (
  122. char * s,
  123. const wchar_t * pwcs,
  124. size_t n
  125. )
  126. {
  127. #ifdef _MT
  128. pthreadlocinfo ptloci = _getptd()->ptlocinfo;
  129. if ( ptloci != __ptlocinfo )
  130. ptloci = __updatetlocinfo();
  131. return __wcstombs_mt(ptloci, s, pwcs, n);
  132. }
  133. size_t __cdecl __wcstombs_mt (
  134. pthreadlocinfo ptloci,
  135. char * s,
  136. const wchar_t * pwcs,
  137. size_t n
  138. )
  139. {
  140. #endif
  141. size_t count = 0;
  142. int i, retval;
  143. char buffer[MB_LEN_MAX];
  144. BOOL defused = 0;
  145. if (s && n == 0)
  146. /* dest string exists, but 0 bytes converted */
  147. return (size_t) 0;
  148. _ASSERTE(pwcs != NULL);
  149. #ifdef _WIN64
  150. /* n must fit into an int for WideCharToMultiByte */
  151. if ( n > INT_MAX )
  152. return (size_t)-1;
  153. #endif
  154. #if !defined( _NTSUBSET_ ) && !defined(_POSIX_)
  155. /* if destination string exists, fill it in */
  156. if (s)
  157. {
  158. #ifdef _MT
  159. if ( ptloci->lc_handle[LC_CTYPE] == _CLOCALEHANDLE )
  160. #else
  161. if ( __lc_handle[LC_CTYPE] == _CLOCALEHANDLE )
  162. #endif
  163. {
  164. /* C locale: easy and fast */
  165. while(count < n)
  166. {
  167. if (*pwcs > 255) /* validate high byte */
  168. {
  169. errno = EILSEQ;
  170. return (size_t)-1; /* error */
  171. }
  172. s[count] = (char) *pwcs;
  173. if (*pwcs++ == L'\0')
  174. return count;
  175. count++;
  176. }
  177. return count;
  178. } else {
  179. if (1 == MB_CUR_MAX)
  180. {
  181. /* If SBCS, one wchar_t maps to one char */
  182. /* WideCharToMultiByte will compare past NULL - reset n */
  183. if (n > 0)
  184. n = wcsncnt(pwcs, n);
  185. #ifdef _MT
  186. if ( ((count = WideCharToMultiByte( ptloci->lc_codepage,
  187. #else
  188. if ( ((count = WideCharToMultiByte( __lc_codepage,
  189. #endif
  190. 0,
  191. pwcs,
  192. (int)n,
  193. s,
  194. (int)n,
  195. NULL,
  196. &defused )) != 0) &&
  197. (!defused) )
  198. {
  199. if (*(s + count - 1) == '\0')
  200. count--; /* don't count NUL */
  201. return count;
  202. }
  203. errno = EILSEQ;
  204. return (size_t)-1;
  205. }
  206. else {
  207. /* If MBCS, wchar_t to char mapping unknown */
  208. /* Assume that usually the buffer is large enough */
  209. #ifdef _MT
  210. if ( ((count = WideCharToMultiByte( ptloci->lc_codepage,
  211. #else
  212. if ( ((count = WideCharToMultiByte( __lc_codepage,
  213. #endif
  214. 0,
  215. pwcs,
  216. -1,
  217. s,
  218. (int)n,
  219. NULL,
  220. &defused )) != 0) &&
  221. (!defused) )
  222. {
  223. return count - 1; /* don't count NUL */
  224. }
  225. if (defused || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  226. {
  227. errno = EILSEQ;
  228. return (size_t)-1;
  229. }
  230. /* buffer not large enough, must do char by char */
  231. while (count < n)
  232. {
  233. #ifdef _MT
  234. if ( ((retval = WideCharToMultiByte( ptloci->lc_codepage,
  235. #else
  236. if ( ((retval = WideCharToMultiByte( __lc_codepage,
  237. #endif
  238. 0,
  239. pwcs,
  240. 1,
  241. buffer,
  242. MB_CUR_MAX,
  243. NULL,
  244. &defused )) == 0)
  245. || defused )
  246. {
  247. errno = EILSEQ;
  248. return (size_t)-1;
  249. }
  250. if (count + retval > n)
  251. return count;
  252. for (i = 0; i < retval; i++, count++) /* store character */
  253. if((s[count] = buffer[i])=='\0')
  254. return count;
  255. pwcs++;
  256. }
  257. return count;
  258. }
  259. }
  260. }
  261. else { /* s == NULL, get size only, pwcs must be NUL-terminated */
  262. #ifdef _MT
  263. if ( ptloci->lc_handle[LC_CTYPE] == _CLOCALEHANDLE )
  264. #else
  265. if ( __lc_handle[LC_CTYPE] == _CLOCALEHANDLE )
  266. #endif
  267. return wcslen(pwcs);
  268. else {
  269. #ifdef _MT
  270. if ( ((count = WideCharToMultiByte( ptloci->lc_codepage,
  271. #else
  272. if ( ((count = WideCharToMultiByte( __lc_codepage,
  273. #endif
  274. 0,
  275. pwcs,
  276. -1,
  277. NULL,
  278. 0,
  279. NULL,
  280. &defused )) == 0) ||
  281. (defused) )
  282. {
  283. errno = EILSEQ;
  284. return (size_t)-1;
  285. }
  286. return count - 1;
  287. }
  288. }
  289. #else /* _NTSUBSET_/_POSIX_ */
  290. /* if destination string exists, fill it in */
  291. if (s)
  292. {
  293. NTSTATUS Status;
  294. Status = RtlUnicodeToMultiByteN( s,
  295. (ULONG) n,
  296. (PULONG)&count,
  297. (wchar_t *)pwcs,
  298. (wcslen(pwcs) + 1) *
  299. sizeof(WCHAR) );
  300. if (NT_SUCCESS(Status))
  301. {
  302. return count - 1; /* don't count NUL */
  303. } else {
  304. errno = EILSEQ;
  305. count = (size_t)-1;
  306. }
  307. } else { /* s == NULL, get size only, pwcs must be NUL-terminated */
  308. NTSTATUS Status;
  309. Status = RtlUnicodeToMultiByteSize( (PULONG)&count,
  310. (wchar_t *)pwcs,
  311. (wcslen(pwcs) + 1) *
  312. sizeof(WCHAR) );
  313. if (NT_SUCCESS(Status))
  314. {
  315. return count - 1; /* don't count NUL */
  316. } else {
  317. errno = EILSEQ;
  318. count = (size_t)-1;
  319. }
  320. }
  321. return count;
  322. #endif /* _NTSUBSET_/_POSIX_ */
  323. }