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.

885 lines
27 KiB

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