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.

890 lines
28 KiB

  1. #if !defined(_BCL_W32UNICODESTRINGALGORITHMS_H_INCLUDED_)
  2. #define _BCL_W32UNICODESTRINGALGORITHMS_H_INCLUDED_
  3. #pragma once
  4. /*++
  5. Copyright (c) 2000 Microsoft Corporation
  6. Module Name:
  7. bcl_w32unicodestringalgorithms.h
  8. Abstract:
  9. Author:
  10. Michael Grier (MGrier) 2/6/2002
  11. Revision History:
  12. --*/
  13. #include <windows.h>
  14. #include <bcl_inlinestring.h>
  15. #include <bcl_unicodechartraits.h>
  16. #include <bcl_w32common.h>
  17. #include <bcl_vararg.h>
  18. #include <limits.h>
  19. namespace BCL
  20. {
  21. template <typename TBuffer, typename TCallDispositionT>
  22. class CWin32NullTerminatedUnicodeStringAlgorithms
  23. {
  24. public:
  25. typedef CWin32NullTerminatedUnicodeStringAlgorithms TThis;
  26. typedef TCallDispositionT TCallDisposition;
  27. typedef CWin32StringComparisonResult TComparisonResult;
  28. typedef BCL::CConstantPointerAndCountPair<WCHAR, SIZE_T> TConstantPair;
  29. typedef BCL::CMutablePointerAndCountPair<WCHAR, SIZE_T> TMutablePair;
  30. typedef CWin32CaseInsensitivityData TCaseInsensitivityData;
  31. typedef SIZE_T TSizeT;
  32. typedef CWin32MBCSToUnicodeDataIn TDecodingDataIn;
  33. typedef CWin32MBCSToUnicodeDataOut TDecodingDataOut;
  34. typedef CWin32UnicodeToMBCSDataIn TEncodingDataIn;
  35. typedef CWin32UnicodeToMBCSDataOut TEncodingDataOut;
  36. typedef CConstantPointerAndCountPair<CHAR, SIZE_T> TConstantNonNativePair;
  37. typedef CMutablePointerAndCountPair<CHAR, SIZE_T> TMutableNonNativePair;
  38. typedef PSTR TMutableNonNativeString;
  39. typedef PCSTR TConstantNonNativeString;
  40. typedef PWSTR TMutableString;
  41. typedef PCWSTR TConstantString;
  42. static inline void _fastcall SetStringCch(BCL::CBaseString *p, SIZE_T cch)
  43. {
  44. BCL_ASSERT((cch == 0) || (cch < TBuffer::TTraits::GetBufferCch(p)));
  45. static_cast<TBuffer *>(p)->m_cchString = cch;
  46. if (TBuffer::TTraits::GetBufferCch(p) != 0)
  47. TBuffer::TTraits::GetMutableBufferPtr(p)[cch] = L'\0';
  48. }
  49. static inline TCallDisposition __fastcall MapStringCchToBufferCch(SIZE_T cchString, SIZE_T &rcchRequired)
  50. {
  51. SIZE_T cchRequired = cchString + 1;
  52. if (cchRequired == 0)
  53. return TCallDisposition::ArithmeticOverflow();
  54. rcchRequired = cchRequired;
  55. return TCallDisposition::Success();
  56. }
  57. static inline TCallDisposition __fastcall MapBufferCchToStringCch(SIZE_T cchBuffer, SIZE_T &rcchString)
  58. {
  59. if (cchBuffer == 0)
  60. rcchString = 0;
  61. else
  62. rcchString = cchBuffer - 1;
  63. return TCallDisposition::Success();
  64. }
  65. static inline TCallDisposition __fastcall IsCharLegalLeadChar(WCHAR wch, bool &rfIsLegal)
  66. {
  67. BCL_MAYFAIL_PROLOG
  68. // fast common path out for ASCII; there are no combining characters in this range
  69. if (wch <= 0x007f)
  70. rfIsLegal = true;
  71. else
  72. {
  73. // low surrogate
  74. if ((wch >= 0xdc00) && (wch <= 0xdfff))
  75. rfIsLegal = false;
  76. else
  77. {
  78. WORD wCharType = 0;
  79. if (!::GetStringTypeExW(LOCALE_INVARIANT, CT_CTYPE3, &wch, 1, &wCharType))
  80. BCL_ORIGINATE_ERROR(TCallDisposition::FromLastError());
  81. // If it's not one of these types of nonspacing marks
  82. rfIsLegal = ((wCharType & (C3_NONSPACING | C3_DIACRITIC | C3_VOWELMARK)) == 0);
  83. }
  84. }
  85. BCL_MAYFAIL_EPILOG_INTERNAL
  86. }
  87. static inline TCallDisposition __fastcall UpperCase(BCL::CBaseString *p, const CWin32CaseInsensitivityData &rcid)
  88. {
  89. BCL_MAYFAIL_PROLOG
  90. BCL_PARAMETER_CHECK(TBuffer::TTraits::GetStringCch(p) <= INT_MAX);
  91. // LCMapStringW() seems to be nice and allow for in-place case changing...
  92. int iResult =
  93. ::LCMapStringW(
  94. rcid.m_lcid,
  95. (rcid.m_dwCmpFlags & ~(NORM_IGNORECASE)) | LCMAP_UPPERCASE,
  96. TBuffer::TTraits::GetBufferPtr(p),
  97. static_cast<INT>(TBuffer::TTraits::GetStringCch(p)),
  98. TBuffer::TTraits::GetMutableBufferPtr(p),
  99. static_cast<INT>(TBuffer::TTraits::GetStringCch(p)));
  100. if (iResult == 0)
  101. return TCallDisposition::FromLastError();
  102. BCL_INTERNAL_ERROR_CHECK(iResult == static_cast<INT>(TBuffer::TTraits::GetStringCch(p)));
  103. BCL_MAYFAIL_EPILOG_INTERNAL
  104. }
  105. static inline TCallDisposition __fastcall LowerCase(BCL::CBaseString *p, const CWin32CaseInsensitivityData &rcid)
  106. {
  107. BCL_MAYFAIL_PROLOG
  108. BCL_PARAMETER_CHECK(TBuffer::TTraits::GetStringCch(p) <= INT_MAX);
  109. // LCMapStringW() seems to be nice and allow for in-place case changing...
  110. int iResult =
  111. ::LCMapStringW(
  112. rcid.m_lcid,
  113. (rcid.m_dwCmpFlags & ~(NORM_IGNORECASE)) | LCMAP_LOWERCASE,
  114. TBuffer::TTraits::GetBufferPtr(p),
  115. static_cast<INT>(TBuffer::TTraits::GetStringCch(p)),
  116. TBuffer::TTraits::GetMutableBufferPtr(p),
  117. static_cast<INT>(TBuffer::TTraits::GetStringCch(p)));
  118. if (iResult == 0)
  119. return TCallDisposition::FromLastError();
  120. BCL_INTERNAL_ERROR_CHECK(iResult == static_cast<INT>(TBuffer::TTraits::GetStringCch(p)));
  121. BCL_MAYFAIL_EPILOG_INTERNAL
  122. }
  123. template <typename TSomeInputType1, typename TSomeInputType2>
  124. static inline TCallDisposition __fastcall
  125. EqualStringsI(
  126. const TSomeInputType1 &rinput1,
  127. const TSomeInputType2 &rinput2,
  128. const CWin32CaseInsensitivityData &rcid,
  129. bool &rfMatches
  130. )
  131. {
  132. BCL_MAYFAIL_PROLOG
  133. rfMatches = false;
  134. BCL_PARAMETER_CHECK(TBuffer::TTraits::GetInputCch(rinput1) <= INT_MAX);
  135. BCL_PARAMETER_CHECK(TBuffer::TTraits::GetInputCch(rinput2) <= INT_MAX);
  136. int i = ::CompareStringW(
  137. rcid.m_lcid,
  138. rcid.m_dwCmpFlags,
  139. TBuffer::TTraits::GetInputPtr(rinput1),
  140. static_cast<INT>(TBuffer::TTraits::GetInputCch(rinput1)),
  141. TBuffer::TTraits::GetInputPtr(rinput2),
  142. static_cast<INT>(TBuffer::TTraits::GetInputCch(rinput2)));
  143. if (i == 0)
  144. BCL_ORIGINATE_ERROR(TCallDisposition::FromLastError());
  145. rfMatches = (i == CSTR_EQUAL);
  146. BCL_MAYFAIL_EPILOG_INTERNAL
  147. }
  148. template <typename TSomeInputType1, typename TSomeInputType2>
  149. static inline TCallDisposition __fastcall CompareStringsI(
  150. const TSomeInputType1 &rinput1,
  151. const TSomeInputType2 &rinput2,
  152. const CWin32CaseInsensitivityData &rcid,
  153. TComparisonResult &rcr
  154. )
  155. {
  156. BCL_MAYFAIL_PROLOG
  157. BCL_PARAMETER_CHECK(TBuffer::TTraits::GetInputCch(rinput1) <= INT_MAX);
  158. BCL_PARAMETER_CHECK(TBuffer::TTraits::GetInputCch(rinput2) <= INT_MAX);
  159. int i = ::CompareStringW(
  160. rcid.m_lcid,
  161. rcid.m_dwCmpFlags,
  162. TBuffer::TTraits::GetInputPtr(rinput1),
  163. static_cast<INT>(TBuffer::TTraits::GetInputCch(rinput1)),
  164. TBuffer::TTraits::GetInputPtr(rinput2),
  165. static_cast<INT>(TBuffer::TTraits::GetInputCch(rinput2)));
  166. if (i == 0)
  167. BCL_ORIGINATE_ERROR(TCallDisposition::FromLastError());
  168. if (i == CSTR_LESS_THAN)
  169. rcr.SetLessThan();
  170. else if (i == CSTR_EQUAL)
  171. rcr.SetEqualTo();
  172. else
  173. {
  174. BCL_INTERNAL_ERROR_CHECK(i == CSTR_GREATER_THAN);
  175. rcr.SetGreaterThan();
  176. }
  177. BCL_MAYFAIL_EPILOG_INTERNAL
  178. }
  179. template <typename TSomeCharacterMatcher>
  180. inline
  181. static
  182. TCallDisposition
  183. ContainsI(
  184. const TConstantPair &rpair,
  185. const TSomeCharacterMatcher &rscm,
  186. const CWin32CaseInsensitivityData &rcid,
  187. bool &rfFound
  188. )
  189. {
  190. BCL_MAYFAIL_PROLOG
  191. rfFound = false;
  192. BCL_PARAMETER_CHECK(rpair.Valid());
  193. SIZE_T cch = rpair.GetCount();
  194. SIZE_T i;
  195. const WCHAR *prgch = rpair.GetPointer();
  196. for (i=0; i<cch; )
  197. {
  198. SIZE_T cchConsumed = 0;
  199. bool fMatch = false;
  200. BCL_IFCALLFAILED_EXIT(rscm.MatchI(rcid, prgch, cchConsumed, fMatch));
  201. BCL_INTERNAL_ERROR_CHECK(cchConsumed != 0);
  202. if (fMatch)
  203. break;
  204. BCL_IFCALLFAILED_EXIT(TBuffer::TTraits::AddWithOverflowCheck(i, cchConsumed, i));
  205. }
  206. if (i != cch)
  207. rfFound = true;
  208. BCL_MAYFAIL_EPILOG_INTERNAL
  209. }
  210. inline
  211. static
  212. TCallDisposition
  213. ContainsI(
  214. const TConstantPair &rpair,
  215. WCHAR ch,
  216. const CWin32CaseInsensitivityData &rcid,
  217. bool &rfFound
  218. )
  219. {
  220. BCL_MAYFAIL_PROLOG
  221. rfFound = false;
  222. BCL_PARAMETER_CHECK(rpair.Valid());
  223. SIZE_T cch = rpair.GetCount();
  224. SIZE_T i;
  225. const WCHAR *prgch = rpair.GetPointer();
  226. for (i=0; i<cch; i++)
  227. {
  228. int iResult = ::CompareStringW(rcid.m_lcid, rcid.m_dwCmpFlags, prgch++, 1, &ch, 1);
  229. if (iResult == 0)
  230. return TCallDisposition::FromLastError();
  231. if (iResult == CSTR_EQUAL)
  232. break;
  233. }
  234. if (i != cch)
  235. rfFound = true;
  236. BCL_MAYFAIL_EPILOG_INTERNAL
  237. }
  238. inline
  239. static
  240. TCallDisposition
  241. ContainsI(
  242. const TConstantPair &rpair,
  243. const TConstantPair &rpairCandidate,
  244. const CWin32CaseInsensitivityData &rcid,
  245. bool &rfFound
  246. )
  247. {
  248. BCL_MAYFAIL_PROLOG
  249. rfFound = false;
  250. BCL_PARAMETER_CHECK(rpair.Valid());
  251. BCL_PARAMETER_CHECK(rpairCandidate.Valid());
  252. SIZE_T cchCandidate = rpairCandidate.GetCount();
  253. const WCHAR *prgwchCandidate = rpairCandidate.GetPointer();
  254. BCL_PARAMETER_CHECK(cchCandidate <= INT_MAX);
  255. if (cchCandidate == 0)
  256. {
  257. // The null string is in every string
  258. rfFound = true;
  259. }
  260. else
  261. {
  262. SIZE_T cch = rpair.GetCount();
  263. SIZE_T i;
  264. const WCHAR *prgch = rpair.GetPointer();
  265. // This is a dismal implementation of this kind of search but
  266. // I don't know if there's a lot you can do with neato algorithms
  267. // while keeping the case insensitivity a black box inside of
  268. // CompareStringW(). -mgrier 2/3/2002
  269. for (i=0; i<cch; i++)
  270. {
  271. int iResult = ::CompareStringW(
  272. rcid.m_lcid,
  273. rcid.m_dwCmpFlags,
  274. prgch,
  275. static_cast<INT>(cchCandidate),
  276. prgwchCandidate,
  277. static_cast<INT>(cchCandidate));
  278. if (iResult == 0)
  279. return TCallDisposition::FromLastError();
  280. if (iResult == CSTR_EQUAL)
  281. {
  282. rfFound = true;
  283. break;
  284. }
  285. const WCHAR wch = *prgch++;
  286. // Skip ahead an additional character if this is a surrogate
  287. if ((wch >= 0xd800) && (wch <= 0xdbff))
  288. {
  289. i++;
  290. prgch++;
  291. }
  292. }
  293. }
  294. BCL_MAYFAIL_EPILOG_INTERNAL
  295. }
  296. inline
  297. static
  298. TCallDisposition
  299. __fastcall
  300. FindFirstI(
  301. const TConstantPair &rpair,
  302. WCHAR ch,
  303. const CWin32CaseInsensitivityData &rcid,
  304. SIZE_T &rich
  305. )
  306. {
  307. BCL_MAYFAIL_PROLOG
  308. BCL_PARAMETER_CHECK(rpair.Valid());
  309. SIZE_T cch = rpair.GetCount();
  310. SIZE_T i;
  311. const WCHAR *prgch = rpair.GetPointer();
  312. for (i=0; i<cch; i++)
  313. {
  314. int iResult = ::CompareStringW(rcid.m_lcid, rcid.m_dwCmpFlags, prgch++, 1, &ch, 1);
  315. if (iResult == 0)
  316. return TCallDisposition::FromLastError();
  317. if (iResult == CSTR_EQUAL)
  318. break;
  319. }
  320. rich = i;
  321. BCL_MAYFAIL_EPILOG_INTERNAL
  322. }
  323. inline
  324. static
  325. TCallDisposition
  326. FindFirstI(
  327. const TConstantPair &rpair,
  328. const TConstantPair &rpairCandidate,
  329. const CWin32CaseInsensitivityData &rcid,
  330. SIZE_T &richFound
  331. )
  332. {
  333. BCL_MAYFAIL_PROLOG
  334. SIZE_T cch = rpair.GetCount();
  335. richFound = cch;
  336. BCL_PARAMETER_CHECK(rpair.Valid());
  337. BCL_PARAMETER_CHECK(rpairCandidate.Valid());
  338. SIZE_T cchCandidate = rpairCandidate.GetCount();
  339. const WCHAR *prgwchCandidate = rpairCandidate.GetPointer();
  340. BCL_PARAMETER_CHECK(cchCandidate <= INT_MAX);
  341. if (cchCandidate == 0)
  342. {
  343. // The null string is in every string
  344. richFound = cch;
  345. }
  346. else
  347. {
  348. SIZE_T i;
  349. const WCHAR *prgch = rpair.GetPointer();
  350. // This is a dismal implementation of this kind of search but
  351. // I don't know if there's a lot you can do with neato algorithms
  352. // while keeping the case insensitivity a black box inside of
  353. // CompareStringW(). -mgrier 2/3/2002
  354. for (i=0; i<cch; i++)
  355. {
  356. int iResult = ::CompareStringW(
  357. rcid.m_lcid,
  358. rcid.m_dwCmpFlags,
  359. prgch,
  360. static_cast<INT>(cchCandidate),
  361. prgwchCandidate,
  362. static_cast<INT>(cchCandidate));
  363. if (iResult == 0)
  364. return TCallDisposition::FromLastError();
  365. if (iResult == CSTR_EQUAL)
  366. {
  367. richFound = i;
  368. break;
  369. }
  370. const WCHAR wch = *prgch++;
  371. // Skip ahead an additional character if this is a surrogate
  372. if ((wch >= 0xd800) && (wch <= 0xdbff))
  373. {
  374. i++;
  375. prgch++;
  376. }
  377. }
  378. }
  379. BCL_MAYFAIL_EPILOG_INTERNAL
  380. }
  381. inline
  382. static
  383. TCallDisposition
  384. __fastcall
  385. FindLastI(
  386. const TConstantPair &rpair,
  387. WCHAR ch,
  388. const CWin32CaseInsensitivityData &rcid,
  389. SIZE_T &richFound
  390. )
  391. {
  392. BCL_MAYFAIL_PROLOG
  393. SIZE_T i;
  394. SIZE_T cch = rpair.GetCount();
  395. const WCHAR *prgwch = rpair.GetPointer() + cch;
  396. richFound = cch;
  397. for (i=cch; i>0; i--)
  398. {
  399. int iResult = ::CompareStringW(rcid.m_lcid, rcid.m_dwCmpFlags, --prgwch, 1, &ch, 1);
  400. if (iResult == 0)
  401. return TCallDisposition::FromLastError();
  402. if (iResult == CSTR_EQUAL)
  403. break;
  404. }
  405. if (i == 0)
  406. richFound = cch;
  407. else
  408. richFound = i - 1;
  409. BCL_MAYFAIL_EPILOG_INTERNAL
  410. }
  411. inline
  412. static
  413. TCallDisposition
  414. FindLastI(
  415. const TConstantPair &rpair,
  416. const TConstantPair &rpairCandidate,
  417. const CWin32CaseInsensitivityData &rcid,
  418. SIZE_T &richFound
  419. )
  420. {
  421. BCL_MAYFAIL_PROLOG
  422. SIZE_T cch = rpair.GetCount();
  423. richFound = cch;
  424. BCL_PARAMETER_CHECK(rpair.Valid());
  425. BCL_PARAMETER_CHECK(rpairCandidate.Valid());
  426. SIZE_T cchCandidate = rpairCandidate.GetCount();
  427. const WCHAR *prgwchCandidate = rpairCandidate.GetPointer();
  428. BCL_PARAMETER_CHECK(cchCandidate <= INT_MAX);
  429. if (cchCandidate == 0)
  430. {
  431. // The null string is in every string
  432. richFound = cch;
  433. }
  434. else
  435. {
  436. // We can't even short circuit out of here just because the candidate string
  437. // is longer than the target string because we don't know what kind of
  438. // case folding magic NLS is doing for us behind the scenes based on
  439. // the case insensitivity data's dwCmpFlags.
  440. SIZE_T i;
  441. const WCHAR *prgch = rpair.GetPointer();
  442. // This is a dismal implementation of this kind of search but
  443. // I don't know if there's a lot you can do with neato algorithms
  444. // while keeping the case insensitivity a black box inside of
  445. // CompareStringW(). -mgrier 2/3/2002
  446. for (i=0; i<cch; i++)
  447. {
  448. int iResult = ::CompareStringW(
  449. rcid.m_lcid,
  450. rcid.m_dwCmpFlags,
  451. prgch,
  452. static_cast<INT>(cchCandidate),
  453. prgwchCandidate,
  454. static_cast<INT>(cchCandidate));
  455. if (iResult == 0)
  456. return TCallDisposition::FromLastError();
  457. if (iResult == CSTR_EQUAL)
  458. {
  459. richFound = i;
  460. // keep looking in case there's another
  461. }
  462. const WCHAR wch = *prgch++;
  463. // Skip ahead an additional character if this is a surrogate
  464. if ((wch >= 0xd800) && (wch <= 0xdbff))
  465. {
  466. i++;
  467. prgch++;
  468. }
  469. }
  470. }
  471. BCL_MAYFAIL_EPILOG_INTERNAL
  472. }
  473. static inline TCallDisposition __fastcall SpanI(const TConstantPair &rpairBuffer, const TConstantPair &rpairSet, const CWin32CaseInsensitivityData &rcid, SIZE_T &rich)
  474. {
  475. BCL_MAYFAIL_PROLOG
  476. SIZE_T i;
  477. SIZE_T cchBuffer = rpairBuffer.GetCount();
  478. const WCHAR *prgwchBuffer = rpairBuffer.GetPointer();
  479. bool fFound;
  480. // This does not handle surrogates correctly
  481. for (i=0; i<cchBuffer; i++)
  482. {
  483. BCL_IFCALLFAILED_EXIT(TBuffer::TTraits::ContainsI(rpairSet, prgwchBuffer[i], rcid, fFound));
  484. if (!fFound)
  485. break;
  486. }
  487. rich = i;
  488. BCL_MAYFAIL_EPILOG_INTERNAL
  489. }
  490. static inline TCallDisposition __fastcall ComplementSpanI(const TConstantPair &rpairBuffer, const TConstantPair &rpairSet, const CWin32CaseInsensitivityData &rcid, SIZE_T &rich)
  491. {
  492. BCL_MAYFAIL_PROLOG
  493. SIZE_T i;
  494. SIZE_T cchBuffer = rpairBuffer.GetCount();
  495. const WCHAR *prgwchBuffer = rpairBuffer.GetPointer();
  496. bool fFound;
  497. // This does not handle surrogates correctly
  498. for (i=0; i<cchBuffer; i++)
  499. {
  500. BCL_IFCALLFAILED_EXIT(TBuffer::TTraits::ContainsI(rpairSet, prgwchBuffer[i], rcid, fFound));
  501. if (fFound)
  502. break;
  503. }
  504. rich = i;
  505. BCL_MAYFAIL_EPILOG_INTERNAL
  506. }
  507. static inline TCallDisposition __fastcall ReverseSpanI(const TConstantPair &rpairBuffer, const TConstantPair &rpairSet, const CWin32CaseInsensitivityData &rcid, SIZE_T &rich)
  508. {
  509. BCL_MAYFAIL_PROLOG
  510. SIZE_T i;
  511. SIZE_T cchBuffer = rpairBuffer.GetCount();
  512. const WCHAR *prgwchBuffer = rpairBuffer.GetPointer();
  513. bool fFound;
  514. // This does not handle surrogates correctly
  515. for (i=cchBuffer; i>0; i--)
  516. {
  517. BCL_IFCALLFAILED_EXIT(TBuffer::TTraits::ContainsI(rpairSet, prgwchBuffer[i-1], rcid, fFound));
  518. if (!fFound)
  519. break;
  520. }
  521. rich = i;
  522. BCL_MAYFAIL_EPILOG_INTERNAL
  523. }
  524. static inline TCallDisposition __fastcall ReverseComplementSpanI(const TConstantPair &rpairBuffer, const TConstantPair &rpairSet, const CWin32CaseInsensitivityData &rcid, SIZE_T &rich)
  525. {
  526. BCL_MAYFAIL_PROLOG
  527. SIZE_T i;
  528. SIZE_T cchBuffer = rpairBuffer.GetCount();
  529. const WCHAR *prgwchBuffer = rpairBuffer.GetPointer();
  530. bool fFound;
  531. // This does not handle surrogates correctly
  532. for (i=cchBuffer; i>0; i--)
  533. {
  534. BCL_IFCALLFAILED_EXIT(TBuffer::TTraits::ContainsI(rpairSet, prgwchBuffer[i], rcid, fFound));
  535. if (fFound)
  536. break;
  537. }
  538. rich = i;
  539. BCL_MAYFAIL_EPILOG_INTERNAL
  540. }
  541. static inline TCallDisposition
  542. DetermineRequiredCharacters(
  543. const CWin32MBCSToUnicodeDataIn &rddi,
  544. const TConstantNonNativePair &rpair,
  545. CWin32MBCSToUnicodeDataOut &rddo,
  546. SIZE_T &rcch
  547. )
  548. {
  549. BCL_MAYFAIL_PROLOG
  550. BCL_PARAMETER_CHECK(rpair.GetCount() <= INT_MAX); // limitation imposed by MultiByteToWideChar API
  551. int iResult = ::MultiByteToWideChar(
  552. rddi.m_CodePage,
  553. rddi.m_dwFlags | MB_ERR_INVALID_CHARS,
  554. rpair.GetPointer(),
  555. static_cast<INT>(rpair.GetCount()),
  556. NULL,
  557. 0);
  558. if (iResult == 0)
  559. BCL_ORIGINATE_ERROR(TCallDisposition::FromLastError());
  560. BCL_INTERNAL_ERROR_CHECK(iResult > 0); // I don't know why MultiByteToWide char would return negative but let's make sure
  561. rcch = iResult;
  562. BCL_MAYFAIL_EPILOG_INTERNAL
  563. }
  564. static inline TCallDisposition
  565. CopyIntoBuffer(
  566. const TMutablePair &rpairOut,
  567. const CWin32MBCSToUnicodeDataIn &rddi,
  568. const TConstantNonNativePair &rpairIn,
  569. CWin32MBCSToUnicodeDataOut &rddo
  570. )
  571. {
  572. BCL_MAYFAIL_PROLOG
  573. BCL_PARAMETER_CHECK(rpairIn.GetCount() <= INT_MAX); // limitation imposed by MultiByteToWideChar API
  574. BCL_PARAMETER_CHECK(rpairOut.GetCount() <= INT_MAX); // might make sense to just clamp at INT_MAX but at least we fail correctly instead of silent truncation
  575. int iResult = ::MultiByteToWideChar(
  576. rddi.m_CodePage,
  577. rddi.m_dwFlags | MB_ERR_INVALID_CHARS,
  578. rpairIn.GetPointer(),
  579. static_cast<INT>(rpairIn.GetCount()),
  580. rpairOut.GetPointer(),
  581. static_cast<INT>(rpairOut.GetCount()));
  582. if (iResult == 0)
  583. return TCallDisposition::FromLastError();
  584. BCL_INTERNAL_ERROR_CHECK(iResult > 0); // I don't know why MultiByteToWide char would return negative but let's make sure
  585. BCL_MAYFAIL_EPILOG_INTERNAL
  586. }
  587. static inline TCallDisposition
  588. CopyIntoBuffer(
  589. const TMutableNonNativePair &rpairOut,
  590. const CWin32UnicodeToMBCSDataIn &rddi,
  591. const TConstantPair &rpairIn,
  592. CWin32UnicodeToMBCSDataOut &rddo,
  593. SIZE_T &rcchWritten
  594. )
  595. {
  596. BCL_MAYFAIL_PROLOG
  597. BCL_PARAMETER_CHECK(rpairIn.GetCount() <= INT_MAX);
  598. BCL_PARAMETER_CHECK(rpairOut.GetCount() <= INT_MAX);
  599. // If we want to have any chance of returning ERROR_BUFFER_OVERFLOW
  600. // either we need to play the "two null chars at the end of the
  601. // buffer" game or we have to do this in two passes - one to
  602. // get the desired length and one to actually move the data.
  603. //
  604. // If someone has an approach which doesn't lose correctness but
  605. // avoids the double conversion, be my guest and fix this. -mgrier 2/6/2002
  606. int iResult = ::WideCharToMultiByte(
  607. rddi.m_CodePage,
  608. rddi.m_dwFlags | WC_NO_BEST_FIT_CHARS,
  609. rpairIn.GetPointer(),
  610. static_cast<INT>(rpairIn.GetCount()),
  611. NULL,
  612. 0,
  613. rddo.m_lpDefaultChar,
  614. rddo.m_lpUsedDefaultChar);
  615. if (iResult == 0)
  616. return TCallDisposition::FromLastError();
  617. BCL_INTERNAL_ERROR_CHECK(iResult >= 0);
  618. if (iResult > static_cast<INT>(rpairOut.GetCount()))
  619. BCL_ORIGINATE_ERROR(TCallDisposition::BufferOverflow());
  620. iResult = ::WideCharToMultiByte(
  621. rddi.m_CodePage,
  622. rddi.m_dwFlags | WC_NO_BEST_FIT_CHARS,
  623. rpairIn.GetPointer(),
  624. static_cast<INT>(rpairIn.GetCount()),
  625. rpairOut.GetPointer(),
  626. static_cast<INT>(rpairOut.GetCount()),
  627. rddo.m_lpDefaultChar,
  628. rddo.m_lpUsedDefaultChar);
  629. if (iResult == 0)
  630. return TCallDisposition::FromLastError();
  631. BCL_INTERNAL_ERROR_CHECK(iResult >= 0);
  632. rcchWritten = iResult;
  633. BCL_MAYFAIL_EPILOG_INTERNAL
  634. }
  635. static inline TCallDisposition
  636. AllocateAndCopyIntoBuffer(
  637. TMutableNonNativeString &rpszOut,
  638. const CWin32UnicodeToMBCSDataIn &rddi,
  639. const TConstantPair &rpairIn,
  640. CWin32UnicodeToMBCSDataOut &rddo,
  641. SIZE_T &rcchWritten
  642. )
  643. {
  644. BCL_MAYFAIL_PROLOG
  645. TSizeT cchInputString, cchBuffer;
  646. TBuffer::TTraits::TPSTRAllocationHelper pszTemp;
  647. BCL_PARAMETER_CHECK(rpairIn.GetCount() <= INT_MAX);
  648. BCL_IFCALLFAILED_EXIT(TBuffer::TTraits::MapStringCchToBufferCch(rpairIn.GetCount(), cchInputString));
  649. if (cchInputString > INT_MAX)
  650. BCL_ORIGINATE_ERROR(TCallDisposition::BufferOverflow());
  651. int iResult = ::WideCharToMultiByte(
  652. rddi.m_CodePage,
  653. rddi.m_dwFlags | WC_NO_BEST_FIT_CHARS,
  654. rpairIn.GetPointer(),
  655. static_cast<INT>(cchInputString),
  656. NULL,
  657. 0,
  658. rddo.m_lpDefaultChar,
  659. rddo.m_lpUsedDefaultChar);
  660. if (iResult == 0)
  661. return TCallDisposition::FromLastError();
  662. BCL_INTERNAL_ERROR_CHECK(iResult >= 0);
  663. cchBuffer = iResult;
  664. BCL_IFCALLFAILED_EXIT(pszTemp.Allocate(cchBuffer));
  665. INT iResult2 = ::WideCharToMultiByte(
  666. rddi.m_CodePage,
  667. rddi.m_dwFlags | WC_NO_BEST_FIT_CHARS,
  668. rpairIn.GetPointer(),
  669. static_cast<INT>(cchInputString),
  670. static_cast<PSTR>(pszTemp),
  671. iResult,
  672. rddo.m_lpDefaultChar,
  673. rddo.m_lpUsedDefaultChar);
  674. if (iResult2 == 0)
  675. return TCallDisposition::FromLastError();
  676. BCL_INTERNAL_ERROR_CHECK(iResult2 >= 0);
  677. BCL_IFCALLFAILED_EXIT(TBuffer::TTraits::MapBufferCchToStringCch(iResult2, rcchWritten));
  678. rpszOut = pszTemp.Detach();
  679. BCL_MAYFAIL_EPILOG_INTERNAL
  680. }
  681. static inline TCallDisposition
  682. AllocateAndCopyIntoBuffer(
  683. TMutableString &rstringOut,
  684. const TConstantPair &rpairIn,
  685. TSizeT &rcchWritten
  686. )
  687. {
  688. BCL_MAYFAIL_PROLOG
  689. TSizeT cchString = rpairIn.GetCount();
  690. TSizeT cchBuffer;
  691. TBuffer::TTraits::TPWSTRAllocationHelper pszTemp;
  692. BCL_IFCALLFAILED_EXIT(TBuffer::TTraits::MapStringCchToBufferCch(cchString, cchBuffer));
  693. BCL_IFCALLFAILED_EXIT(pszTemp.Allocate(cchBuffer));
  694. BCL_IFCALLFAILED_EXIT(TBuffer::TTraits::CopyIntoBuffer(TMutablePair(static_cast<PWSTR>(pszTemp), cchBuffer), rpairIn, rcchWritten));
  695. rstringOut = pszTemp.Detach();
  696. BCL_MAYFAIL_EPILOG_INTERNAL
  697. }
  698. }; // class CWin32NullTerminatedUnicodeStringAlgorithms
  699. }; // namespace BCL
  700. #endif // !defined(_BCL_W32UNICODESTRINGALGORITHMS_H_INCLUDED_)