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.

621 lines
15 KiB

  1. //
  2. // strinout.cpp
  3. //
  4. // Unicode wrappers (String converters)
  5. //
  6. // Copyright(C) Microsoft Corporation 2000
  7. // Author: Nadim Abdo (nadima)
  8. //
  9. // based on code from shell\shlwapi\unicwrap.*
  10. //
  11. #include "stdafx.h"
  12. #include "cstrinout.h"
  13. //+---------------------------------------------------------------------------
  14. //
  15. // Member: CConvertStr::Free
  16. //
  17. // Synopsis: Frees string if alloc'd and initializes to NULL.
  18. //
  19. //----------------------------------------------------------------------------
  20. void
  21. CConvertStr::Free()
  22. {
  23. if (_pstr != _ach && HIWORD64(_pstr) != 0 && !IsAtom())
  24. {
  25. delete [] _pstr;
  26. }
  27. _pstr = NULL;
  28. }
  29. //+---------------------------------------------------------------------------
  30. //
  31. // Member: CConvertStrW::Free
  32. //
  33. // Synopsis: Frees string if alloc'd and initializes to NULL.
  34. //
  35. //----------------------------------------------------------------------------
  36. void
  37. CConvertStrW::Free()
  38. {
  39. if (_pwstr != _awch && HIWORD64(_pwstr) != 0)
  40. {
  41. delete [] _pwstr;
  42. }
  43. _pwstr = NULL;
  44. }
  45. //+---------------------------------------------------------------------------
  46. //
  47. // Member: CStrInW::Init
  48. //
  49. // Synopsis: Converts a LPSTR function argument to a LPWSTR.
  50. //
  51. // Arguments: [pstr] -- The function argument. May be NULL or an atom
  52. // (HIWORD64(pwstr) == 0).
  53. //
  54. // [cch] -- The number of characters in the string to
  55. // convert. If -1, the string is assumed to be
  56. // NULL terminated and its length is calculated.
  57. //
  58. // Modifies: [this]
  59. //
  60. //----------------------------------------------------------------------------
  61. void
  62. CStrInW::Init(LPCSTR pstr, int cch)
  63. {
  64. int cchBufReq;
  65. _cwchLen = 0;
  66. // Check if string is NULL or an atom.
  67. if (HIWORD64(pstr) == 0)
  68. {
  69. _pwstr = (LPWSTR) pstr;
  70. return;
  71. }
  72. ASSERT(cch == -1 || cch > 0);
  73. //
  74. // Convert string to preallocated buffer, and return if successful.
  75. //
  76. // Since the passed in buffer may not be null terminated, we have
  77. // a problem if cch==ARRAYSIZE(_awch), because MultiByteToWideChar
  78. // will succeed, and we won't be able to null terminate the string!
  79. // Decrease our buffer by one for this case.
  80. //
  81. _cwchLen = MultiByteToWideChar(
  82. CP_ACP, 0, pstr, cch, _awch, ARRAYSIZE(_awch)-1);
  83. if (_cwchLen > 0)
  84. {
  85. // Some callers don't NULL terminate.
  86. //
  87. // We could check "if (-1 != cch)" before doing this,
  88. // but always doing the null is less code.
  89. //
  90. _awch[_cwchLen] = 0;
  91. if (0 == _awch[_cwchLen-1]) // account for terminator
  92. _cwchLen--;
  93. _pwstr = _awch;
  94. return;
  95. }
  96. //
  97. // Alloc space on heap for buffer.
  98. //
  99. cchBufReq = MultiByteToWideChar( CP_ACP, 0, pstr, cch, NULL, 0 );
  100. // Again, leave room for null termination
  101. cchBufReq++;
  102. ASSERT(cchBufReq > 0);
  103. _pwstr = new WCHAR[cchBufReq];
  104. if (!_pwstr)
  105. {
  106. // On failure, the argument will point to the empty string.
  107. _awch[0] = 0;
  108. _pwstr = _awch;
  109. return;
  110. }
  111. ASSERT(HIWORD64(_pwstr));
  112. _cwchLen = MultiByteToWideChar(
  113. CP_ACP, 0, pstr, cch, _pwstr, cchBufReq );
  114. #if DBG == 1 /* { */
  115. if (0 == _cwchLen)
  116. {
  117. int errcode = GetLastError();
  118. ASSERT(0 && "MultiByteToWideChar failed in unicode wrapper.");
  119. }
  120. #endif /* } */
  121. // Again, make sure we're always null terminated
  122. ASSERT(_cwchLen < cchBufReq);
  123. _pwstr[_cwchLen] = 0;
  124. if (0 == _pwstr[_cwchLen-1]) // account for terminator
  125. _cwchLen--;
  126. }
  127. //+---------------------------------------------------------------------------
  128. //
  129. // Member: CStrIn::CStrIn
  130. //
  131. // Synopsis: Inits the class.
  132. //
  133. // NOTE: Don't inline this function or you'll increase code size
  134. // by pushing -1 on the stack for each call.
  135. //
  136. //----------------------------------------------------------------------------
  137. CStrIn::CStrIn(LPCWSTR pwstr) : CConvertStr(CP_ACP)
  138. {
  139. Init(pwstr, -1);
  140. }
  141. CStrIn::CStrIn(UINT uCP, LPCWSTR pwstr) : CConvertStr(uCP)
  142. {
  143. Init(pwstr, -1);
  144. }
  145. //+---------------------------------------------------------------------------
  146. //
  147. // Member: CStrIn::Init
  148. //
  149. // Synopsis: Converts a LPWSTR function argument to a LPSTR.
  150. //
  151. // Arguments: [pwstr] -- The function argument. May be NULL or an atom
  152. // (HIWORD(pwstr) == 0).
  153. //
  154. // [cwch] -- The number of characters in the string to
  155. // convert. If -1, the string is assumed to be
  156. // NULL terminated and its length is calculated.
  157. //
  158. // Modifies: [this]
  159. //
  160. // Note: We ignore AreFileApisANSI() and always use CP_ACP.
  161. // The reason is that nobody uses SetFileApisToOEM() except
  162. // console apps, and once you set file APIs to OEM, you
  163. // cannot call shell/user/gdi APIs, since they assume ANSI
  164. // regardless of the FileApis setting. So you end up in
  165. // this horrible messy state where the filename APIs interpret
  166. // the strings as OEM but SHELL32 interprets the strings
  167. // as ANSI and you end up with a big mess.
  168. //
  169. //----------------------------------------------------------------------------
  170. void
  171. CStrIn::Init(LPCWSTR pwstr, int cwch)
  172. {
  173. int cchBufReq;
  174. #if DBG == 1 /* { */
  175. int errcode;
  176. #endif /* } */
  177. _cchLen = 0;
  178. // Check if string is NULL or an atom.
  179. if (HIWORD64(pwstr) == 0 || IsAtom())
  180. {
  181. _pstr = (LPSTR) pwstr;
  182. return;
  183. }
  184. if ( cwch == 0 )
  185. {
  186. *_ach = '\0';
  187. _pstr = _ach;
  188. return;
  189. }
  190. //
  191. // Convert string to preallocated buffer, and return if successful.
  192. //
  193. _cchLen = WideCharToMultiByte(
  194. _uCP, 0, pwstr, cwch, _ach, ARRAYSIZE(_ach)-1, NULL, NULL);
  195. if (_cchLen > 0)
  196. {
  197. // This is DBCS safe since byte before _cchLen is last character
  198. _ach[_cchLen] = 0;
  199. // this may not be safe if the last character
  200. // was a multibyte character...
  201. if (_ach[_cchLen-1]==0)
  202. _cchLen--; // account for terminator
  203. _pstr = _ach;
  204. return;
  205. }
  206. cchBufReq = WideCharToMultiByte(
  207. CP_ACP, 0, pwstr, cwch, NULL, 0, NULL, NULL);
  208. cchBufReq++;
  209. ASSERT(cchBufReq > 0);
  210. _pstr = new char[cchBufReq];
  211. if (!_pstr)
  212. {
  213. // On failure, the argument will point to the empty string.
  214. _ach[0] = 0;
  215. _pstr = _ach;
  216. return;
  217. }
  218. ASSERT(HIWORD64(_pstr));
  219. _cchLen = WideCharToMultiByte(
  220. _uCP, 0, pwstr, cwch, _pstr, cchBufReq, NULL, NULL);
  221. #if DBG == 1 /* { */
  222. if (_cchLen < 0)
  223. {
  224. errcode = GetLastError();
  225. ASSERT(0 && "WideCharToMultiByte failed in unicode wrapper.");
  226. }
  227. #endif /* } */
  228. // Again, make sure we're always null terminated
  229. ASSERT(_cchLen < cchBufReq);
  230. _pstr[_cchLen] = 0;
  231. if (0 == _pstr[_cchLen-1]) // account for terminator
  232. _cchLen--;
  233. }
  234. //+---------------------------------------------------------------------------
  235. //
  236. // Member: CStrInMulti::CStrInMulti
  237. //
  238. // Synopsis: Converts mulitple LPWSTRs to a multiple LPSTRs.
  239. //
  240. // Arguments: [pwstr] -- The strings to convert.
  241. //
  242. // Modifies: [this]
  243. //
  244. //----------------------------------------------------------------------------
  245. CStrInMulti::CStrInMulti(LPCWSTR pwstr)
  246. {
  247. LPCWSTR pwstrT;
  248. // We don't handle atoms because we don't need to.
  249. ASSERT(HIWORD64(pwstr));
  250. //
  251. // Count number of characters to convert.
  252. //
  253. pwstrT = pwstr;
  254. if (pwstr)
  255. {
  256. do {
  257. while (*pwstrT++)
  258. ;
  259. } while (*pwstrT++);
  260. }
  261. Init(pwstr, (int)(pwstrT - pwstr));
  262. }
  263. //+---------------------------------------------------------------------------
  264. //
  265. // Member: CPPFIn::CPPFIn
  266. //
  267. // Synopsis: Inits the class. Truncates the filename to MAX_PATH
  268. // so Win9x DBCS won't fault. Win9x SBCS silently truncates
  269. // to MAX_PATH, so we're bug-for-bug compatible.
  270. //
  271. //----------------------------------------------------------------------------
  272. CPPFIn::CPPFIn(LPCWSTR pwstr)
  273. {
  274. SHUnicodeToAnsi(pwstr, _ach, ARRAYSIZE(_ach));
  275. }
  276. //+---------------------------------------------------------------------------
  277. //
  278. // Member: CStrOut::CStrOut
  279. //
  280. // Synopsis: Allocates enough space for an out buffer.
  281. //
  282. // Arguments: [pwstr] -- The Unicode buffer to convert to when destroyed.
  283. // May be NULL.
  284. //
  285. // [cwchBuf] -- The size of the buffer in characters.
  286. //
  287. // Modifies: [this].
  288. //
  289. //----------------------------------------------------------------------------
  290. CStrOut::CStrOut(LPWSTR pwstr, int cwchBuf) : CConvertStr(CP_ACP)
  291. {
  292. Init(pwstr, cwchBuf);
  293. }
  294. CStrOut::CStrOut(UINT uCP, LPWSTR pwstr, int cwchBuf) : CConvertStr(uCP)
  295. {
  296. Init(pwstr, cwchBuf);
  297. }
  298. void
  299. CStrOut::Init(LPWSTR pwstr, int cwchBuf)
  300. {
  301. ASSERT(cwchBuf >= 0);
  302. _pwstr = pwstr;
  303. _cwchBuf = cwchBuf;
  304. if (!pwstr)
  305. {
  306. // Force cwchBuf = 0 because many callers (in particular, registry
  307. // munging functions) pass garbage as the length because they know
  308. // it will be ignored.
  309. _cwchBuf = 0;
  310. _pstr = NULL;
  311. return;
  312. }
  313. ASSERT(HIWORD64(pwstr));
  314. // Initialize buffer in case Windows API returns an error.
  315. _ach[0] = 0;
  316. // Use preallocated buffer if big enough.
  317. if (cwchBuf * 2 <= ARRAYSIZE(_ach))
  318. {
  319. _pstr = _ach;
  320. return;
  321. }
  322. // Allocate buffer.
  323. _pstr = new char[cwchBuf * 2];
  324. if (!_pstr)
  325. {
  326. //
  327. // On failure, the argument will point to a zero-sized buffer initialized
  328. // to the empty string. This should cause the Windows API to fail.
  329. //
  330. ASSERT(cwchBuf > 0);
  331. _pwstr[0] = 0;
  332. _cwchBuf = 0;
  333. _pstr = _ach;
  334. return;
  335. }
  336. ASSERT(HIWORD64(_pstr));
  337. _pstr[0] = 0;
  338. }
  339. //+---------------------------------------------------------------------------
  340. //
  341. // Member: CStrOutW::CStrOutW
  342. //
  343. // Synopsis: Allocates enough space for an out buffer.
  344. //
  345. // Arguments: [pstr] -- The MBCS buffer to convert to when destroyed.
  346. // May be NULL.
  347. //
  348. // [cchBuf] -- The size of the buffer in characters.
  349. //
  350. // Modifies: [this].
  351. //
  352. //----------------------------------------------------------------------------
  353. CStrOutW::CStrOutW(LPSTR pstr, int cchBuf)
  354. {
  355. ASSERT(cchBuf >= 0);
  356. _pstr = pstr;
  357. _cchBuf = cchBuf;
  358. if (!pstr)
  359. {
  360. // Force cchBuf = 0 because many callers (in particular, registry
  361. // munging functions) pass garbage as the length because they know
  362. // it will be ignored.
  363. _cchBuf = 0;
  364. _pwstr = NULL;
  365. return;
  366. }
  367. ASSERT(HIWORD64(pstr));
  368. // Initialize buffer in case Windows API returns an error.
  369. _awch[0] = 0;
  370. // Use preallocated buffer if big enough.
  371. if (cchBuf <= ARRAYSIZE(_awch))
  372. {
  373. _pwstr = _awch;
  374. return;
  375. }
  376. // Allocate buffer.
  377. _pwstr = new WCHAR[cchBuf];
  378. if (!_pwstr)
  379. {
  380. //
  381. // On failure, the argument will point to a zero-sized buffer initialized
  382. // to the empty string. This should cause the Windows API to fail.
  383. //
  384. ASSERT(cchBuf > 0);
  385. _pstr[0] = 0;
  386. _cchBuf = 0;
  387. _pwstr = _awch;
  388. return;
  389. }
  390. ASSERT(HIWORD64(_pwstr));
  391. _pwstr[0] = 0;
  392. }
  393. //+---------------------------------------------------------------------------
  394. //
  395. // Member: CStrOut::ConvertIncludingNul
  396. //
  397. // Synopsis: Converts the buffer from MBCS to Unicode
  398. //
  399. // Return: Character count INCLUDING the trailing '\0'
  400. //
  401. //----------------------------------------------------------------------------
  402. int
  403. CStrOut::ConvertIncludingNul()
  404. {
  405. int cch;
  406. if (!_pstr)
  407. return 0;
  408. cch = SHAnsiToUnicodeCP(_uCP, _pstr, _pwstr, _cwchBuf);
  409. #if DBG == 1 /* { */
  410. if (cch == 0 && _cwchBuf > 0)
  411. {
  412. int errcode = GetLastError();
  413. ASSERT(0 && "SHAnsiToUnicode failed in unicode wrapper.");
  414. }
  415. #endif /* } */
  416. Free();
  417. return cch;
  418. }
  419. //+---------------------------------------------------------------------------
  420. //
  421. // Member: CStrOutW::ConvertIncludingNul
  422. //
  423. // Synopsis: Converts the buffer from Unicode to MBCS
  424. //
  425. // Return: Character count INCLUDING the trailing '\0'
  426. //
  427. //----------------------------------------------------------------------------
  428. int
  429. CStrOutW::ConvertIncludingNul()
  430. {
  431. int cch;
  432. if (!_pwstr)
  433. return 0;
  434. cch = SHUnicodeToAnsi(_pwstr, _pstr, _cchBuf);
  435. #if DBG == 1 /* { */
  436. if (cch == 0 && _cchBuf > 0)
  437. {
  438. int errcode = GetLastError();
  439. ASSERT(0 && "SHUnicodeToAnsi failed in unicode wrapper.");
  440. }
  441. #endif /* } */
  442. Free();
  443. return cch;
  444. }
  445. //+---------------------------------------------------------------------------
  446. //
  447. // Member: CStrOut::ConvertExcludingNul
  448. //
  449. // Synopsis: Converts the buffer from MBCS to Unicode
  450. //
  451. // Return: Character count EXCLUDING the trailing '\0'
  452. //
  453. //----------------------------------------------------------------------------
  454. int
  455. CStrOut::ConvertExcludingNul()
  456. {
  457. int ret = ConvertIncludingNul();
  458. if (ret > 0)
  459. {
  460. ret -= 1;
  461. }
  462. return ret;
  463. }
  464. //+---------------------------------------------------------------------------
  465. //
  466. // Member: CStrOut::CopyNoConvert
  467. //
  468. // Synopsis: Copies to the output buffer without converting
  469. //
  470. // Return: Character count EXCLUDING the trailing '\0'
  471. //
  472. //----------------------------------------------------------------------------
  473. int
  474. CStrOut::CopyNoConvert(int srcBytes)
  475. {
  476. if (!_pstr || !_pwstr)
  477. {
  478. return 0;
  479. }
  480. if (srcBytes < (int)(_cwchBuf * sizeof(WCHAR)))
  481. {
  482. memcpy(_pwstr, _pstr, srcBytes);
  483. Free();
  484. return srcBytes;
  485. }
  486. else
  487. {
  488. return 0;
  489. }
  490. }
  491. //+---------------------------------------------------------------------------
  492. //
  493. // Member: CStrOut::~CStrOut
  494. //
  495. // Synopsis: Converts the buffer from MBCS to Unicode.
  496. //
  497. // Note: Don't inline this function, or you'll increase code size as
  498. // both ConvertIncludingNul() and CConvertStr::~CConvertStr will be
  499. // called inline.
  500. //
  501. //----------------------------------------------------------------------------
  502. CStrOut::~CStrOut()
  503. {
  504. ConvertIncludingNul();
  505. }
  506. //+---------------------------------------------------------------------------
  507. //
  508. // Member: CStrOutW::~CStrOutW
  509. //
  510. // Synopsis: Converts the buffer from Unicode to MBCS.
  511. //
  512. // Note: Don't inline this function, or you'll increase code size as
  513. // both ConvertIncludingNul() and CConvertStr::~CConvertStr will be
  514. // called inline.
  515. //
  516. //----------------------------------------------------------------------------
  517. CStrOutW::~CStrOutW()
  518. {
  519. ConvertIncludingNul();
  520. }