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.

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