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.

1613 lines
42 KiB

  1. //***************************************************************************
  2. //
  3. // Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
  4. //
  5. // CHSTRING.CPP
  6. //
  7. // Purpose: utility library version of MFC CString
  8. //
  9. //***************************************************************************
  10. #include "precomp.h"
  11. #pragma warning( disable : 4290 )
  12. #include <chstring.h>
  13. #include <stdio.h>
  14. #include <comdef.h>
  15. #include <AssertBreak.h>
  16. #include <ScopeGuard.h>
  17. #define _wcsinc(_pc) ((_pc)+1)
  18. #define FORCE_ANSI 0x10000
  19. #define FORCE_UNICODE 0x20000
  20. #define DEPRECATED 0
  21. const CHString& afxGetEmptyCHString();
  22. #define afxEmptyCHString afxGetEmptyCHString()
  23. // Global data used for LoadString.
  24. #if 0
  25. HINSTANCE g_hModule = GetModuleHandle(NULL); // Default to use the process module.
  26. #endif
  27. #ifdef FRAMEWORK_ALLOW_DEPRECATED
  28. void WINAPI SetCHStringResourceHandle(HINSTANCE handle)
  29. {
  30. ASSERT_BREAK(DEPRECATED);
  31. #if 0
  32. g_hModule = handle;
  33. #endif
  34. }
  35. #endif
  36. /////////////////////////////////////////////////////////////////////////////
  37. // static class data, special inlines
  38. /////////////////////////////////////////////////////////////////////////////
  39. WCHAR afxChNil = '\0';
  40. static DWORD GetPlatformID(void)
  41. {
  42. OSVERSIONINFOA version;
  43. version.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA) ;
  44. GetVersionExA(&version);
  45. return version.dwPlatformId;
  46. }
  47. static DWORD s_dwPlatformID = GetPlatformID();
  48. /////////////////////////////////////////////////////////////////////////////
  49. // For an empty string, m_pchData will point here
  50. // (note: avoids special case of checking for NULL m_pchData)
  51. // empty string data (and locked)
  52. /////////////////////////////////////////////////////////////////////////////
  53. static int rgInitData[] = { -1, 0, 0, 0 };
  54. static CHStringData* afxDataNil = (CHStringData*)&rgInitData;
  55. LPCWSTR afxPchNil = (LPCWSTR)(((BYTE*)&rgInitData)+sizeof(CHStringData));
  56. /////////////////////////////////////////////////////////////////////////////
  57. // special function to make EmptyString work even during initialization
  58. /////////////////////////////////////////////////////////////////////////////
  59. // special function to make afxEmptyString work even during initialization
  60. const CHString& afxGetEmptyCHString()
  61. {
  62. return *(CHString*)&afxPchNil;
  63. }
  64. ///////////////////////////////////////////////////////////////////////////////
  65. // CHString conversion helpers (these use the current system locale)
  66. ///////////////////////////////////////////////////////////////////////////////
  67. int _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
  68. {
  69. if (count == 0 && mbstr != NULL)
  70. {
  71. return 0;
  72. }
  73. int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1, mbstr, count, NULL, NULL);
  74. ASSERT_BREAK(mbstr != NULL || result <= (int)count);
  75. if (result > 0)
  76. {
  77. mbstr[result-1] = 0;
  78. }
  79. return result;
  80. }
  81. ///////////////////////////////////////////////////////////////////////////////
  82. int _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
  83. {
  84. if (count == 0 && wcstr != NULL)
  85. {
  86. return 0;
  87. }
  88. int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1,wcstr, count);
  89. ASSERT_BREAK(wcstr != NULL || result <= (int)count);
  90. if (result > 0)
  91. {
  92. wcstr[result-1] = 0;
  93. }
  94. return result;
  95. }
  96. ///////////////////////////////////////////////////////////////////////////////
  97. //*************************************************************************
  98. //
  99. // THE CHSTRING CLASS: PROTECTED MEMBER FUNCTIONS
  100. //
  101. //*************************************************************************
  102. ///////////////////////////////////////////////////////////////////////////////
  103. ///////////////////////////////////////////////////////////////////////////////
  104. // implementation helpers
  105. ///////////////////////////////////////////////////////////////////////////////
  106. CHStringData* CHString::GetData() const
  107. {
  108. if( m_pchData == (WCHAR*)*(&afxPchNil))
  109. {
  110. return (CHStringData *)afxDataNil;
  111. }
  112. return ((CHStringData*)m_pchData)-1;
  113. }
  114. //////////////////////////////////////////////////////////////////////////////
  115. //
  116. // Function: Init
  117. //
  118. // Description: This function initializes the data ptr
  119. //
  120. ///////////////////////////////////////////////////////////////////////////////
  121. void CHString::Init()
  122. {
  123. m_pchData = (WCHAR*)*(&afxPchNil);
  124. }
  125. //////////////////////////////////////////////////////////////////////////////
  126. //
  127. // Function: AllocCopy
  128. //
  129. // Description: This function will clone the data attached to this
  130. // string allocating 'nExtraLen' characters, it places
  131. // results in uninitialized string 'dest' and will copy
  132. // the part or all of original data to start of new string
  133. //
  134. //////////////////////////////////////////////////////////////////////////////
  135. void CHString::AllocCopy( CHString& dest, int nCopyLen, int nCopyIndex, int nExtraLen) const
  136. {
  137. int nNewLen = nCopyLen + nExtraLen;
  138. if (nNewLen == 0)
  139. {
  140. dest.Init();
  141. }
  142. else
  143. {
  144. dest.AllocBuffer(nNewLen);
  145. memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(WCHAR));
  146. }
  147. }
  148. //////////////////////////////////////////////////////////////////////////////
  149. //
  150. // Function: AllocBuffer
  151. //
  152. // Description: Always allocate one extra character for '\0'
  153. // termination. assumes [optimistically] that
  154. // data length will equal allocation length
  155. //
  156. //////////////////////////////////////////////////////////////////////////////
  157. void CHString::AllocBuffer(int nLen)
  158. {
  159. ASSERT_BREAK(nLen >= 0);
  160. ASSERT_BREAK(nLen <= INT_MAX-1); // max size (enough room for 1 extra)
  161. if (nLen == 0)
  162. {
  163. Init();
  164. }
  165. else
  166. {
  167. CHStringData* pData = (CHStringData*)new BYTE[sizeof(CHStringData) + (nLen+1)*sizeof(WCHAR)];
  168. if ( pData )
  169. {
  170. pData->nRefs = 1;
  171. pData->data()[nLen] = '\0';
  172. pData->nDataLength = nLen;
  173. pData->nAllocLength = nLen;
  174. m_pchData = pData->data();
  175. }
  176. else
  177. {
  178. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  179. }
  180. }
  181. }
  182. //////////////////////////////////////////////////////////////////////////////
  183. //
  184. // Function: AssignCopy
  185. //
  186. // Description: Assigns a copy of the string to the current data ptr
  187. //
  188. //
  189. //////////////////////////////////////////////////////////////////////////////
  190. void CHString::AssignCopy(int nSrcLen, LPCWSTR lpszSrcData)
  191. {
  192. // Call this first, it will release the buffer if it has
  193. // already been allocated and no one is using it
  194. AllocBeforeWrite(nSrcLen);
  195. // Now, check to see if the nSrcLen is > 0, if it is, then
  196. // continue, otherwise, go ahead and return
  197. if( nSrcLen > 0 )
  198. {
  199. memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(WCHAR));
  200. GetData()->nDataLength = nSrcLen;
  201. m_pchData[nSrcLen] = '\0';
  202. }
  203. else
  204. {
  205. Release();
  206. }
  207. }
  208. //////////////////////////////////////////////////////////////////////////////
  209. //
  210. // ConcatCopy
  211. //
  212. // Description: This is the master concatenation routine
  213. // Concatenates two sources, and assumes
  214. // that 'this' is a new CHString object
  215. //
  216. //////////////////////////////////////////////////////////////////////////////
  217. void CHString::ConcatCopy( int nSrc1Len, LPCWSTR lpszSrc1Data,
  218. int nSrc2Len, LPCWSTR lpszSrc2Data)
  219. {
  220. int nNewLen = nSrc1Len + nSrc2Len;
  221. if (nNewLen != 0)
  222. {
  223. AllocBuffer(nNewLen);
  224. memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(WCHAR));
  225. memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(WCHAR));
  226. }
  227. }
  228. //////////////////////////////////////////////////////////////////////////////
  229. //
  230. // ConcatInPlace
  231. //
  232. // Description: The main routine for += operators
  233. //
  234. //////////////////////////////////////////////////////////////////////////////
  235. void CHString::ConcatInPlace(int nSrcLen, LPCWSTR lpszSrcData)
  236. {
  237. // concatenating an empty string is a no-op!
  238. if (nSrcLen == 0)
  239. {
  240. return;
  241. }
  242. // if the buffer is too small, or we have a width mis-match, just
  243. // allocate a new buffer (slow but sure)
  244. if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
  245. {
  246. // we have to grow the buffer, use the ConcatCopy routine
  247. CHStringData* pOldData = GetData();
  248. ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
  249. ASSERT_BREAK(pOldData != NULL);
  250. CHString::Release(pOldData);
  251. }
  252. else
  253. {
  254. // fast concatenation when buffer big enough
  255. memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(WCHAR));
  256. GetData()->nDataLength += nSrcLen;
  257. ASSERT_BREAK(GetData()->nDataLength <= GetData()->nAllocLength);
  258. m_pchData[GetData()->nDataLength] = '\0';
  259. }
  260. }
  261. //////////////////////////////////////////////////////////////////////////////
  262. //
  263. // FormatV
  264. //
  265. // Description: Formats the variable arg list
  266. //
  267. //////////////////////////////////////////////////////////////////////////////
  268. void CHString::FormatV(LPCWSTR lpszFormat, va_list argList)
  269. {
  270. ASSERT_BREAK(lpszFormat!=NULL);
  271. va_list argListSave = argList;
  272. // make a guess at the maximum length of the resulting string
  273. int nMaxLen = 0;
  274. for (LPCWSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _wcsinc(lpsz)){
  275. // handle '%' character, but watch out for '%%'
  276. if (*lpsz != '%' || *(lpsz = _wcsinc(lpsz)) == '%'){
  277. nMaxLen += wcslen(lpsz);
  278. continue;
  279. }
  280. int nItemLen = 0;
  281. // handle '%' character with format
  282. int nWidth = 0;
  283. for (; *lpsz != '\0'; lpsz = _wcsinc(lpsz)){
  284. // check for valid flags
  285. if (*lpsz == '#')
  286. nMaxLen += 2; // for '0x'
  287. else if (*lpsz == '*')
  288. nWidth = va_arg(argList, int);
  289. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  290. *lpsz == ' ')
  291. ;
  292. else // hit non-flag character
  293. break;
  294. }
  295. // get width and skip it
  296. if (nWidth == 0){
  297. // width indicated by
  298. nWidth = _wtoi(lpsz);
  299. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _wcsinc(lpsz))
  300. ;
  301. }
  302. ASSERT_BREAK(nWidth >= 0);
  303. int nPrecision = 0;
  304. if (*lpsz == '.'){
  305. // skip past '.' separator (width.precision)
  306. lpsz = _wcsinc(lpsz);
  307. // get precision and skip it
  308. if (*lpsz == '*'){
  309. nPrecision = va_arg(argList, int);
  310. lpsz = _wcsinc(lpsz);
  311. }
  312. else{
  313. nPrecision = _wtoi(lpsz);
  314. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _wcsinc(lpsz))
  315. ;
  316. }
  317. ASSERT_BREAK(nPrecision >= 0);
  318. }
  319. // should be on type modifier or specifier
  320. int nModifier = 0;
  321. switch (*lpsz){
  322. // modifiers that affect size
  323. case 'h':
  324. nModifier = FORCE_ANSI;
  325. lpsz = _wcsinc(lpsz);
  326. break;
  327. case 'l':
  328. nModifier = FORCE_UNICODE;
  329. lpsz = _wcsinc(lpsz);
  330. break;
  331. // modifiers that do not affect size
  332. case 'F':
  333. case 'N':
  334. case 'L':
  335. lpsz = _wcsinc(lpsz);
  336. break;
  337. }
  338. // now should be on specifier
  339. switch (*lpsz | nModifier){
  340. // single characters
  341. case 'c':
  342. case 'C':
  343. nItemLen = 2;
  344. va_arg(argList, TCHAR_ARG);
  345. break;
  346. case 'c'|FORCE_ANSI:
  347. case 'C'|FORCE_ANSI:
  348. nItemLen = 2;
  349. va_arg(argList, CHAR_ARG);
  350. break;
  351. case 'c'|FORCE_UNICODE:
  352. case 'C'|FORCE_UNICODE:
  353. nItemLen = 2;
  354. va_arg(argList, WCHAR_ARG);
  355. break;
  356. // strings
  357. case 's':
  358. nItemLen = wcslen(va_arg(argList, LPCWSTR));
  359. nItemLen = max(1, nItemLen);
  360. break;
  361. case 'S':
  362. nItemLen = strlen(va_arg(argList, LPCSTR));
  363. nItemLen = max(1, nItemLen);
  364. break;
  365. case 's'|FORCE_ANSI:
  366. case 'S'|FORCE_ANSI:
  367. nItemLen = strlen(va_arg(argList, LPCSTR));
  368. nItemLen = max(1, nItemLen);
  369. break;
  370. #ifndef _MAC
  371. case 's'|FORCE_UNICODE:
  372. case 'S'|FORCE_UNICODE:
  373. nItemLen = wcslen(va_arg(argList, LPWSTR));
  374. nItemLen = max(1, nItemLen);
  375. break;
  376. #endif
  377. }
  378. // adjust nItemLen for strings
  379. if (nItemLen != 0){
  380. nItemLen = max(nItemLen, nWidth);
  381. if (nPrecision != 0)
  382. nItemLen = min(nItemLen, nPrecision);
  383. }
  384. else{
  385. switch (*lpsz){
  386. // integers
  387. case 'd':
  388. case 'i':
  389. case 'u':
  390. case 'x':
  391. case 'X':
  392. case 'o':
  393. va_arg(argList, int);
  394. nItemLen = 32;
  395. nItemLen = max(nItemLen, nWidth+nPrecision);
  396. break;
  397. case 'e':
  398. case 'f':
  399. case 'g':
  400. case 'G':
  401. va_arg(argList, DOUBLE_ARG);
  402. nItemLen = 128;
  403. nItemLen = max(nItemLen, nWidth+nPrecision);
  404. break;
  405. case 'p':
  406. va_arg(argList, void*);
  407. nItemLen = 32;
  408. nItemLen = max(nItemLen, nWidth+nPrecision);
  409. break;
  410. // no output
  411. case 'n':
  412. va_arg(argList, int*);
  413. break;
  414. default:
  415. ASSERT_BREAK(FALSE); // unknown formatting option
  416. }
  417. }
  418. // adjust nMaxLen for output nItemLen
  419. nMaxLen += nItemLen;
  420. }
  421. GetBuffer(nMaxLen);
  422. int iSize = vswprintf(m_pchData, lpszFormat, argListSave); //<= GetAllocLength();
  423. ASSERT_BREAK(iSize <= nMaxLen);
  424. ReleaseBuffer();
  425. va_end(argListSave);
  426. }
  427. //////////////////////////////////////////////////////////////////////////////
  428. //
  429. // CopyBeforeWrite
  430. //
  431. // Description:
  432. //
  433. //////////////////////////////////////////////////////////////////////////////
  434. void CHString::CopyBeforeWrite()
  435. {
  436. if (GetData()->nRefs > 1)
  437. {
  438. CHStringData* pData = GetData();
  439. Release();
  440. AllocBuffer(pData->nDataLength);
  441. memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(WCHAR));
  442. }
  443. ASSERT_BREAK(GetData()->nRefs <= 1);
  444. }
  445. //////////////////////////////////////////////////////////////////////////////
  446. //
  447. // AllocBeforeWrite
  448. //
  449. // Description:
  450. //
  451. //////////////////////////////////////////////////////////////////////////////
  452. void CHString::AllocBeforeWrite(int nLen)
  453. {
  454. if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
  455. {
  456. Release();
  457. AllocBuffer(nLen);
  458. }
  459. ASSERT_BREAK(GetData()->nRefs <= 1);
  460. }
  461. //////////////////////////////////////////////////////////////////////////////
  462. //
  463. // Release
  464. //
  465. // Description: Deallocate data
  466. //
  467. //////////////////////////////////////////////////////////////////////////////
  468. void CHString::Release()
  469. {
  470. if (GetData() != afxDataNil)
  471. {
  472. ASSERT_BREAK(GetData()->nRefs != 0);
  473. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  474. {
  475. delete[] (BYTE*)GetData();
  476. }
  477. Init();
  478. }
  479. }
  480. //////////////////////////////////////////////////////////////////////////////
  481. //
  482. // Release
  483. //
  484. // Description: Deallocate data
  485. //
  486. //////////////////////////////////////////////////////////////////////////////
  487. void CHString::Release(CHStringData* pData)
  488. {
  489. if (pData != afxDataNil)
  490. {
  491. ASSERT_BREAK(pData->nRefs != 0);
  492. if (InterlockedDecrement(&pData->nRefs) <= 0)
  493. {
  494. delete[] (BYTE*)pData;
  495. }
  496. }
  497. }
  498. //////////////////////////////////////////////////////////////////////////////
  499. // Construction/Destruction
  500. ///////////////////////////////////////////////////////////////////////////////
  501. //////////////////////////////////////////////////////////////////////////////
  502. //
  503. // Description:
  504. //
  505. //////////////////////////////////////////////////////////////////////////////
  506. CHString::CHString()
  507. {
  508. Init();
  509. }
  510. //////////////////////////////////////////////////////////////////////////////
  511. //
  512. // Description:
  513. //
  514. //////////////////////////////////////////////////////////////////////////////
  515. CHString::CHString(WCHAR ch, int nLength)
  516. {
  517. ASSERT_BREAK(!_istlead(ch)); // can't create a lead byte string
  518. Init();
  519. if (nLength >= 1)
  520. {
  521. AllocBuffer(nLength);
  522. for (int i = 0; i < nLength; i++)
  523. {
  524. m_pchData[i] = ch;
  525. }
  526. }
  527. }
  528. //////////////////////////////////////////////////////////////////////////////
  529. //
  530. // Description:
  531. //
  532. //////////////////////////////////////////////////////////////////////////////
  533. CHString::CHString(LPCWSTR lpch, int nLength)
  534. {
  535. Init();
  536. if (nLength != 0)
  537. {
  538. ASSERT_BREAK(lpch!=NULL);
  539. AllocBuffer(nLength);
  540. memcpy(m_pchData, lpch, nLength*sizeof(WCHAR));
  541. }
  542. }
  543. //////////////////////////////////////////////////////////////////////////////
  544. //
  545. // Description:
  546. //
  547. //////////////////////////////////////////////////////////////////////////////
  548. //#ifdef _UNICODE
  549. CHString::CHString(LPCSTR lpsz)
  550. {
  551. Init();
  552. int nSrcLen = lpsz != NULL ? strlen(lpsz) : 0;
  553. if (nSrcLen != 0)
  554. {
  555. AllocBuffer(nSrcLen);
  556. _mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  557. ReleaseBuffer();
  558. }
  559. }
  560. //////////////////////////////////////////////////////////////////////////////
  561. //
  562. // Description:
  563. //
  564. //////////////////////////////////////////////////////////////////////////////
  565. //#else //_UNICODE
  566. #if 0
  567. CHString::CHString(LPCWSTR lpsz)
  568. {
  569. Init();
  570. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  571. if (nSrcLen != 0){
  572. AllocBuffer(nSrcLen*2);
  573. _wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  574. ReleaseBuffer();
  575. }
  576. }
  577. #endif
  578. //////////////////////////////////////////////////////////////////////////////
  579. //
  580. // Description:
  581. //
  582. //////////////////////////////////////////////////////////////////////////////
  583. CHString::CHString(LPCWSTR lpsz)
  584. {
  585. Init();
  586. // if (lpsz != NULL && HIWORD(lpsz) == NULL)
  587. // {
  588. //??
  589. // }
  590. // else
  591. // {
  592. int nLen = SafeStrlen(lpsz);
  593. if (nLen != 0)
  594. {
  595. AllocBuffer(nLen);
  596. memcpy(m_pchData, lpsz, nLen*sizeof(WCHAR));
  597. }
  598. // }
  599. }
  600. //////////////////////////////////////////////////////////////////////////////
  601. //
  602. // Description:
  603. //
  604. //////////////////////////////////////////////////////////////////////////////
  605. CHString::CHString(const CHString& stringSrc)
  606. {
  607. ASSERT_BREAK(stringSrc.GetData()->nRefs != 0);
  608. if (stringSrc.GetData()->nRefs >= 0)
  609. {
  610. ASSERT_BREAK(stringSrc.GetData() != afxDataNil);
  611. m_pchData = stringSrc.m_pchData;
  612. InterlockedIncrement(&GetData()->nRefs);
  613. }
  614. else
  615. {
  616. Init();
  617. *this = stringSrc.m_pchData;
  618. }
  619. }
  620. //////////////////////////////////////////////////////////////////////////////
  621. //
  622. // Description:
  623. //
  624. //////////////////////////////////////////////////////////////////////////////
  625. void CHString::Empty()
  626. {
  627. if (GetData()->nDataLength == 0)
  628. {
  629. return;
  630. }
  631. if (GetData()->nRefs >= 0)
  632. {
  633. Release();
  634. }
  635. else
  636. {
  637. *this = &afxChNil;
  638. }
  639. ASSERT_BREAK(GetData()->nDataLength == 0);
  640. ASSERT_BREAK(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
  641. }
  642. //////////////////////////////////////////////////////////////////////////////
  643. //
  644. // Description:
  645. //
  646. //////////////////////////////////////////////////////////////////////////////
  647. CHString::~CHString()
  648. {
  649. if (GetData() != afxDataNil)
  650. {
  651. // free any attached data
  652. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  653. {
  654. delete[] (BYTE*)GetData();
  655. }
  656. }
  657. }
  658. //////////////////////////////////////////////////////////////////////////////
  659. //
  660. // Description:
  661. //
  662. //////////////////////////////////////////////////////////////////////////////
  663. void CHString::SetAt(int nIndex, WCHAR ch)
  664. {
  665. ASSERT_BREAK(nIndex >= 0);
  666. ASSERT_BREAK(nIndex < GetData()->nDataLength);
  667. CopyBeforeWrite();
  668. m_pchData[nIndex] = ch;
  669. }
  670. //////////////////////////////////////////////////////////////////////////////
  671. //
  672. // Description:
  673. //
  674. // Assignment operators
  675. // All assign a new value to the string
  676. // (a) first see if the buffer is big enough
  677. // (b) if enough room, copy on top of old buffer, set size and type
  678. // (c) otherwise free old string data, and create a new one
  679. //
  680. // All routines return the new string (but as a 'const CHString&' so that
  681. // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  682. //
  683. /////////////////////////////////////////////////////////////////////////
  684. const CHString& CHString::operator=(const CHString& stringSrc)
  685. {
  686. if (m_pchData != stringSrc.m_pchData)
  687. {
  688. if ((GetData()->nRefs < 0 && GetData() != afxDataNil) ||
  689. stringSrc.GetData()->nRefs < 0)
  690. {
  691. // actual copy necessary since one of the strings is locked
  692. AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  693. }
  694. else
  695. {
  696. // can just copy references around
  697. Release();
  698. ASSERT_BREAK(stringSrc.GetData() != afxDataNil);
  699. m_pchData = stringSrc.m_pchData;
  700. InterlockedIncrement(&GetData()->nRefs);
  701. }
  702. }
  703. return *this;
  704. /* if (m_pchData != stringSrc.m_pchData){
  705. // can just copy references around
  706. Release();
  707. if( stringSrc.GetData() != afxDataNil) {
  708. AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  709. InterlockedIncrement(&GetData()->nRefs);
  710. }
  711. }
  712. return *this;*/
  713. }
  714. /////////////////////////////////////////////////////////////////////////////
  715. const CHString& CHString::operator=(LPCWSTR lpsz)
  716. {
  717. ASSERT_BREAK(lpsz != NULL);
  718. AssignCopy(SafeStrlen(lpsz), lpsz);
  719. return *this;
  720. }
  721. /////////////////////////////////////////////////////////////////////////////
  722. // Special conversion assignment
  723. //#ifdef _UNICODE
  724. const CHString& CHString::operator=(LPCSTR lpsz)
  725. {
  726. int nSrcLen = lpsz != NULL ? strlen(lpsz) : 0 ;
  727. AllocBeforeWrite( nSrcLen ) ;
  728. if( nSrcLen )
  729. {
  730. _mbstowcsz( m_pchData, lpsz, nSrcLen + 1 ) ;
  731. ReleaseBuffer() ;
  732. }
  733. else
  734. {
  735. Release() ;
  736. }
  737. return *this;
  738. }
  739. /////////////////////////////////////////////////////////////////////////////
  740. //#else //!_UNICODE
  741. #if 0
  742. const CHString& CHString::operator=(LPCWSTR lpsz)
  743. {
  744. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0 ;
  745. AllocBeforeWrite( nSrcLen * 2 ) ;
  746. if( nSrcLen )
  747. {
  748. _wcstombsz(m_pchData, lpsz, (nSrcLen * 2) + 1 ) ;
  749. ReleaseBuffer();
  750. }
  751. else
  752. {
  753. Release() ;
  754. }
  755. return *this;
  756. }
  757. #endif
  758. //////////////////////////////////////////////////////////////////////////////
  759. const CHString& CHString::operator=(WCHAR ch)
  760. {
  761. ASSERT_BREAK(!_istlead(ch)); // can't set single lead byte
  762. AssignCopy(1, &ch);
  763. return *this;
  764. }
  765. /////////////////////////////////////////////////////////////////////////////
  766. // NOTE: "operator+" is done as friend functions for simplicity
  767. // There are three variants:
  768. // CHString + CHString
  769. // and for ? = WCHAR, LPCWSTR
  770. // CHString + ?
  771. // ? + CHString
  772. /////////////////////////////////////////////////////////////////////////////
  773. CHString WINAPI operator+(const CHString& string1, const CHString& string2)
  774. {
  775. CHString s;
  776. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
  777. string2.GetData()->nDataLength, string2.m_pchData);
  778. return s;
  779. }
  780. /////////////////////////////////////////////////////////////////////////////
  781. CHString WINAPI operator+(const CHString& string, LPCWSTR lpsz)
  782. {
  783. ASSERT_BREAK(lpsz != NULL );
  784. CHString s;
  785. s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
  786. CHString::SafeStrlen(lpsz), lpsz);
  787. return s;
  788. }
  789. /////////////////////////////////////////////////////////////////////////////
  790. CHString WINAPI operator+(LPCWSTR lpsz, const CHString& string)
  791. {
  792. ASSERT_BREAK(lpsz != NULL );
  793. CHString s;
  794. s.ConcatCopy(CHString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
  795. string.m_pchData);
  796. return s;
  797. }
  798. /////////////////////////////////////////////////////////////////////////////
  799. CHString WINAPI operator+(const CHString& string1, WCHAR ch)
  800. {
  801. CHString s;
  802. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
  803. return s;
  804. }
  805. /////////////////////////////////////////////////////////////////////////////
  806. CHString WINAPI operator+(WCHAR ch, const CHString& string)
  807. {
  808. CHString s;
  809. s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
  810. return s;
  811. }
  812. /////////////////////////////////////////////////////////////////////////////
  813. const CHString& CHString::operator+=(LPCWSTR lpsz)
  814. {
  815. ASSERT_BREAK(lpsz != NULL );
  816. ConcatInPlace(SafeStrlen(lpsz), lpsz);
  817. return *this;
  818. }
  819. /////////////////////////////////////////////////////////////////////////////
  820. const CHString& CHString::operator+=(WCHAR ch)
  821. {
  822. ConcatInPlace(1, &ch);
  823. return *this;
  824. }
  825. /////////////////////////////////////////////////////////////////////////////
  826. const CHString& CHString::operator+=(const CHString& string)
  827. {
  828. ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
  829. return *this;
  830. }
  831. ///////////////////////////////////////////////////////////////////////////////
  832. int CHString::Compare(LPCWSTR lpsz ) const
  833. {
  834. ASSERT_BREAK( lpsz!=NULL );
  835. ASSERT_BREAK( m_pchData != NULL );
  836. return wcscmp(m_pchData, lpsz); // MBCS/Unicode aware strcmp
  837. }
  838. ///////////////////////////////////////////////////////////////////////////////
  839. //
  840. //
  841. // Description: Advanced direct buffer access
  842. //
  843. ///////////////////////////////////////////////////////////////////////////////
  844. LPWSTR CHString::GetBuffer(int nMinBufLength)
  845. {
  846. ASSERT_BREAK(nMinBufLength >= 0);
  847. if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
  848. {
  849. // we have to grow the buffer
  850. CHStringData* pOldData = GetData();
  851. int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
  852. if (nMinBufLength < nOldLen)
  853. {
  854. nMinBufLength = nOldLen;
  855. }
  856. AllocBuffer(nMinBufLength);
  857. memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(WCHAR));
  858. GetData()->nDataLength = nOldLen;
  859. CHString::Release(pOldData);
  860. }
  861. ASSERT_BREAK(GetData()->nRefs <= 1);
  862. // return a pointer to the character storage for this string
  863. ASSERT_BREAK(m_pchData != NULL);
  864. return m_pchData;
  865. }
  866. ///////////////////////////////////////////////////////////////////////////////
  867. void CHString::ReleaseBuffer(int nNewLength)
  868. {
  869. CopyBeforeWrite(); // just in case GetBuffer was not called
  870. if (nNewLength == -1)
  871. {
  872. nNewLength = wcslen(m_pchData); // zero terminated
  873. }
  874. ASSERT_BREAK(nNewLength <= GetData()->nAllocLength);
  875. GetData()->nDataLength = nNewLength;
  876. m_pchData[nNewLength] = '\0';
  877. }
  878. ///////////////////////////////////////////////////////////////////////////////
  879. LPWSTR CHString::GetBufferSetLength(int nNewLength)
  880. {
  881. ASSERT_BREAK(nNewLength >= 0);
  882. GetBuffer(nNewLength);
  883. GetData()->nDataLength = nNewLength;
  884. m_pchData[nNewLength] = '\0';
  885. return m_pchData;
  886. }
  887. ///////////////////////////////////////////////////////////////////////////////
  888. void CHString::FreeExtra()
  889. {
  890. ASSERT_BREAK(GetData()->nDataLength <= GetData()->nAllocLength);
  891. if (GetData()->nDataLength != GetData()->nAllocLength)
  892. {
  893. CHStringData* pOldData = GetData();
  894. AllocBuffer(GetData()->nDataLength);
  895. memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(WCHAR));
  896. ASSERT_BREAK(m_pchData[GetData()->nDataLength] == '\0');
  897. CHString::Release(pOldData);
  898. }
  899. ASSERT_BREAK(GetData() != NULL);
  900. }
  901. ///////////////////////////////////////////////////////////////////////////////
  902. LPWSTR CHString::LockBuffer()
  903. {
  904. LPWSTR lpsz = GetBuffer(0);
  905. GetData()->nRefs = -1;
  906. return lpsz;
  907. }
  908. ///////////////////////////////////////////////////////////////////////////////
  909. void CHString::UnlockBuffer()
  910. {
  911. ASSERT_BREAK(GetData()->nRefs == -1);
  912. if (GetData() != afxDataNil)
  913. {
  914. GetData()->nRefs = 1;
  915. }
  916. }
  917. ///////////////////////////////////////////////////////////////////////////////
  918. int CHString::Find(WCHAR ch) const
  919. {
  920. // find first single character
  921. LPWSTR lpsz = wcschr(m_pchData, ch);
  922. // return -1 if not found and index otherwise
  923. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  924. }
  925. //////////////////////////////////////////////////////////////////////////////
  926. int CHString::FindOneOf(LPCWSTR lpszCharSet) const
  927. {
  928. ASSERT_BREAK(lpszCharSet!=0);
  929. LPWSTR lpsz = wcspbrk(m_pchData, lpszCharSet);
  930. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  931. }
  932. //////////////////////////////////////////////////////////////////////////////
  933. int CHString::ReverseFind(WCHAR ch) const
  934. {
  935. // find last single character
  936. LPWSTR lpsz = wcsrchr(m_pchData, (_TUCHAR)ch);
  937. // return -1 if not found, distance from beginning otherwise
  938. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  939. }
  940. //////////////////////////////////////////////////////////////////////////////
  941. // find a sub-string (like strstr)
  942. int CHString::Find(LPCWSTR lpszSub) const
  943. {
  944. ASSERT_BREAK(lpszSub!=NULL);
  945. // find first matching substring
  946. LPWSTR lpsz = wcsstr(m_pchData, lpszSub);
  947. // return -1 for not found, distance from beginning otherwise
  948. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  949. }
  950. //////////////////////////////////////////////////////////////////////////////
  951. void CHString::MakeUpper()
  952. {
  953. CopyBeforeWrite();
  954. ::_wcsupr(m_pchData);
  955. }
  956. //////////////////////////////////////////////////////////////////////////////
  957. void CHString::MakeLower()
  958. {
  959. CopyBeforeWrite();
  960. ::_wcslwr(m_pchData);
  961. }
  962. //////////////////////////////////////////////////////////////////////////////
  963. void CHString::MakeReverse()
  964. {
  965. CopyBeforeWrite();
  966. _wcsrev(m_pchData);
  967. }
  968. //////////////////////////////////////////////////////////////////////////////
  969. //#ifndef _UNICODE
  970. //void CHString::AnsiToOem()
  971. //{
  972. // CopyBeforeWrite();
  973. // ::AnsiToOemW(m_pchData, m_pchData);
  974. //}
  975. //void CHString::OemToAnsi()
  976. //{
  977. // CopyBeforeWrite();
  978. // ::OemToAnsi(m_pchData, m_pchData);
  979. //}
  980. //#endif
  981. //////////////////////////////////////////////////////////////////////////////
  982. // Very simple sub-string extraction
  983. CHString CHString::Mid(int nFirst) const
  984. {
  985. return Mid(nFirst, GetData()->nDataLength - nFirst);
  986. }
  987. //////////////////////////////////////////////////////////////////////////////
  988. CHString CHString::Mid(int nFirst, int nCount) const
  989. {
  990. // out-of-bounds requests return sensible things
  991. if (nFirst < 0)
  992. {
  993. nFirst = 0;
  994. }
  995. if (nCount < 0)
  996. {
  997. nCount = 0;
  998. }
  999. if (nFirst + nCount > GetData()->nDataLength)
  1000. {
  1001. nCount = GetData()->nDataLength - nFirst;
  1002. }
  1003. if (nFirst > GetData()->nDataLength)
  1004. {
  1005. nCount = 0;
  1006. }
  1007. CHString dest;
  1008. AllocCopy(dest, nCount, nFirst, 0);
  1009. return dest;
  1010. }
  1011. //////////////////////////////////////////////////////////////////////////////
  1012. CHString CHString::Right(int nCount) const
  1013. {
  1014. if (nCount < 0)
  1015. {
  1016. nCount = 0;
  1017. }
  1018. else if (nCount > GetData()->nDataLength)
  1019. {
  1020. nCount = GetData()->nDataLength;
  1021. }
  1022. CHString dest;
  1023. AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
  1024. return dest;
  1025. }
  1026. //////////////////////////////////////////////////////////////////////////////
  1027. CHString CHString::Left(int nCount) const
  1028. {
  1029. if (nCount < 0)
  1030. {
  1031. nCount = 0;
  1032. }
  1033. else if (nCount > GetData()->nDataLength)
  1034. {
  1035. nCount = GetData()->nDataLength;
  1036. }
  1037. CHString dest;
  1038. AllocCopy(dest, nCount, 0, 0);
  1039. return dest;
  1040. }
  1041. //////////////////////////////////////////////////////////////////////////////
  1042. // strspn equivalent
  1043. CHString CHString::SpanIncluding(LPCWSTR lpszCharSet) const
  1044. {
  1045. ASSERT_BREAK(lpszCharSet != NULL);
  1046. return Left(wcsspn(m_pchData, lpszCharSet));
  1047. }
  1048. //////////////////////////////////////////////////////////////////////////////
  1049. // strcspn equivalent
  1050. CHString CHString::SpanExcluding(LPCWSTR lpszCharSet) const
  1051. {
  1052. ASSERT_BREAK(lpszCharSet != NULL);
  1053. return Left(wcscspn(m_pchData, lpszCharSet));
  1054. }
  1055. //////////////////////////////////////////////////////////////////////////////
  1056. void CHString::TrimRight()
  1057. {
  1058. CopyBeforeWrite();
  1059. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  1060. LPWSTR lpsz = m_pchData;
  1061. LPWSTR lpszLast = NULL;
  1062. while (*lpsz != '\0')
  1063. {
  1064. if (_istspace(*lpsz))
  1065. {
  1066. if (lpszLast == NULL)
  1067. {
  1068. lpszLast = lpsz;
  1069. }
  1070. }
  1071. else
  1072. {
  1073. lpszLast = NULL;
  1074. }
  1075. lpsz = _wcsinc(lpsz);
  1076. }
  1077. if (lpszLast != NULL)
  1078. {
  1079. // truncate at trailing space start
  1080. *lpszLast = '\0';
  1081. GetData()->nDataLength = (int)(lpszLast - m_pchData);
  1082. }
  1083. }
  1084. //////////////////////////////////////////////////////////////////////////////
  1085. void CHString::TrimLeft()
  1086. {
  1087. CopyBeforeWrite();
  1088. // find first non-space character
  1089. LPCWSTR lpsz = m_pchData;
  1090. while (_istspace(*lpsz))
  1091. {
  1092. lpsz = _wcsinc(lpsz);
  1093. }
  1094. // fix up data and length
  1095. int nDataLength = GetData()->nDataLength - (int)(lpsz - m_pchData);
  1096. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(WCHAR));
  1097. GetData()->nDataLength = nDataLength;
  1098. }
  1099. //////////////////////////////////////////////////////////////////////////////
  1100. // formatting (using wsprintf style formatting)
  1101. void __cdecl CHString::Format(LPCWSTR lpszFormat, ...)
  1102. {
  1103. ASSERT_BREAK(lpszFormat!=NULL);
  1104. va_list argList;
  1105. va_start(argList, lpszFormat);
  1106. FormatV(lpszFormat, argList);
  1107. va_end(argList);
  1108. }
  1109. #ifdef FRAMEWORK_ALLOW_DEPRECATED
  1110. void __cdecl CHString::Format(UINT nFormatID, ...)
  1111. {
  1112. ASSERT_BREAK(DEPRECATED);
  1113. #if 0
  1114. CHString strFormat;
  1115. strFormat.LoadStringW(nFormatID);
  1116. va_list argList;
  1117. va_start(argList, nFormatID);
  1118. FormatV(strFormat, argList);
  1119. va_end(argList);
  1120. #endif
  1121. }
  1122. #endif
  1123. class auto_va_list
  1124. {
  1125. va_list& argList_;
  1126. public:
  1127. auto_va_list(va_list& arg):argList_(arg){ };
  1128. ~auto_va_list(){va_end(argList_);}
  1129. };
  1130. //////////////////////////////////////////////////////////////////////////////
  1131. // formatting (using FormatMessage style formatting)
  1132. void __cdecl CHString::FormatMessageW(LPCWSTR lpszFormat, ...)
  1133. {
  1134. // format message into temporary buffer lpszTemp
  1135. va_list argList;
  1136. va_start(argList, lpszFormat);
  1137. auto_va_list _arg(argList);
  1138. if (s_dwPlatformID == VER_PLATFORM_WIN32_NT)
  1139. {
  1140. LPWSTR lpszTemp = 0;
  1141. if (::FormatMessageW(
  1142. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1143. lpszFormat,
  1144. 0,
  1145. 0,
  1146. (LPWSTR) &lpszTemp,
  1147. 0,
  1148. &argList) == 0 || lpszTemp == 0)
  1149. throw CHeap_Exception (CHeap_Exception::E_ALLOCATION_ERROR);
  1150. ScopeGuard _1 = MakeGuard (LocalFree, lpszTemp);
  1151. ASSERT_BREAK(lpszTemp != NULL);
  1152. // assign lpszTemp into the resulting string and free the temporary
  1153. *this = lpszTemp;
  1154. }
  1155. else
  1156. {
  1157. LPSTR lpszTemp = 0;
  1158. if (::FormatMessageA(
  1159. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1160. (LPCTSTR) bstr_t(lpszFormat),
  1161. 0,
  1162. 0,
  1163. (LPSTR) &lpszTemp,
  1164. 0,
  1165. &argList)==0 || lpszTemp == 0)
  1166. throw CHeap_Exception (CHeap_Exception::E_ALLOCATION_ERROR);
  1167. ScopeGuard _1 = MakeGuard (LocalFree, lpszTemp);
  1168. ASSERT_BREAK(lpszTemp != NULL);
  1169. // assign lpszTemp into the resulting string and free the temporary
  1170. *this = lpszTemp;
  1171. }
  1172. }
  1173. #ifdef FRAMEWORK_ALLOW_DEPRECATED
  1174. void __cdecl CHString::FormatMessageW(UINT nFormatID, ...)
  1175. {
  1176. ASSERT_BREAK(DEPRECATED);
  1177. #if 0
  1178. // get format string from string table
  1179. CHString strFormat;
  1180. strFormat.LoadStringW(nFormatID);
  1181. // format message into temporary buffer lpszTemp
  1182. va_list argList;
  1183. va_start(argList, nFormatID);
  1184. auto_va_list _arg(argList);
  1185. if (s_dwPlatformID == VER_PLATFORM_WIN32_NT)
  1186. {
  1187. LPWSTR lpszTemp = 0;
  1188. if (::FormatMessageW(
  1189. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1190. (LPCWSTR) strFormat,
  1191. 0,
  1192. 0,
  1193. (LPWSTR) &lpszTemp,
  1194. 0,
  1195. &argList) == 0 || lpszTemp == NULL)
  1196. {
  1197. // Should throw memory exception here. Now we do.
  1198. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  1199. };
  1200. ScopeGuard _1 = MakeGuard (LocalFree, lpszTemp);
  1201. // assign lpszTemp into the resulting string and free lpszTemp
  1202. *this = lpszTemp;
  1203. }
  1204. else
  1205. {
  1206. LPSTR lpszTemp = 0;
  1207. if (::FormatMessageA(
  1208. FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1209. (LPCSTR) bstr_t(strFormat),
  1210. 0,
  1211. 0,
  1212. (LPSTR) &lpszTemp,
  1213. 0,
  1214. &argList) == 0 || lpszTemp == NULL)
  1215. {
  1216. // Should throw memory exception here. Now we do.
  1217. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  1218. }
  1219. ScopeGuard _1 = MakeGuard (LocalFree, lpszTemp);
  1220. // assign lpszTemp into the resulting string and free lpszTemp
  1221. *this = lpszTemp;
  1222. }
  1223. }
  1224. #endif
  1225. }
  1226. #endif
  1227. ///////////////////////////////////////////////////////////////////////////////
  1228. BSTR CHString::AllocSysString() const
  1229. {
  1230. BSTR bstr;
  1231. bstr = ::SysAllocStringLen(m_pchData, GetData()->nDataLength);
  1232. if ( ! bstr )
  1233. {
  1234. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  1235. }
  1236. ASSERT_BREAK(bstr!=NULL);
  1237. return bstr;
  1238. }
  1239. ///////////////////////////////////////////////////////////////////////////////
  1240. // CHString support for template collections
  1241. void ConstructElements(CHString* pElements, int nCount)
  1242. {
  1243. ASSERT_BREAK(nCount != 0 || pElements != NULL );
  1244. for (; nCount--; ++pElements)
  1245. {
  1246. memcpy(pElements, &afxPchNil, sizeof(*pElements));
  1247. }
  1248. }
  1249. void DestructElements(CHString* pElements, int nCount)
  1250. {
  1251. ASSERT_BREAK(nCount != 0 || pElements != NULL);
  1252. for (; nCount--; ++pElements)
  1253. {
  1254. pElements->~CHString();
  1255. }
  1256. }
  1257. void CopyElements(CHString* pDest, const CHString* pSrc, int nCount)
  1258. {
  1259. ASSERT_BREAK(nCount != 0 || pDest != NULL );
  1260. ASSERT_BREAK(nCount != 0 || pSrc != NULL );
  1261. for (; nCount--; ++pDest, ++pSrc)
  1262. {
  1263. *pDest = *pSrc;
  1264. }
  1265. }
  1266. UINT HashKey(LPCWSTR key)
  1267. {
  1268. UINT nHash = 0;
  1269. while (*key)
  1270. {
  1271. nHash = (nHash<<5) + nHash + *key++;
  1272. }
  1273. return nHash;
  1274. }
  1275. /////////////////////////////////////////////////////////////////////////////
  1276. // Windows extensions to strings
  1277. #ifdef _UNICODE
  1278. #define CHAR_FUDGE 1 // one WCHAR unused is good enough
  1279. #else
  1280. #define CHAR_FUDGE 2 // two BYTES unused for case of DBC last char
  1281. #endif
  1282. #define STR_BLK_SIZE 256
  1283. #ifdef FRAMEWORK_ALLOW_DEPRECATED
  1284. BOOL CHString::LoadStringW(UINT nID)
  1285. {
  1286. ASSERT_BREAK(DEPRECATED);
  1287. #if 0
  1288. // try fixed buffer first (to avoid wasting space in the heap)
  1289. WCHAR szTemp[ STR_BLK_SIZE ];
  1290. int nLen = LoadStringW(nID, szTemp, STR_BLK_SIZE);
  1291. if (STR_BLK_SIZE - nLen > CHAR_FUDGE)
  1292. {
  1293. *this = szTemp;
  1294. }
  1295. else
  1296. {
  1297. // try buffer size of 512, then larger size until entire string is retrieved
  1298. int nSize = STR_BLK_SIZE;
  1299. do
  1300. {
  1301. nSize += STR_BLK_SIZE;
  1302. nLen = LoadStringW(nID, GetBuffer(nSize-1), nSize);
  1303. }
  1304. while (nSize - nLen <= CHAR_FUDGE);
  1305. ReleaseBuffer();
  1306. }
  1307. return nLen > 0;
  1308. #endif
  1309. return FALSE;
  1310. }
  1311. #endif
  1312. #ifdef FRAMEWORK_ALLOW_DEPRECATED
  1313. int CHString::LoadStringW(UINT nID, LPWSTR lpszBuf, UINT nMaxBuf)
  1314. {
  1315. ASSERT_BREAK(DEPRECATED);
  1316. #if 0
  1317. int nLen;
  1318. if (s_dwPlatformID == VER_PLATFORM_WIN32_NT)
  1319. {
  1320. nLen = ::LoadStringW(g_hModule, nID, lpszBuf, nMaxBuf);
  1321. if (nLen == 0)
  1322. {
  1323. lpszBuf[0] = '\0';
  1324. }
  1325. }
  1326. else
  1327. {
  1328. char *pszBuf = new char[nMaxBuf];
  1329. if ( pszBuf )
  1330. {
  1331. nLen = ::LoadStringA(g_hModule, nID, pszBuf, nMaxBuf);
  1332. if (nLen == 0)
  1333. {
  1334. lpszBuf[0] = '\0';
  1335. }
  1336. else
  1337. {
  1338. nLen = ::MultiByteToWideChar(CP_ACP, 0, pszBuf, nLen + 1,
  1339. lpszBuf, nMaxBuf);
  1340. // Truncate to requested size
  1341. if (nLen > 0)
  1342. {
  1343. // nLen doesn't include the '\0'.
  1344. nLen = min(nMaxBuf - 1, (UINT) nLen - 1);
  1345. }
  1346. lpszBuf[nLen] = '\0';
  1347. }
  1348. delete pszBuf;
  1349. }
  1350. else
  1351. {
  1352. throw CHeap_Exception ( CHeap_Exception :: E_ALLOCATION_ERROR ) ;
  1353. }
  1354. }
  1355. return nLen; // excluding terminator
  1356. #endif
  1357. return 0;
  1358. }
  1359. #endif
  1360. #if (defined DEBUG || defined _DEBUG)
  1361. WCHAR CHString::GetAt(int nIndex) const
  1362. {
  1363. ASSERT_BREAK(nIndex >= 0);
  1364. ASSERT_BREAK(nIndex < GetData()->nDataLength);
  1365. return m_pchData[nIndex];
  1366. }
  1367. WCHAR CHString::operator[](int nIndex) const
  1368. {
  1369. ASSERT_BREAK(nIndex >= 0);
  1370. ASSERT_BREAK(nIndex < GetData()->nDataLength);
  1371. return m_pchData[nIndex];
  1372. }
  1373. #endif