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.

583 lines
14 KiB

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