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.

712 lines
24 KiB

  1. #if !defined(_FUSION_INC_FUSIONCHARTRAITS_H_INCLUDED_)
  2. #define _FUSION_INC_FUSIONCHARTRAITS_H_INCLUDED_
  3. #pragma once
  4. #include <stdio.h>
  5. #include <limits.h>
  6. #include "returnstrategy.h"
  7. #include "fusionhashstring.h"
  8. #include "fusionstring.h"
  9. enum StringComparisonResult {
  10. eLessThan,
  11. eEquals,
  12. eGreaterThan
  13. };
  14. //
  15. // This is not the base of all possible CharTraits, but it is the base of the ones
  16. // we have so far. There are pieces of this you can imagine changing.
  17. // StringLength could be strlen/wcslen (msvcrt/Rtl/ntoskrnl)
  18. // CompareStrings could be stricmp/wcsicmp or like unilib and do all the work itself
  19. // WideCharToMultiByte / MultiByteToWideChar could use Rtl.
  20. // more
  21. //
  22. template <typename Char, typename OtherChar>
  23. class CCharTraitsBase
  24. {
  25. typedef CCharTraitsBase<Char, OtherChar> TThis;
  26. public:
  27. typedef Char TChar;
  28. typedef Char* TMutableString;
  29. typedef const Char* TConstantString;
  30. // MFC 7.0 templatized CString makes some good use of this idea; we do not yet.
  31. typedef OtherChar TOtherChar;
  32. typedef OtherChar* TOtherString;
  33. typedef const OtherChar* TOtherConstantString;
  34. inline static TChar NullCharacter() { return 0; }
  35. inline static bool IsNullCharacter(TChar ch)
  36. { return ch == NullCharacter(); }
  37. inline static TConstantString PreferredPathSeparatorString()
  38. {
  39. const static TChar Result[] = { '\\', 0 };
  40. return Result;
  41. }
  42. inline static TChar PreferredPathSeparator()
  43. { return '\\'; }
  44. inline static bool IsPathSeparator(TChar ch)
  45. { return ((ch == '\\') || (ch == '/')); }
  46. inline static TConstantString PathSeparators()
  47. {
  48. const static TChar Result[] = { '\\', '/', 0 };
  49. return Result;
  50. }
  51. inline static TChar DotChar()
  52. { return '.'; }
  53. // copy into buffer from TChar to TChar
  54. template <typename ReturnStrategy>
  55. inline static ReturnStrategy::ReturnType
  56. CopyIntoBuffer(
  57. ReturnStrategy &returnStrategy,
  58. TChar rgchBuffer[],
  59. SIZE_T cchBuffer,
  60. TConstantString szString,
  61. SIZE_T cchIn
  62. )
  63. {
  64. if (cchBuffer != 0)
  65. {
  66. if (szString != NULL)
  67. {
  68. SIZE_T cchToCopy = cchIn;
  69. if (cchToCopy >= cchBuffer)
  70. cchToCopy = cchBuffer - 1;
  71. memcpy(rgchBuffer, szString, cchToCopy * sizeof(TChar));
  72. rgchBuffer[cchToCopy] = NullCharacter();
  73. }
  74. else
  75. rgchBuffer[0] = NullCharacter();
  76. }
  77. returnStrategy.SetWin32Bool(TRUE);
  78. return returnStrategy.Return();
  79. }
  80. // copy into buffer from TChar to TChar
  81. inline static HRESULT CopyIntoBuffer(TChar rgchBuffer[], SIZE_T cchBuffer, TConstantString szString, SIZE_T cchIn)
  82. {
  83. CReturnStrategyHresult hr;
  84. return TThis::CopyIntoBuffer(hr, rgchBuffer, cchBuffer, szString, cchIn);
  85. }
  86. // copy into buffer from TChar to TChar
  87. inline static BOOL Win32CopyIntoBuffer(TChar rgchBuffer[], SIZE_T cchBuffer, TConstantString szString, SIZE_T cchIn)
  88. {
  89. CReturnStrategyBoolLastError f;
  90. return TThis::CopyIntoBuffer(f, rgchBuffer, cchBuffer, szString, cchIn);
  91. }
  92. // copy into buffer from TChar to TChar
  93. template <typename ReturnStrategy>
  94. inline static ReturnStrategy::ReturnType
  95. CopyIntoBufferAndAdvanceCursor(
  96. ReturnStrategy &returnStrategy,
  97. TMutableString &rBuffer,
  98. SIZE_T &cchBuffer,
  99. TConstantString szString,
  100. SIZE_T cchIn
  101. )
  102. {
  103. FN_TRACE();
  104. ASSERT((cchBuffer != 0) || (cchIn == 0));
  105. ASSERT((szString != NULL) || (cchIn == 0));
  106. if (cchBuffer != 0)
  107. {
  108. if (szString != NULL)
  109. {
  110. SIZE_T cchToCopy = static_cast<SIZE_T>(cchIn);
  111. // Someone should have stopped this before we got this far.
  112. ASSERT(cchToCopy <= cchBuffer);
  113. // You should not include the null character in the count in
  114. ASSERT((cchToCopy == NULL) || (szString[cchToCopy-1] != NullCharacter()));
  115. if (cchToCopy > cchBuffer)
  116. cchToCopy = cchBuffer;
  117. memcpy(rBuffer, szString, cchToCopy * sizeof(TChar));
  118. rBuffer += cchToCopy;
  119. cchBuffer -= cchToCopy;
  120. }
  121. }
  122. returnStrategy.SetWin32Bool(TRUE);
  123. return returnStrategy.Return();
  124. }
  125. inline static BOOL Win32HashString(TConstantString szString, SIZE_T cchIn, ULONG &rulPseudoKey, bool fCaseInsensitive)
  126. {
  127. BOOL fSuccess = FALSE;
  128. FN_TRACE_WIN32(fSuccess);
  129. IFW32FALSE_EXIT(::FusionpHashUnicodeString(szString, cchIn, &rulPseudoKey, fCaseInsensitive));
  130. fSuccess = TRUE;
  131. Exit:
  132. return fSuccess;
  133. }
  134. // copy into buffer from TChar to TChar
  135. inline static BOOL Win32CopyIntoBufferAndAdvanceCursor(TMutableString &rBuffer, SIZE_T &cchBuffer, TConstantString szString, SIZE_T cchIn)
  136. {
  137. CReturnStrategyBoolLastError f;
  138. return CopyIntoBufferAndAdvanceCursor(f, rBuffer, cchBuffer, szString, cchIn);
  139. }
  140. // copy into buffer from TChar to TChar
  141. inline static HRESULT ComCopyIntoBufferAndAdvanceCursor(TMutableString &rBuffer, SIZE_T &cchBuffer, TConstantString szString, SIZE_T cchIn)
  142. {
  143. CReturnStrategyHresult hr;
  144. return CopyIntoBufferAndAdvanceCursor(hr, rBuffer, cchBuffer, szString, cchIn);
  145. }
  146. // determine characters required for matching type (TChar)
  147. // like strlen but checks for null and optionally can be told the length
  148. template <typename ReturnStrategy>
  149. inline static ReturnStrategy::ReturnType
  150. DetermineRequiredCharacters(
  151. ReturnStrategy &returnStrategy,
  152. TConstantString /* sz */,
  153. SIZE_T cchIn,
  154. SIZE_T &rcch
  155. )
  156. {
  157. rcch = cchIn + 1;
  158. returnStrategy.SetWin32Bool(TRUE);
  159. return returnStrategy.Return();
  160. }
  161. // determine characters required for matching type (TChar)
  162. inline static HRESULT DetermineRequiredCharacters(TConstantString sz, SIZE_T cchIn, SIZE_T &rcch)
  163. {
  164. CReturnStrategyHresult returnStrategy;
  165. return DetermineRequiredCharacters(returnStrategy, sz, cchIn, rcch);
  166. }
  167. // determine characters required for matching type (TChar)
  168. inline static BOOL Win32DetermineRequiredCharacters(TConstantString sz, SIZE_T cchIn, SIZE_T &rcch)
  169. {
  170. CReturnStrategyBoolLastError returnStrategy;
  171. return DetermineRequiredCharacters(returnStrategy, sz, cchIn, rcch);
  172. }
  173. inline static BOOL Win32EqualStrings(bool &rfMatches, PCWSTR psz1, SIZE_T cch1, PCWSTR psz2, SIZE_T cch2, bool fCaseInsensitive)
  174. {
  175. rfMatches = (::FusionpCompareStrings(psz1, cch1, psz2, cch2, fCaseInsensitive) == 0);
  176. return TRUE;
  177. }
  178. inline static BOOL Win32EqualStrings(bool &rfMatches, PCSTR psz1, SIZE_T cch1, PCSTR psz2, SIZE_T cch2, bool fCaseInsensitive)
  179. {
  180. rfMatches = (::FusionpCompareStrings(psz1, cch1, psz2, cch2, fCaseInsensitive) == 0);
  181. return TRUE;
  182. }
  183. inline static BOOL Win32CompareStrings(StringComparisonResult &rscr, PCWSTR psz1, SIZE_T cch1, PCWSTR psz2, SIZE_T cch2, bool fCaseInsensitive)
  184. {
  185. int i = ::FusionpCompareStrings(psz1, cch1, psz2, cch2, fCaseInsensitive);
  186. if (i == 0)
  187. rscr = eEquals;
  188. else if (i < 0)
  189. rscr = eLessThan;
  190. else
  191. rscr = eGreaterThan;
  192. return TRUE;
  193. }
  194. inline static BOOL Win32CompareStrings(StringComparisonResult &rscr, PCSTR psz1, SIZE_T cch1, PCSTR psz2, SIZE_T cch2, bool fCaseInsensitive)
  195. {
  196. int i = ::FusionpCompareStrings(psz1, cch1, psz2, cch2, fCaseInsensitive);
  197. if (i == 0)
  198. rscr = eEquals;
  199. else if (i < 0)
  200. rscr = eLessThan;
  201. else
  202. rscr = eGreaterThan;
  203. return TRUE;
  204. }
  205. inline static int CompareStrings(LCID lcid, DWORD dwCmpFlags, PCWSTR psz1, int cch1, PCWSTR psz2, int cch2)
  206. {
  207. return ::CompareStringW(lcid, dwCmpFlags, psz1, cch1, psz2, cch2);
  208. }
  209. inline static int CompareStrings(LCID lcid, DWORD dwCmpFlags, PCSTR psz1, int cch1, PCSTR psz2, int cch2)
  210. {
  211. return ::CompareStringA(lcid, dwCmpFlags, psz1, cch1, psz2, cch2);
  212. }
  213. inline static int FormatV(PSTR pszBuffer, SIZE_T nBufferSize, PCSTR pszFormat, va_list args)
  214. {
  215. return _vsnprintf(pszBuffer, nBufferSize, pszFormat, args);
  216. }
  217. inline static int FormatV(PWSTR pszBuffer, SIZE_T nBufferSize, PCWSTR pszFormat, va_list args)
  218. {
  219. return _vsnwprintf(pszBuffer, nBufferSize, pszFormat, args);
  220. }
  221. #if 0
  222. inline static BOOL Win32GetRequiredBufferSizeInCharsForFormatV(PCWSTR pszFormat, va_list args, SIZE_T& rcch)
  223. {
  224. FN_PROLOG_WIN32
  225. INT i = 0;
  226. rcch = 0;
  227. if ((i = _vscwprintf(pszFormat, args)) < 0)
  228. ORIGINATE_WIN32_FAILURE_AND_EXIT(_vscwprintf, ERROR_INVALID_PARAMETER);
  229. rcch = static_cast<SIZE_T>(i);
  230. FN_EPILOG
  231. }
  232. inline static BOOL Win32GetRequiredBufferSizeInCharsForFormatV(PCSTR pszFormat, va_list args, SIZE_T& rcch)
  233. {
  234. FN_PROLOG_WIN32
  235. INT i = 0;
  236. rcch = 0;
  237. if ((i = _vscprintf(pszFormat, args)) < 0)
  238. ORIGINATE_WIN32_FAILURE_AND_EXIT(_vscprintf, ERROR_INVALID_PARAMETER);
  239. rcch = static_cast<SIZE_T>(i);
  240. FN_EPILOG
  241. }
  242. #endif
  243. };
  244. class CUnicodeCharTraits : public CCharTraitsBase<WCHAR, CHAR>
  245. {
  246. typedef CUnicodeCharTraits TThis;
  247. typedef CCharTraitsBase<WCHAR, CHAR> Base;
  248. public:
  249. // without using, we end up hiding these by providing equally named functions
  250. using Base::DetermineRequiredCharacters;
  251. using Base::Win32DetermineRequiredCharacters;
  252. using Base::CopyIntoBuffer;
  253. using Base::Win32CopyIntoBuffer;
  254. inline static PCWSTR DotString() { return L"."; }
  255. inline static SIZE_T DotStringCch() { return 1; }
  256. // determine characters required for mismatched type (CHAR -> WCHAR)
  257. template <typename ReturnStrategy>
  258. inline static ReturnStrategy::ReturnType
  259. DetermineRequiredCharacters(
  260. ReturnStrategy &returnStrategy,
  261. PCSTR sz,
  262. SIZE_T cchIn,
  263. SIZE_T &rcch,
  264. UINT cp = CP_THREAD_ACP,
  265. DWORD dwFlags = MB_ERR_INVALID_CHARS
  266. )
  267. {
  268. FN_TRACE();
  269. if (sz != NULL)
  270. {
  271. // For 64-bit, clamp the maximum size passed in to the largest that the INT
  272. // parameter to MultiByteToWideChar() can take.
  273. ASSERT2(cchIn <= INT_MAX, "large parameter clamped");
  274. if (cchIn > INT_MAX)
  275. cchIn = INT_MAX;
  276. INT cch = ::MultiByteToWideChar(cp, dwFlags, sz, static_cast<INT>(cchIn), NULL, 0);
  277. if ((cch == 0) && (cchIn > 0))
  278. {
  279. returnStrategy.SetWin32Bool(FALSE);
  280. goto Exit;
  281. }
  282. rcch = static_cast<SIZE_T>(cch) + 1;
  283. }
  284. else
  285. rcch = 1;
  286. returnStrategy.SetWin32Bool(TRUE);
  287. Exit:
  288. return returnStrategy.Return();
  289. }
  290. inline static BOOL FindCharacter(PCWSTR sz, SIZE_T cch, WCHAR ch, BOOL *pfFound, SIZE_T *pich)
  291. {
  292. BOOL fSuccess = FALSE;
  293. FN_TRACE_WIN32(fSuccess);
  294. // There doesn't seem to be a builtin to do this...
  295. SIZE_T i;
  296. if (pfFound != NULL)
  297. *pfFound = FALSE;
  298. if (pich != NULL)
  299. *pich = 0;
  300. PARAMETER_CHECK((pfFound != NULL) && (pich != NULL));
  301. for (i=0; i<cch; i++)
  302. {
  303. if (sz[i] == ch)
  304. {
  305. *pich = i;
  306. *pfFound = TRUE;
  307. break;
  308. }
  309. }
  310. fSuccess = TRUE;
  311. Exit:
  312. return fSuccess;
  313. }
  314. inline static bool ContainsCharacter(PCWSTR sz, SIZE_T cch, WCHAR ch)
  315. {
  316. SIZE_T i;
  317. for (i=0; i<cch; i++)
  318. {
  319. if (sz[i] == ch)
  320. return true;
  321. }
  322. return false;
  323. }
  324. inline static BOOL Win32ToLower(WCHAR wchToConvert, WCHAR &rwchConverted)
  325. {
  326. rwchConverted = ::FusionpRtlDowncaseUnicodeChar(wchToConvert);
  327. return TRUE;
  328. }
  329. inline static BOOL Win32ToUpper(WCHAR wchToConvert, WCHAR &rwchConverted)
  330. {
  331. rwchConverted = ::FusionpRtlUpcaseUnicodeChar(wchToConvert);
  332. return TRUE;
  333. }
  334. inline static BOOL Win32ReverseFind(PCWSTR &rpchFound, PCWSTR psz, SIZE_T cch, WCHAR wchToFind, bool fCaseInsensitive)
  335. {
  336. BOOL fSuccess = FALSE;
  337. SIZE_T i = 0;
  338. rpchFound = NULL;
  339. if (fCaseInsensitive)
  340. {
  341. // Map the character to its lower case equivalent...
  342. if (!TThis::Win32ToLower(wchToFind, wchToFind))
  343. goto Exit;
  344. for (i=cch; i>0; i--)
  345. {
  346. bool fMatch;
  347. if (!TThis::Win32CompareLowerCaseCharacterToCharCaseInsensitively(fMatch, wchToFind, psz[i - 1]))
  348. goto Exit;
  349. if (fMatch)
  350. break;
  351. }
  352. }
  353. else
  354. {
  355. for (i=cch; i>0; i--)
  356. {
  357. if (psz[i - 1] == wchToFind)
  358. break;
  359. }
  360. }
  361. if (i != 0)
  362. rpchFound = &psz[i - 1];
  363. fSuccess = TRUE;
  364. Exit:
  365. return fSuccess;
  366. }
  367. inline static BOOL Win32CompareLowerCaseCharacterToCharCaseInsensitively(bool &rfMatch, WCHAR wchLowerCase, WCHAR wchCandidate)
  368. {
  369. BOOL fSuccess = FALSE;
  370. rfMatch = false;
  371. if (!TThis::Win32ToLower(wchCandidate, wchCandidate))
  372. goto Exit;
  373. if (wchCandidate == wchLowerCase)
  374. rfMatch = true;
  375. fSuccess = TRUE;
  376. Exit:
  377. return fSuccess;
  378. }
  379. // determine characters required for mismatched type (CHAR -> WCHAR)
  380. inline static HRESULT DetermineRequiredCharacters(PCSTR sz, SIZE_T cchIn, SIZE_T &rcch, UINT cp = CP_THREAD_ACP, DWORD dwFlags = MB_ERR_INVALID_CHARS)
  381. {
  382. CReturnStrategyHresult hr;
  383. return DetermineRequiredCharacters(hr, sz, cchIn, rcch, cp, dwFlags);
  384. }
  385. // determine characters required for mismatched type (CHAR -> WCHAR)
  386. inline static BOOL Win32DetermineRequiredCharacters(PCSTR sz, SIZE_T cchIn, SIZE_T &rcch, UINT cp = CP_THREAD_ACP, DWORD dwFlags = MB_ERR_INVALID_CHARS)
  387. {
  388. CReturnStrategyBoolLastError f;
  389. return DetermineRequiredCharacters(f, sz, cchIn, rcch, cp, dwFlags);
  390. }
  391. inline static SIZE_T NullTerminatedStringLength(PCWSTR sz) { return (sz != NULL) ? ::wcslen(sz) : 0; }
  392. // copy into buffer from CHAR to WCHAR
  393. template <typename ReturnStrategy>
  394. inline static ReturnStrategy::ReturnType
  395. CopyIntoBuffer(
  396. ReturnStrategy &returnStrategy,
  397. WCHAR rgchBuffer[],
  398. SIZE_T cchBuffer,
  399. PCSTR szString,
  400. SIZE_T cchIn,
  401. UINT cp = CP_THREAD_ACP,
  402. DWORD dwFlags = MB_ERR_INVALID_CHARS
  403. )
  404. {
  405. FN_TRACE();
  406. // The caller must be on drugs if they (think that they) have a buffer larger than 2gb, but
  407. // let's at least clamp it so that we don't get a negative int value passed in
  408. // to ::MultiByteToWideChar().
  409. ASSERT2(cchBuffer <= INT_MAX, "large parameter clamped");
  410. if (cchBuffer > INT_MAX)
  411. cchBuffer = INT_MAX;
  412. if (cchBuffer != 0)
  413. {
  414. if (szString != NULL)
  415. {
  416. // It would seem that you could just pass the -1 into MultiByteToWideChar(), but
  417. // you get some errors on the boundary conditions, because -1 implies that you
  418. // want to consider the null termination on the input string, and the output
  419. // string will be null terminated also. Consider the degenerate case of a 2
  420. // character output buffer and an input string that's a single non-null
  421. // character followed by a null character. We're going to trim the size of
  422. // cchBuffer by 1 so that we manually null-terminate in case the input string
  423. // was not null-terminated, so MultiByteToWideChar() just writes a single
  424. // null character to the output buffer since it thinks it must write a null-
  425. // terminated string.
  426. //
  427. // Instead, we'll just always pass in an exact length, not including the null character
  428. // in the input, and we'll always put the null in place after the conversion succeeds.
  429. //
  430. // (this comment is mostly outdated - 11/24/2000 - but the discussion of how the
  431. // MultiByteToWideChar() API works is worth keeping -mgrier)
  432. // Since MultiByteToWideChar() takes an "int" length, clamp the maximum
  433. // value we pass in to 2gb.
  434. ASSERT2(cchIn <= INT_MAX, "large parameter clamped");
  435. if (cchIn > INT_MAX)
  436. cchIn = INT_MAX;
  437. INT cch = ::MultiByteToWideChar(cp, dwFlags, szString, static_cast<INT>(cchIn), rgchBuffer, static_cast<INT>(cchBuffer) - 1);
  438. if ((cch == 0) && (cchBuffer > 1))
  439. {
  440. returnStrategy.SetWin32Bool(FALSE);
  441. goto Exit;
  442. }
  443. rgchBuffer[cch] = NullCharacter();
  444. }
  445. else
  446. rgchBuffer[0] = NullCharacter();
  447. }
  448. returnStrategy.SetWin32Bool(TRUE);
  449. Exit:
  450. return returnStrategy.Return();
  451. }
  452. // copy into buffer from CHAR to WCHAR
  453. inline static BOOL Win32CopyIntoBuffer(WCHAR rgchBuffer[], SIZE_T cchBuffer, PCSTR szString, SIZE_T cchIn, UINT cp = CP_THREAD_ACP, DWORD dwFlags = MB_ERR_INVALID_CHARS)
  454. {
  455. CReturnStrategyBoolLastError f;
  456. return CopyIntoBuffer(f, rgchBuffer, cchBuffer, szString, cchIn, cp, dwFlags);
  457. }
  458. // copy into buffer from CHAR to WCHAR
  459. inline static HRESULT CopyIntoBuffer(WCHAR rgchBuffer[], SIZE_T cchBuffer, PCSTR szString, SIZE_T cchIn, UINT cp = CP_THREAD_ACP, DWORD dwFlags = MB_ERR_INVALID_CHARS)
  460. {
  461. CReturnStrategyHresult hr;
  462. return CopyIntoBuffer(hr, rgchBuffer, cchBuffer, szString, cchIn, cp, dwFlags);
  463. }
  464. inline static SIZE_T Cch(PCWSTR psz) { return (psz != NULL) ? ::wcslen(psz) : 0; }
  465. };
  466. template <UINT cp = CP_THREAD_ACP> class CMBCSCharTraits : public CCharTraitsBase<CHAR, WCHAR>
  467. {
  468. private:
  469. typedef CCharTraitsBase<CHAR, WCHAR> Base;
  470. public:
  471. typedef CHAR TChar;
  472. typedef LPSTR TMutableString;
  473. typedef PCSTR TConstantString;
  474. typedef CUnicodeCharTraits TOtherTraits;
  475. typedef TOtherTraits::TOtherChar TOtherChar;
  476. typedef TOtherTraits::TOtherString TOtherString;
  477. typedef TOtherTraits::TConstantString TOtherConstantString;
  478. inline static PCSTR DotString() { return "."; }
  479. inline static SIZE_T DotStringCch() { return 1; }
  480. // without using, we end up hiding these by providing equally named functions
  481. using Base::DetermineRequiredCharacters;
  482. using Base::Win32DetermineRequiredCharacters;
  483. using Base::CopyIntoBuffer;
  484. using Base::Win32CopyIntoBuffer;
  485. // determine characters required for mismatched type (WCHAR -> CHAR)
  486. template <typename ReturnStrategy>
  487. inline static ReturnStrategy::ReturnType
  488. DetermineRequiredCharacters(
  489. ReturnStrategy &returnStrategy,
  490. PCWSTR sz,
  491. SIZE_T cchIn,
  492. SIZE_T &rcch,
  493. DWORD dwFlags = 0,
  494. PCSTR pszDefaultChar = NULL,
  495. LPBOOL lpUsedDefaultChar = NULL
  496. )
  497. {
  498. if (sz != NULL)
  499. {
  500. ASSERT2(cchIn <= INT_MAX, "large parameter clamped");
  501. ASSERT(cchIn <= INT_MAX);
  502. if (cchIn > INT_MAX)
  503. cchIn = INT_MAX;
  504. INT cch = ::WideCharToMultiByte(cp, dwFlags, sz, static_cast<INT>(cchIn), NULL, 0, pszDefaultChar, lpUsedDefaultChar);
  505. if ((cch == 0) && (cchIn > 0))
  506. {
  507. returnStrategy.SetWin32Bool(FALSE);
  508. goto Exit;
  509. }
  510. rcch = static_cast<SIZE_T>(cch) + 1;
  511. } else
  512. rcch = 1;
  513. returnStrategy.SetWin32Bool(TRUE);
  514. Exit:
  515. return returnStrategy.Return();
  516. }
  517. inline static SIZE_T NullTerminatedStringLength(PCSTR sz) { return ::strlen(sz); }
  518. // determine characters required for mismatched type (WCHAR -> CHAR)
  519. inline static BOOL Win32DetermineRequiredCharacters(PCWSTR sz, SIZE_T cchIn, SIZE_T &rcch, DWORD dwFlags = 0, PCSTR pszDefaultChar = NULL, LPBOOL lpUsedDefaultChar = NULL)
  520. {
  521. CReturnStrategyBoolLastError f;
  522. return DetermineRequiredCharacters(f, sz, cchIn, rcch, dwFlags, pszDefaultChar, lpUsedDefaultChar);
  523. }
  524. // determine characters required for mismatched type (WCHAR -> CHAR)
  525. inline static HRESULT DetermineRequiredCharacters(PCWSTR sz, SIZE_T cchIn, SIZE_T &rcch, DWORD dwFlags = 0, PCSTR pszDefaultChar = NULL, LPBOOL lpUsedDefaultChar = NULL)
  526. {
  527. CReturnStrategyHresult hr;
  528. return DetermineRequiredCharacters(hr, sz, cchIn, rcch, dwFlags, pszDefaultChar, lpUsedDefaultChar);
  529. }
  530. // copy into buffer from WCHAR to CHAR
  531. template <typename ReturnStrategy>
  532. inline static ReturnStrategy::ReturnType
  533. CopyIntoBuffer(
  534. ReturnStrategy &returnStrategy,
  535. CHAR rgchBuffer[],
  536. SIZE_T cchBuffer,
  537. PCWSTR szString,
  538. SIZE_T cchIn,
  539. DWORD dwFlags = 0,
  540. PCSTR pszDefaultChar = NULL,
  541. LPBOOL lpUsedDefaultChar = NULL
  542. )
  543. {
  544. if (cchBuffer != 0)
  545. {
  546. // Clamp the maximum buffer size to maxint, since the buffer size passed in to
  547. // WideCharToMultiByte() is an INT rather than a SIZE_T or INT_PTR etc.
  548. // After all, who's really going to have a buffer size > 2gb? The caller
  549. // probably just messed up.
  550. ASSERT2(cchBuffer <= INT_MAX, "large parameter clamped");
  551. if (cchBuffer > INT_MAX)
  552. cchBuffer = INT_MAX;
  553. if (szString != NULL)
  554. {
  555. // It would seem that you could just pass the -1 into MultiByteToWideChar(), but
  556. // you get some errors on the boundary conditions, because -1 implies that you
  557. // want to consider the null termination on the input string, and the output
  558. // string will be null terminated also. Consider the degenerate case of a 2
  559. // character output buffer and an input string that's a single non-null
  560. // character followed by a null character. We're going to trim the size of
  561. // cchBuffer by 1 so that we manually null-terminate in case the input string
  562. // was not null-terminated, so MultiByteToWideChar() just writes a single
  563. // null character to the output buffer since it thinks it must write a null-
  564. // terminated string.
  565. //
  566. // Instead, we'll just always pass in an exact length, not including the null character
  567. // in the input, and we'll always put the null in place after the conversion succeeds.
  568. //
  569. ASSERT2(cchIn <= INT_MAX, "large parameter clamped");
  570. if (cchIn > INT_MAX)
  571. cchIn = INT_MAX;
  572. INT cch = ::WideCharToMultiByte(cp, dwFlags, szString, static_cast<INT>(cchIn), rgchBuffer, static_cast<INT>(cchBuffer - 1), pszDefaultChar, lpUsedDefaultChar);
  573. if ((cch == 0) && (cchBuffer > 1))
  574. {
  575. returnStrategy.SetWin32Bool(FALSE);
  576. goto Exit;
  577. }
  578. rgchBuffer[cch] = NullCharacter();
  579. }
  580. else
  581. rgchBuffer[0] = NullCharacter();
  582. }
  583. returnStrategy.SetWin32Bool(TRUE);
  584. Exit:
  585. return returnStrategy.Return();
  586. }
  587. // copy into buffer from WCHAR to CHAR
  588. inline static HRESULT CopyIntoBuffer(CHAR rgchBuffer[], SIZE_T cchBuffer, PCWSTR szString, SIZE_T cchIn, DWORD dwFlags = 0, PCSTR pszDefaultChar = NULL, LPBOOL lpUsedDefaultChar = NULL)
  589. {
  590. CReturnStrategyHresult hr;
  591. return CopyIntoBuffer(hr, rgchBuffer, cchBuffer, szString, cchIn, dwFlags, pszDefaultChar, lpUsedDefaultChar);
  592. }
  593. // copy into buffer from WCHAR to CHAR
  594. inline static BOOL Win32CopyIntoBuffer(CHAR rgchBuffer[], SIZE_T cchBuffer, PCWSTR szString, SIZE_T cchIn, DWORD dwFlags = 0, PCSTR pszDefaultChar = NULL, LPBOOL lpUsedDefaultChar = NULL)
  595. {
  596. CReturnStrategyBoolLastError f;
  597. return CopyIntoBuffer(f, rgchBuffer, cchBuffer, szString, cchIn, dwFlags, pszDefaultChar, lpUsedDefaultChar);
  598. }
  599. inline static SIZE_T Cch(PCSTR psz) { return ::strlen(psz); }
  600. };
  601. typedef CMBCSCharTraits<CP_THREAD_ACP> CANSICharTraits;
  602. #endif