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.

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