Leaked source code of windows server 2003
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.

570 lines
12 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. unicode.c
  5. Abstract:
  6. Simplified Unicode-Ansi conversion functions.
  7. Externally exposed routines:
  8. In-Place Conversion:
  9. KnownSizeDbcsToUnicodeN
  10. KnownSizeUnicodeToDbcsN
  11. KnownSizeWtoA
  12. KnownSizeAtoW
  13. In-Place Conversion without nul checks:
  14. DirectDbcsToUnicodeN
  15. DirectUnicodeToDbcsN
  16. DirectAtoW
  17. DirectWtoA
  18. Length/pool options:
  19. DbcsToUnicodeN
  20. UnicodeToDbcsN
  21. DbcsToUnicode
  22. UnicodeToDbcs
  23. FreeConvertedPoolStr
  24. Simplified type conversions:
  25. ConvertWtoA
  26. ConvertAtoW
  27. FreeConvertedStr
  28. TCHAR routines that can be compiled both ways:
  29. CreateDbcs
  30. CreateUnicode
  31. DestroyDbcs
  32. DestroyUnicode
  33. Author:
  34. Jim Schmidt (jimschm) 04-Aug-1997
  35. Revision History:
  36. jimschm 15-Feb-1999 Eliminated MikeCo's routines, since they are
  37. broken on FE
  38. jimschm 23-Sep-1998 Added in-place routines
  39. --*/
  40. #include "pch.h"
  41. #include "migutilp.h"
  42. #include <locale.h>
  43. #include <mbctype.h>
  44. extern POOLHANDLE g_TextPool;
  45. extern DWORD g_MigutilWCToMBFlags;
  46. WORD g_GlobalCodePage = CP_ACP;
  47. typedef VOID(WINAPI SETACP)(WORD CodePage);
  48. typedef SETACP * PSETACP;
  49. VOID
  50. SetGlobalCodePage (
  51. IN WORD CodePage,
  52. IN LCID Locale
  53. )
  54. {
  55. PSETACP SetACP;
  56. HANDLE Lib;
  57. g_GlobalCodePage = CodePage;
  58. if (ISNT()) {
  59. Lib = LoadSystemLibrary (TEXT("kernel32.dll"));
  60. if (Lib) {
  61. SetACP = (PSETACP) GetProcAddress (Lib, "SetCPGlobal");
  62. if (SetACP) {
  63. SetACP (CodePage);
  64. }
  65. FreeLibrary (Lib);
  66. }
  67. }
  68. SetThreadLocale (Locale);
  69. setlocale(LC_ALL,"");
  70. g_IsMbcp = (_setmbcp(CodePage) == 0);
  71. }
  72. VOID
  73. GetGlobalCodePage (
  74. OUT PWORD CodePage, OPTIONAL
  75. OUT PLCID Locale OPTIONAL
  76. )
  77. {
  78. if (CodePage) {
  79. if (g_GlobalCodePage == CP_ACP) {
  80. *CodePage = (WORD)GetACP();
  81. } else {
  82. *CodePage = g_GlobalCodePage;
  83. }
  84. }
  85. if (Locale) {
  86. *Locale = GetThreadLocale();
  87. }
  88. }
  89. PCSTR
  90. RealUnicodeToDbcsN (
  91. IN POOLHANDLE Pool, OPTIONAL
  92. IN PCWSTR StrIn,
  93. IN DWORD Lchars
  94. )
  95. /*++
  96. Routine Description:
  97. Converts a UNICODE string to DBCS.
  98. WARNING: Currently supports the ANSI code page only. Later we can fix this.
  99. Arguments:
  100. Pool - Specifies the pool where memory is allocated from. If not specified,
  101. g_TextPool is used instead.
  102. StrIn - Specifies the inbound UNICODE string
  103. Lchars - Specifies the number of characters, excluding the nul, to
  104. convert.
  105. Return Value:
  106. A pointer to the ANSI string, or NULL if an error occurred.
  107. --*/
  108. {
  109. PSTR DbcsStr;
  110. DWORD Size;
  111. DWORD rc;
  112. if (!Pool) {
  113. Pool = g_TextPool;
  114. }
  115. if (INVALID_CHAR_COUNT == Lchars) {
  116. Lchars = LcharCountW (StrIn);
  117. }
  118. Size = (Lchars + 1) * sizeof (WCHAR);
  119. DbcsStr = (PSTR) PoolMemGetAlignedMemory (Pool, Size);
  120. if (!DbcsStr) {
  121. DEBUGMSG ((DBG_ERROR, "UnicodeToDbcsN could not allocate string"));
  122. return NULL;
  123. }
  124. rc = WideCharToMultiByte (
  125. g_GlobalCodePage,
  126. g_MigutilWCToMBFlags,
  127. StrIn,
  128. Lchars, // wc input count
  129. DbcsStr,
  130. Size,
  131. NULL,
  132. NULL
  133. );
  134. // Report error returns from WideCharToMultiByte
  135. if (!rc && Lchars) {
  136. PushError();
  137. PoolMemReleaseMemory (Pool, DbcsStr);
  138. PopError();
  139. DEBUGMSG ((
  140. DBG_WARNING,
  141. "UnicodeToDbcsN error caused memory to be released in pool; may cause harmless PoolMem warnings."
  142. ));
  143. return NULL;
  144. }
  145. *LcharCountToPointerA (DbcsStr, Lchars) = 0;
  146. return DbcsStr;
  147. }
  148. PCWSTR
  149. RealDbcsToUnicodeN (
  150. IN POOLHANDLE Pool, OPTIONAL
  151. IN PCSTR StrIn,
  152. IN DWORD Lchars
  153. )
  154. /*++
  155. Routine Description:
  156. Converts a DBCS string to UNICODE.
  157. WARNING: Currently supports the ANSI code page only. Later we can fix this.
  158. Arguments:
  159. Pool - Specifies pool to allocate UNICODE string from. If not specified,
  160. g_TextPool is used.
  161. StrIn - Specifies string to be converted
  162. Lchars - Specifies the number of multibyte characters, excluding the nul,
  163. to convert. If -1, all of StrIn will be converted.
  164. Return Value:
  165. A pointer to the converted UNICODE string, or NULL if an error ocurred.
  166. --*/
  167. {
  168. PWSTR UnicodeStr;
  169. DWORD UnicodeStrBufLenBytes;
  170. DWORD WcharsConverted;
  171. DWORD StrInBytesToConvert;
  172. //
  173. // Find number of multi-byte characters to convert. Punt on case where
  174. // caller asks for more chars than available.
  175. //
  176. if (INVALID_CHAR_COUNT == Lchars) {
  177. Lchars = LcharCountA (StrIn);
  178. }
  179. //
  180. // Count bytes to convert from the input string (excludes delimiter)
  181. //
  182. StrInBytesToConvert = (UINT) (UINT_PTR) (LcharCountToPointerA(StrIn, Lchars) - StrIn);
  183. //
  184. // Get output buffer size, in bytes, including delimiter
  185. //
  186. UnicodeStrBufLenBytes = (Lchars + 1) * sizeof (WCHAR);
  187. if (!Pool) {
  188. Pool = g_TextPool;
  189. }
  190. //
  191. // Get buffer
  192. //
  193. UnicodeStr = (PWSTR) PoolMemGetAlignedMemory (Pool, UnicodeStrBufLenBytes);
  194. if (!UnicodeStr) {
  195. DEBUGMSG ((DBG_ERROR, "DbcsToUnicodeN could not allocate string"));
  196. return NULL;
  197. }
  198. //
  199. // Convert
  200. //
  201. WcharsConverted = MultiByteToWideChar (
  202. g_GlobalCodePage,
  203. 0, // MB_ERR_INVALID_CHARS,
  204. StrIn,
  205. StrInBytesToConvert,
  206. UnicodeStr,
  207. UnicodeStrBufLenBytes
  208. );
  209. //
  210. // Check for conversion error (>0 chars in, 0 chars out)
  211. //
  212. if (0 == WcharsConverted && 0 != Lchars) {
  213. PushError();
  214. PoolMemReleaseMemory (Pool, UnicodeStr);
  215. PopError();
  216. DEBUGMSG ((
  217. DBG_WARNING,
  218. "DbcsToUnicodeN error caused memory to be released in pool; may cause harmless PoolMem warnings."
  219. ));
  220. return NULL;
  221. }
  222. //
  223. // Write delimiter on the output string
  224. //
  225. UnicodeStr[WcharsConverted] = 0;
  226. return UnicodeStr;
  227. }
  228. VOID
  229. FreeConvertedPoolStr (
  230. IN POOLHANDLE Pool, OPTIONAL
  231. IN PVOID StrIn
  232. )
  233. /*++
  234. Routine Description:
  235. Frees the memory allocated by UnicodeToDbcsN or DbcsToUnicodeN.
  236. Arguments:
  237. Pool - Specifies pool to allocate UNICODE string from. If not specified,
  238. g_TextPool is used.
  239. StrIn - Specifies string that was returned by UnicodeToDebcsN or
  240. DbcsToUnicodeN.
  241. Return Value:
  242. none
  243. --*/
  244. {
  245. if (!StrIn) {
  246. return;
  247. }
  248. if (!Pool) {
  249. Pool = g_TextPool;
  250. }
  251. PoolMemReleaseMemory (Pool, (PVOID) StrIn);
  252. }
  253. PSTR
  254. KnownSizeUnicodeToDbcsN (
  255. OUT PSTR StrOut,
  256. IN PCWSTR StrIn,
  257. IN DWORD Lchars
  258. )
  259. /*++
  260. Routine Description:
  261. KnownSizeUnicodeToDbcsN converts a UNICODE string to DBCS. The caller
  262. manages the outbound buffer.
  263. Arguments:
  264. StrOut - Receives the DBCS result.
  265. StrIn - Specifies the UNICODE string to convert.
  266. Lchars - Specifies the character count of StrIn (not the byte count), or
  267. INVALID_CHAR_COUNT for the complete string.
  268. Return Value:
  269. Returns StrOut.
  270. --*/
  271. {
  272. DWORD rc;
  273. if (INVALID_CHAR_COUNT == Lchars) {
  274. Lchars = LcharCountW (StrIn);
  275. }
  276. rc = WideCharToMultiByte (
  277. g_GlobalCodePage,
  278. g_MigutilWCToMBFlags,
  279. StrIn,
  280. Lchars, // wc input count
  281. StrOut,
  282. Lchars * 2,
  283. NULL,
  284. NULL
  285. );
  286. DEBUGMSG_IF ((
  287. !rc && Lchars,
  288. DBG_WARNING,
  289. "KnownSizeUnicodeToDbcsN failed."
  290. ));
  291. StrOut[rc] = 0;
  292. return StrOut;
  293. }
  294. PWSTR
  295. KnownSizeDbcsToUnicodeN (
  296. OUT PWSTR StrOut,
  297. IN PCSTR StrIn,
  298. IN DWORD Lchars
  299. )
  300. /*++
  301. Routine Description:
  302. KnownSizeDbcsToUnicodeN converts a DBCS string to UNICODE. The caller
  303. manages the outbound buffer.
  304. Arguments:
  305. StrOut - Receives the UNICODE result.
  306. StrIn - Specifies the DBCS string to convert.
  307. Lchars - Specifies the character count of StrIn (not the byte count), or
  308. INVALID_CHAR_COUNT for the complete string.
  309. Return Value:
  310. Returns StrOut.
  311. --*/
  312. {
  313. DWORD rc;
  314. DWORD StrInBytesToConvert;
  315. if (INVALID_CHAR_COUNT == Lchars) {
  316. StrInBytesToConvert = ByteCountA (StrIn);
  317. } else {
  318. StrInBytesToConvert = (UINT) (UINT_PTR) (LcharCountToPointerA (StrIn, Lchars) - StrIn);
  319. }
  320. rc = MultiByteToWideChar (
  321. g_GlobalCodePage,
  322. 0, // MB_ERR_INVALID_CHARS,
  323. StrIn,
  324. StrInBytesToConvert,
  325. StrOut,
  326. StrInBytesToConvert * 2
  327. );
  328. DEBUGMSG_IF ((
  329. !rc && Lchars,
  330. DBG_WARNING,
  331. "KnownSizeDbcsToUnicodeN failed."
  332. ));
  333. StrOut[rc] = 0;
  334. return StrOut;
  335. }
  336. PSTR
  337. DirectUnicodeToDbcsN (
  338. OUT PSTR StrOut,
  339. IN PCWSTR StrIn,
  340. IN DWORD Bytes
  341. )
  342. /*++
  343. Routine Description:
  344. DirectUnicodeToDbcsN converts a UNICODE string to DBCS. The caller
  345. manages the outbound buffer. This function does not check for nuls
  346. in StrIn when Bytes is non-zero, and it does not terminate the
  347. string.
  348. Arguments:
  349. StrOut - Receives the DBCS result.
  350. StrIn - Specifies the UNICODE string to convert.
  351. Bytes - Specifies the byte count of StrIn, or INVALID_CHAR_COUNT
  352. for the complete string.
  353. Return Value:
  354. Returns StrOut.
  355. --*/
  356. {
  357. DWORD rc;
  358. if (INVALID_CHAR_COUNT == Bytes) {
  359. Bytes = ByteCountW (StrIn);
  360. }
  361. rc = WideCharToMultiByte (
  362. g_GlobalCodePage,
  363. g_MigutilWCToMBFlags,
  364. StrIn,
  365. Bytes / sizeof (WCHAR),
  366. StrOut,
  367. Bytes,
  368. NULL,
  369. NULL
  370. );
  371. DEBUGMSG_IF ((
  372. !rc && Bytes,
  373. DBG_WARNING,
  374. "DirectUnicodeToDbcsN failed."
  375. ));
  376. return StrOut;
  377. }
  378. PWSTR
  379. DirectDbcsToUnicodeN (
  380. OUT PWSTR StrOut,
  381. IN PCSTR StrIn,
  382. IN DWORD Bytes
  383. )
  384. /*++
  385. Routine Description:
  386. DirectDbcsToUnicodeN converts a DBCS string to UNICODE. The caller
  387. manages the outbound buffer. This function does not check for nuls
  388. in StrIn when Bytes is non-zero, and it does not terminate the string.
  389. Arguments:
  390. StrOut - Receives the UNICODE result.
  391. StrIn - Specifies the DBCS string to convert.
  392. Bytes - Specifies the byte count of StrIn, or INVALID_CHAR_COUNT
  393. for the complete string.
  394. Return Value:
  395. Returns StrOut.
  396. --*/
  397. {
  398. DWORD rc;
  399. if (INVALID_CHAR_COUNT == Bytes) {
  400. Bytes = ByteCountA (StrIn);
  401. }
  402. rc = MultiByteToWideChar (
  403. g_GlobalCodePage,
  404. 0, // MB_ERR_INVALID_CHARS,
  405. StrIn,
  406. Bytes,
  407. StrOut,
  408. Bytes * 2
  409. );
  410. DEBUGMSG_IF ((
  411. !rc && Bytes,
  412. DBG_WARNING,
  413. "DirectDbcsToUnicodeN failed."
  414. ));
  415. return StrOut;
  416. }