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.

1937 lines
56 KiB

  1. // This is copied from the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) Microsoft Corporation, 1992 - 1999
  3. // All rights reserved.
  4. //
  5. // This has been modified from the original MFC version to provide
  6. // two classes: CStrW manipulates and stores only wide char strings,
  7. // and CStr uses TCHARs.
  8. //
  9. #include "pch.h"
  10. #include "proppage.h"
  11. #if !defined(UNICODE)
  12. #include <stdio.h>
  13. #endif
  14. #include "cstr.h"
  15. #if !defined(_wcsinc)
  16. #define _wcsinc(_pc) ((_pc)+1)
  17. #endif
  18. /////////////////////////////////////////////////////////////////////////////
  19. // static class data, special inlines
  20. // For an empty string, m_???Data will point here
  21. // (note: avoids a lot of NULL pointer tests when we call standard
  22. // C runtime libraries
  23. TCHAR strChNilT = '\0';
  24. // for creating empty key strings
  25. const CStr strEmptyStringT;
  26. void CStr::Init()
  27. {
  28. m_nDataLength = m_nAllocLength = 0;
  29. m_pchData = (LPTSTR)&strChNilT;
  30. }
  31. // declared static
  32. void CStr::SafeDelete(LPTSTR& lpch)
  33. {
  34. if (lpch != (LPTSTR)&strChNilT &&
  35. lpch)
  36. {
  37. delete[] lpch;
  38. lpch = 0;
  39. }
  40. }
  41. //////////////////////////////////////////////////////////////////////////////
  42. // Construction/Destruction
  43. CStr::CStr()
  44. {
  45. Init();
  46. }
  47. CStr::CStr(const CStr& stringSrc)
  48. {
  49. // if constructing a String from another String, we make a copy of the
  50. // original string data to enforce value semantics (i.e. each string
  51. // gets a copy of its own
  52. m_pchData = 0;
  53. stringSrc.AllocCopy(*this, stringSrc.m_nDataLength, 0, 0);
  54. }
  55. BOOL CStr::AllocBuffer(int nLen)
  56. // always allocate one extra character for '\0' termination
  57. // assumes [optimistically] that data length will equal allocation length
  58. {
  59. dspAssert(nLen >= 0);
  60. if (nLen == 0)
  61. {
  62. Init();
  63. }
  64. else
  65. {
  66. m_pchData = new TCHAR[nLen+1]; //REVIEW may throw an exception
  67. if (!m_pchData)
  68. {
  69. Empty();
  70. return FALSE;
  71. }
  72. m_pchData[nLen] = '\0';
  73. m_nDataLength = nLen;
  74. m_nAllocLength = nLen;
  75. }
  76. return TRUE;
  77. }
  78. void CStr::Empty()
  79. {
  80. SafeDelete(m_pchData);
  81. Init();
  82. dspAssert(m_nDataLength == 0);
  83. dspAssert(m_nAllocLength == 0);
  84. }
  85. CStr::~CStr()
  86. // free any attached data
  87. {
  88. SafeDelete(m_pchData);
  89. }
  90. //////////////////////////////////////////////////////////////////////////////
  91. // Helpers for the rest of the implementation
  92. static inline int SafeStrlenT(LPCTSTR lpsz)
  93. {
  94. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  95. return (lpsz == NULL) ? 0 : lstrlen(lpsz);
  96. }
  97. void CStr::AllocCopy(CStr& dest, int nCopyLen, int nCopyIndex,
  98. int nExtraLen) const
  99. {
  100. // will clone the data attached to this string
  101. // allocating 'nExtraLen' characters
  102. // Places results in uninitialized string 'dest'
  103. // Will copy the part or all of original data to start of new string
  104. int nNewLen = nCopyLen + nExtraLen;
  105. if (nNewLen == 0)
  106. {
  107. dest.SafeDelete(dest.m_pchData);
  108. dest.Init();
  109. }
  110. else
  111. {
  112. if (!dest.AllocBuffer(nNewLen)) return;
  113. memcpy(dest.m_pchData, &m_pchData[nCopyIndex], nCopyLen*sizeof(TCHAR));
  114. }
  115. }
  116. //////////////////////////////////////////////////////////////////////////////
  117. // More sophisticated construction
  118. CStr::CStr(LPCTSTR lpsz)
  119. {
  120. int nLen;
  121. if ((nLen = SafeStrlenT(lpsz)) == 0)
  122. Init();
  123. else
  124. {
  125. if (!AllocBuffer(nLen))
  126. {
  127. Init();
  128. return;
  129. }
  130. memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
  131. }
  132. }
  133. /////////////////////////////////////////////////////////////////////////////
  134. // Special conversion constructors
  135. #ifdef UNICODE
  136. CStr::CStr(LPCSTR lpsz)
  137. {
  138. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  139. if (nSrcLen == 0)
  140. Init();
  141. else
  142. {
  143. if (!AllocBuffer(nSrcLen))
  144. {
  145. Init();
  146. return;
  147. }
  148. mmc_mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  149. }
  150. }
  151. #else //UNICODE
  152. CStr::CStr(LPCWSTR lpsz)
  153. {
  154. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  155. if (nSrcLen == 0)
  156. Init();
  157. else
  158. {
  159. if (!AllocBuffer(nSrcLen*2))
  160. {
  161. Init();
  162. return;
  163. }
  164. mmc_wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  165. ReleaseBuffer();
  166. }
  167. }
  168. #endif //!UNICODE
  169. //////////////////////////////////////////////////////////////////////////////
  170. // Assignment operators
  171. // All assign a new value to the string
  172. // (a) first see if the buffer is big enough
  173. // (b) if enough room, copy on top of old buffer, set size and type
  174. // (c) otherwise free old string data, and create a new one
  175. //
  176. // All routines return the new string (but as a 'const CStr&' so that
  177. // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  178. //
  179. void CStr::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
  180. {
  181. // check if it will fit
  182. if (nSrcLen > m_nAllocLength)
  183. {
  184. // it won't fit, allocate another one
  185. Empty();
  186. if (!AllocBuffer(nSrcLen)) return;
  187. }
  188. if (nSrcLen != 0)
  189. memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
  190. m_nDataLength = nSrcLen;
  191. m_pchData[nSrcLen] = '\0';
  192. }
  193. const CStr& CStr::operator=(const CStr& stringSrc)
  194. {
  195. AssignCopy(stringSrc.m_nDataLength, stringSrc.m_pchData);
  196. return *this;
  197. }
  198. const CStr& CStr::operator=(LPCTSTR lpsz)
  199. {
  200. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  201. AssignCopy(SafeStrlenT(lpsz), lpsz);
  202. return *this;
  203. }
  204. /////////////////////////////////////////////////////////////////////////////
  205. // Special conversion assignment
  206. #ifdef UNICODE
  207. const CStr& CStr::operator=(LPCSTR lpsz)
  208. {
  209. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  210. // check if it will fit
  211. if (nSrcLen > m_nAllocLength)
  212. {
  213. // it won't fit, allocate another one
  214. Empty();
  215. if (!AllocBuffer(nSrcLen)) return *this;
  216. }
  217. if (nSrcLen != 0)
  218. mmc_mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  219. m_nDataLength = nSrcLen;
  220. m_pchData[nSrcLen] = '\0';
  221. return *this;
  222. }
  223. #else //!UNICODE
  224. const CStr& CStr::operator=(LPCWSTR lpsz)
  225. {
  226. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  227. nSrcLen *= 2;
  228. // check if it will fit
  229. if (nSrcLen > m_nAllocLength)
  230. {
  231. // it won't fit, allocate another one
  232. Empty();
  233. if (!AllocBuffer(nSrcLen)) return *this;
  234. }
  235. if (nSrcLen != 0)
  236. {
  237. mmc_wcstombsz(m_pchData, lpsz, nSrcLen+1);
  238. ReleaseBuffer();
  239. }
  240. return *this;
  241. }
  242. #endif //!UNICODE
  243. //////////////////////////////////////////////////////////////////////////////
  244. // concatenation
  245. // NOTE: "operator+" is done as friend functions for simplicity
  246. // There are three variants:
  247. // String + String
  248. // and for ? = TCHAR, LPCTSTR
  249. // String + ?
  250. // ? + String
  251. void CStr::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
  252. int nSrc2Len, LPCTSTR lpszSrc2Data)
  253. {
  254. // -- master concatenation routine
  255. // Concatenate two sources
  256. // -- assume that 'this' is a new String object
  257. int nNewLen = nSrc1Len + nSrc2Len;
  258. if (!AllocBuffer(nNewLen)) return;
  259. memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
  260. memcpy(&m_pchData[nSrc1Len], lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
  261. }
  262. CStr STRAPI operator+(const CStr& string1, const CStr& string2)
  263. {
  264. CStr s;
  265. s.ConcatCopy(string1.m_nDataLength, string1.m_pchData,
  266. string2.m_nDataLength, string2.m_pchData);
  267. return s;
  268. }
  269. CStr STRAPI operator+(const CStr& string, LPCTSTR lpsz)
  270. {
  271. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  272. CStr s;
  273. s.ConcatCopy(string.m_nDataLength, string.m_pchData, SafeStrlenT(lpsz), lpsz);
  274. return s;
  275. }
  276. CStr STRAPI operator+(LPCTSTR lpsz, const CStr& string)
  277. {
  278. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  279. CStr s;
  280. s.ConcatCopy(SafeStrlenT(lpsz), lpsz, string.m_nDataLength, string.m_pchData);
  281. return s;
  282. }
  283. //////////////////////////////////////////////////////////////////////////////
  284. // concatenate in place
  285. void CStr::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
  286. {
  287. // -- the main routine for += operators
  288. // if the buffer is too small, or we have a width mis-match, just
  289. // allocate a new buffer (slow but sure)
  290. if (m_nDataLength + nSrcLen > m_nAllocLength)
  291. {
  292. // we have to grow the buffer, use the Concat in place routine
  293. LPTSTR lpszOldData = m_pchData;
  294. ConcatCopy(m_nDataLength, lpszOldData, nSrcLen, lpszSrcData);
  295. dspAssert(lpszOldData != NULL);
  296. SafeDelete(lpszOldData);
  297. }
  298. else
  299. {
  300. // fast concatenation when buffer big enough
  301. memcpy(&m_pchData[m_nDataLength], lpszSrcData, nSrcLen*sizeof(TCHAR));
  302. m_nDataLength += nSrcLen;
  303. }
  304. dspAssert(m_nDataLength <= m_nAllocLength);
  305. m_pchData[m_nDataLength] = '\0';
  306. }
  307. const CStr& CStr::operator+=(LPCTSTR lpsz)
  308. {
  309. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  310. ConcatInPlace(SafeStrlenT(lpsz), lpsz);
  311. return *this;
  312. }
  313. const CStr& CStr::operator+=(TCHAR ch)
  314. {
  315. ConcatInPlace(1, &ch);
  316. return *this;
  317. }
  318. const CStr& CStr::operator+=(const CStr& string)
  319. {
  320. ConcatInPlace(string.m_nDataLength, string.m_pchData);
  321. return *this;
  322. }
  323. ///////////////////////////////////////////////////////////////////////////////
  324. // Advanced direct buffer access
  325. LPTSTR CStr::GetBuffer(int nMinBufLength)
  326. {
  327. dspAssert(nMinBufLength >= 0);
  328. if (nMinBufLength > m_nAllocLength)
  329. {
  330. // we have to grow the buffer
  331. LPTSTR lpszOldData = m_pchData;
  332. int nOldLen = m_nDataLength; // AllocBuffer will tromp it
  333. if (!AllocBuffer(nMinBufLength)) return NULL;
  334. memcpy(m_pchData, lpszOldData, nOldLen*sizeof(TCHAR));
  335. m_nDataLength = nOldLen;
  336. m_pchData[m_nDataLength] = '\0';
  337. SafeDelete(lpszOldData);
  338. }
  339. // return a pointer to the character storage for this string
  340. dspAssert(m_pchData != NULL);
  341. return m_pchData;
  342. }
  343. void CStr::ReleaseBuffer(int nNewLength)
  344. {
  345. if (nNewLength == -1)
  346. nNewLength = lstrlen(m_pchData); // zero terminated
  347. dspAssert(nNewLength <= m_nAllocLength);
  348. m_nDataLength = nNewLength;
  349. m_pchData[m_nDataLength] = '\0';
  350. }
  351. LPTSTR CStr::GetBufferSetLength(int nNewLength)
  352. {
  353. dspAssert(nNewLength >= 0);
  354. GetBuffer(nNewLength);
  355. m_nDataLength = nNewLength;
  356. m_pchData[m_nDataLength] = '\0';
  357. return m_pchData;
  358. }
  359. void CStr::FreeExtra()
  360. {
  361. dspAssert(m_nDataLength <= m_nAllocLength);
  362. if (m_nDataLength != m_nAllocLength)
  363. {
  364. LPTSTR lpszOldData = m_pchData;
  365. if (!AllocBuffer(m_nDataLength)) return;
  366. memcpy(m_pchData, lpszOldData, m_nDataLength*sizeof(TCHAR));
  367. dspAssert(m_pchData[m_nDataLength] == '\0');
  368. SafeDelete(lpszOldData);
  369. }
  370. dspAssert(m_pchData != NULL);
  371. }
  372. ///////////////////////////////////////////////////////////////////////////////
  373. // Commonly used routines (rarely used routines in STREX.CPP)
  374. int CStr::Find(TCHAR ch) const
  375. {
  376. // find first single character
  377. LPTSTR lpsz = _tcschr(m_pchData, ch);
  378. // return -1 if not found and index otherwise
  379. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  380. }
  381. int CStr::FindOneOf(LPCTSTR lpszCharSet) const
  382. {
  383. dspAssert(IsValidString(lpszCharSet, FALSE));
  384. LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);
  385. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  386. }
  387. ///////////////////////////////////////////////////////////////////////////////
  388. // String conversion helpers (these use the current system locale)
  389. int mmc_wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
  390. {
  391. if (count == 0 && mbstr != NULL)
  392. return 0;
  393. int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1,
  394. mbstr, static_cast<int>(count), NULL, NULL);
  395. dspAssert(mbstr == NULL || result <= (int)count);
  396. if (result > 0)
  397. mbstr[result-1] = 0;
  398. return result;
  399. }
  400. int mmc_mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
  401. {
  402. if (count == 0 && wcstr != NULL)
  403. return 0;
  404. int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1,
  405. wcstr, static_cast<int>(count));
  406. dspAssert(wcstr == NULL || result <= (int)count);
  407. if (result > 0)
  408. wcstr[result-1] = 0;
  409. return result;
  410. }
  411. /////////////////////////////////////////////////////////////////////////////
  412. // Windows extensions to strings
  413. BOOL CStr::LoadString(HINSTANCE hInst, UINT nID)
  414. {
  415. dspAssert(nID != 0); // 0 is an illegal string ID
  416. // Note: resource strings limited to 511 characters
  417. TCHAR szBuffer[512];
  418. UINT nSize = StrLoadString(hInst, nID, szBuffer);
  419. AssignCopy(nSize, szBuffer);
  420. return nSize > 0;
  421. }
  422. int STRAPI StrLoadString(HINSTANCE hInst, UINT nID, LPTSTR lpszBuf)
  423. {
  424. dspAssert(IsValidAddressz(lpszBuf, 512)); // must be big enough for 512 bytes
  425. #ifdef DBG
  426. // LoadString without annoying warning from the Debug kernel if the
  427. // segment containing the string is not present
  428. if (::FindResource(hInst, MAKEINTRESOURCE((nID>>4)+1), RT_STRING) == NULL)
  429. {
  430. lpszBuf[0] = '\0';
  431. return 0; // not found
  432. }
  433. #endif //DBG
  434. int nLen = ::LoadString(hInst, nID, lpszBuf, 511);
  435. dspAssert(nLen);
  436. if (nLen == 0)
  437. lpszBuf[0] = '\0';
  438. return nLen;
  439. }
  440. BOOL STRAPI IsValidAddressz(const void* lp, UINT nBytes, BOOL bReadWrite)
  441. {
  442. // simple version using Win-32 APIs for pointer validation.
  443. return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
  444. (!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
  445. }
  446. BOOL STRAPI IsValidString(LPCSTR lpsz, int nLength)
  447. {
  448. if (lpsz == NULL)
  449. return FALSE;
  450. return ::IsBadStringPtrA(lpsz, nLength) == 0;
  451. }
  452. BOOL STRAPI IsValidString(LPCWSTR lpsz, int nLength)
  453. {
  454. if (lpsz == NULL)
  455. return FALSE;
  456. return ::IsBadStringPtrW(lpsz, nLength) == 0;
  457. }
  458. #ifdef OLE_AUTOMATION
  459. #ifdef UNICODE
  460. BSTR CStr::AllocSysString()
  461. {
  462. BSTR bstr = ::SysAllocStringLen(m_pchData, m_nDataLength);
  463. if (bstr == NULL)
  464. ;//REVIEW AfxThrowMemoryException();
  465. return bstr;
  466. }
  467. BSTR CStr::SetSysString(BSTR* pbstr)
  468. {
  469. dspAssert(IsValidAddressz(pbstr, sizeof(BSTR)));
  470. if (!::SysReAllocStringLen(pbstr, m_pchData, m_nDataLength))
  471. ; //REVIEW AfxThrowMemoryException();
  472. dspAssert(*pbstr != NULL);
  473. return *pbstr;
  474. }
  475. #endif
  476. #endif // #ifdef OLE_AUTOMATION
  477. ///////////////////////////////////////////////////////////////////////////////
  478. // Orginally from StrEx.cpp
  479. CStr::CStr(TCHAR ch, int nLength)
  480. {
  481. #ifndef UNICODE
  482. dspAssert(!IsDBCSLeadByte(ch)); // can't create a lead byte string
  483. #endif
  484. if (nLength < 1)
  485. {
  486. // return empty string if invalid repeat count
  487. Init();
  488. }
  489. else
  490. {
  491. if (!AllocBuffer(nLength))
  492. {
  493. Init();
  494. return;
  495. }
  496. #ifdef UNICODE
  497. for (int i = 0; i < nLength; i++)
  498. m_pchData[i] = ch;
  499. #else
  500. memset(m_pchData, ch, nLength);
  501. #endif
  502. }
  503. }
  504. CStr::CStr(LPCTSTR lpch, int nLength)
  505. {
  506. if (nLength == 0)
  507. Init();
  508. else
  509. {
  510. dspAssert(IsValidAddressz(lpch, nLength, FALSE));
  511. if (!AllocBuffer(nLength))
  512. {
  513. Init();
  514. return;
  515. }
  516. memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
  517. }
  518. }
  519. //////////////////////////////////////////////////////////////////////////////
  520. // Assignment operators
  521. const CStr& CStr::operator=(TCHAR ch)
  522. {
  523. #ifndef UNICODE
  524. dspAssert(!IsDBCSLeadByte(ch)); // can't set single lead byte
  525. #endif
  526. AssignCopy(1, &ch);
  527. return *this;
  528. }
  529. //////////////////////////////////////////////////////////////////////////////
  530. // less common string expressions
  531. CStr STRAPI operator+(const CStr& string1, TCHAR ch)
  532. {
  533. CStr s;
  534. s.ConcatCopy(string1.m_nDataLength, string1.m_pchData, 1, &ch);
  535. return s;
  536. }
  537. CStr STRAPI operator+(TCHAR ch, const CStr& string)
  538. {
  539. CStr s;
  540. s.ConcatCopy(1, &ch, string.m_nDataLength, string.m_pchData);
  541. return s;
  542. }
  543. //////////////////////////////////////////////////////////////////////////////
  544. // Very simple sub-string extraction
  545. CStr CStr::Mid(int nFirst) const
  546. {
  547. return Mid(nFirst, m_nDataLength - nFirst);
  548. }
  549. CStr CStr::Mid(int nFirst, int nCount) const
  550. {
  551. dspAssert(nFirst >= 0);
  552. dspAssert(nCount >= 0);
  553. // out-of-bounds requests return sensible things
  554. if (nFirst + nCount > m_nDataLength)
  555. nCount = m_nDataLength - nFirst;
  556. if (nFirst > m_nDataLength)
  557. nCount = 0;
  558. CStr dest;
  559. AllocCopy(dest, nCount, nFirst, 0);
  560. return dest;
  561. }
  562. CStr CStr::Right(int nCount) const
  563. {
  564. dspAssert(nCount >= 0);
  565. if (nCount > m_nDataLength)
  566. nCount = m_nDataLength;
  567. CStr dest;
  568. AllocCopy(dest, nCount, m_nDataLength-nCount, 0);
  569. return dest;
  570. }
  571. CStr CStr::Left(int nCount) const
  572. {
  573. dspAssert(nCount >= 0);
  574. if (nCount > m_nDataLength)
  575. nCount = m_nDataLength;
  576. CStr dest;
  577. AllocCopy(dest, nCount, 0, 0);
  578. return dest;
  579. }
  580. // strspn equivalent
  581. CStr CStr::SpanIncluding(LPCTSTR lpszCharSet) const
  582. {
  583. dspAssert(IsValidString(lpszCharSet, FALSE));
  584. return Left(static_cast<int>(_tcsspn(m_pchData, lpszCharSet)));
  585. }
  586. // strcspn equivalent
  587. CStr CStr::SpanExcluding(LPCTSTR lpszCharSet) const
  588. {
  589. dspAssert(IsValidString(lpszCharSet, FALSE));
  590. return Left(static_cast<int>(_tcscspn(m_pchData, lpszCharSet)));
  591. }
  592. //////////////////////////////////////////////////////////////////////////////
  593. // Finding
  594. int CStr::ReverseFind(TCHAR ch) const
  595. {
  596. // find last single character
  597. LPTSTR lpsz = _tcsrchr(m_pchData, ch);
  598. // return -1 if not found, distance from beginning otherwise
  599. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  600. }
  601. // find a sub-string (like strstr)
  602. int CStr::Find(LPCTSTR lpszSub) const
  603. {
  604. dspAssert(IsValidString(lpszSub, FALSE));
  605. // find first matching substring
  606. LPTSTR lpsz = _tcsstr(m_pchData, lpszSub);
  607. // return -1 for not found, distance from beginning otherwise
  608. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  609. }
  610. /////////////////////////////////////////////////////////////////////////////
  611. // String formatting
  612. #define FORCE_ANSI 0x10000
  613. #define FORCE_UNICODE 0x20000
  614. // formatting (using wsprintf style formatting)
  615. void CStr::Format(LPCTSTR lpszFormat, ...)
  616. {
  617. dspAssert(IsValidString(lpszFormat, FALSE));
  618. va_list argList;
  619. va_start(argList, lpszFormat);
  620. // make a guess at the maximum length of the resulting string
  621. size_t nMaxLen = 0;
  622. for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  623. {
  624. // handle '%' character, but watch out for '%%'
  625. if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
  626. {
  627. nMaxLen += _tclen(lpsz);
  628. continue;
  629. }
  630. size_t nItemLen = 0;
  631. // handle '%' character with format
  632. int nWidth = 0;
  633. for (; *lpsz != '\0'; lpsz = _tcsinc(lpsz))
  634. {
  635. // check for valid flags
  636. if (*lpsz == '#')
  637. nMaxLen += 2; // for '0x'
  638. else if (*lpsz == '*')
  639. nWidth = va_arg(argList, int);
  640. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  641. *lpsz == ' ')
  642. ;
  643. else // hit non-flag character
  644. break;
  645. }
  646. // get width and skip it
  647. if (nWidth == 0)
  648. {
  649. // width indicated by
  650. nWidth = _ttoi(lpsz);
  651. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  652. ;
  653. }
  654. dspAssert(nWidth >= 0);
  655. int nPrecision = 0;
  656. if (*lpsz == '.')
  657. {
  658. // skip past '.' separator (width.precision)
  659. lpsz = _tcsinc(lpsz);
  660. // get precision and skip it
  661. if (*lpsz == '*')
  662. {
  663. nPrecision = va_arg(argList, int);
  664. lpsz = _tcsinc(lpsz);
  665. }
  666. else
  667. {
  668. nPrecision = _ttoi(lpsz);
  669. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  670. ;
  671. }
  672. dspAssert(nPrecision >= 0);
  673. }
  674. // should be on type modifier or specifier
  675. int nModifier = 0;
  676. switch (*lpsz)
  677. {
  678. // modifiers that affect size
  679. case 'h':
  680. nModifier = FORCE_ANSI;
  681. lpsz = _tcsinc(lpsz);
  682. break;
  683. case 'l':
  684. nModifier = FORCE_UNICODE;
  685. lpsz = _tcsinc(lpsz);
  686. break;
  687. // modifiers that do not affect size
  688. case 'F':
  689. case 'N':
  690. case 'L':
  691. lpsz = _tcsinc(lpsz);
  692. break;
  693. }
  694. // now should be on specifier
  695. switch (*lpsz | nModifier)
  696. {
  697. // single characters
  698. case 'c':
  699. case 'C':
  700. nItemLen = 2;
  701. va_arg(argList, TCHAR);
  702. break;
  703. case 'c'|FORCE_ANSI:
  704. case 'C'|FORCE_ANSI:
  705. nItemLen = 2;
  706. va_arg(argList, char);
  707. break;
  708. case 'c'|FORCE_UNICODE:
  709. case 'C'|FORCE_UNICODE:
  710. nItemLen = 2;
  711. va_arg(argList, WCHAR);
  712. break;
  713. // strings
  714. case 's':
  715. case 'S':
  716. nItemLen = lstrlen(va_arg(argList, LPCTSTR));
  717. nItemLen = __max(1, nItemLen);
  718. break;
  719. case 's'|FORCE_ANSI:
  720. case 'S'|FORCE_ANSI:
  721. nItemLen = lstrlenA(va_arg(argList, LPCSTR));
  722. nItemLen = __max(1, nItemLen);
  723. break;
  724. #ifndef _MAC
  725. case 's'|FORCE_UNICODE:
  726. case 'S'|FORCE_UNICODE:
  727. nItemLen = wcslen(va_arg(argList, LPWSTR));
  728. nItemLen = __max(1, nItemLen);
  729. break;
  730. #endif
  731. }
  732. // adjust nItemLen for strings
  733. if (nItemLen != 0)
  734. {
  735. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth));
  736. if (nPrecision != 0)
  737. nItemLen = __min(nItemLen, static_cast<UINT>(nPrecision));
  738. }
  739. else
  740. {
  741. switch (*lpsz)
  742. {
  743. // integers
  744. case 'd':
  745. case 'i':
  746. case 'u':
  747. case 'x':
  748. case 'X':
  749. case 'o':
  750. va_arg(argList, int);
  751. nItemLen = 32;
  752. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth+nPrecision));
  753. break;
  754. case 'e':
  755. case 'f':
  756. case 'g':
  757. case 'G':
  758. va_arg(argList, _STR_DOUBLE);
  759. nItemLen = 128;
  760. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth+nPrecision));
  761. break;
  762. case 'p':
  763. va_arg(argList, void*);
  764. nItemLen = 32;
  765. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth+nPrecision));
  766. break;
  767. // no output
  768. case 'n':
  769. va_arg(argList, int*);
  770. break;
  771. default:
  772. dspAssert(FALSE); // unknown formatting option
  773. }
  774. }
  775. // adjust nMaxLen for output nItemLen
  776. nMaxLen += nItemLen;
  777. }
  778. va_end(argList);
  779. // finally, set the buffer length and format the string
  780. va_start(argList, lpszFormat); // restart the arg list
  781. GetBuffer(static_cast<int>(nMaxLen));
  782. if (_vstprintf(m_pchData, lpszFormat, argList) > static_cast<int>(nMaxLen))
  783. {
  784. dspAssert(FALSE);
  785. }
  786. ReleaseBuffer();
  787. va_end(argList);
  788. }
  789. void CStr::TrimRight()
  790. {
  791. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  792. LPTSTR lpsz = m_pchData;
  793. LPTSTR lpszLast = NULL;
  794. while (*lpsz != '\0')
  795. {
  796. if (_istspace(*lpsz))
  797. {
  798. if (lpszLast == NULL)
  799. lpszLast = lpsz;
  800. }
  801. else
  802. lpszLast = NULL;
  803. lpsz = _tcsinc(lpsz);
  804. }
  805. if (lpszLast != NULL)
  806. {
  807. // truncate at trailing space start
  808. *lpszLast = '\0';
  809. m_nDataLength = (int)(lpszLast - m_pchData);
  810. }
  811. }
  812. void CStr::TrimLeft()
  813. {
  814. // find first non-space character
  815. LPCTSTR lpsz = m_pchData;
  816. while (_istspace(*lpsz))
  817. lpsz = _tcsinc(lpsz);
  818. // fix up data and length
  819. int nDataLength = (int)(m_nDataLength - (lpsz - m_pchData));
  820. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  821. m_nDataLength = nDataLength;
  822. }
  823. ///////////////////////////////////////////////////////////////////////////////
  824. // String support for template collections
  825. void STRAPI ConstructElements(CStr* pElements, int nCount)
  826. {
  827. dspAssert(IsValidAddressz(pElements, nCount * sizeof(CStr)));
  828. for (; nCount--; ++pElements)
  829. memcpy(pElements, &strEmptyStringT, sizeof(*pElements));
  830. }
  831. void STRAPI DestructElements(CStr* pElements, int nCount)
  832. {
  833. dspAssert(IsValidAddressz(pElements, nCount * sizeof(CStr)));
  834. for (; nCount--; ++pElements)
  835. pElements->Empty();
  836. }
  837. //
  838. // Added by JonN 4/16/98
  839. //
  840. void FreeCStrList( IN OUT CStrListItem** ppList )
  841. {
  842. dspAssert( NULL != ppList );
  843. while (NULL != *ppList)
  844. {
  845. CStrListItem* pTemp = (*ppList)->pnext;
  846. delete *ppList;
  847. *ppList = pTemp;
  848. }
  849. }
  850. void CStrListAdd( IN OUT CStrListItem** ppList, IN LPCTSTR lpsz )
  851. {
  852. dspAssert( NULL != ppList );
  853. CStrListItem* pnewitem = new CStrListItem;
  854. if (pnewitem != NULL)
  855. {
  856. pnewitem->str = lpsz;
  857. pnewitem->pnext = *ppList;
  858. *ppList = pnewitem;
  859. }
  860. }
  861. bool CStrListContains( IN CStrListItem** ppList, IN LPCTSTR lpsz )
  862. {
  863. dspAssert( NULL != ppList );
  864. for (CStrListItem* pList = *ppList; NULL != pList; pList = pList->pnext)
  865. {
  866. if ( !_tcsicmp( lpsz, pList->str ) )
  867. return true;
  868. }
  869. return false;
  870. }
  871. int CountCStrList( IN CStrListItem** ppList )
  872. {
  873. dspAssert( NULL != ppList );
  874. int cCount = 0;
  875. for (CStrListItem* pList = *ppList; NULL != pList; pList = pList->pnext)
  876. {
  877. cCount++;
  878. }
  879. return cCount;
  880. }
  881. /////////////////////////////////////////////////////////////////////////////
  882. // static class data, special inlines
  883. // For an empty string, m_???Data will point here
  884. // (note: avoids a lot of NULL pointer tests when we call standard
  885. // C runtime libraries
  886. WCHAR strChNilW = '\0';
  887. // for creating empty key strings
  888. const CStrW strEmptyStringW;
  889. void CStrW::Init()
  890. {
  891. m_nDataLength = m_nAllocLength = 0;
  892. m_pchData = (PWSTR)&strChNilW;
  893. }
  894. // declared static
  895. void CStrW::SafeDelete(PWSTR& lpch)
  896. {
  897. if (lpch != (PWSTR)&strChNilW &&
  898. lpch)
  899. {
  900. delete[] lpch;
  901. lpch = 0;
  902. }
  903. }
  904. //////////////////////////////////////////////////////////////////////////////
  905. // Construction/Destruction
  906. CStrW::CStrW()
  907. {
  908. Init();
  909. }
  910. CStrW::CStrW(const CStrW& stringSrc)
  911. {
  912. // if constructing a String from another String, we make a copy of the
  913. // original string data to enforce value semantics (i.e. each string
  914. // gets a copy of its own
  915. stringSrc.AllocCopy(*this, stringSrc.m_nDataLength, 0, 0);
  916. }
  917. BOOL CStrW::AllocBuffer(int nLen)
  918. // always allocate one extra character for '\0' termination
  919. // assumes [optimistically] that data length will equal allocation length
  920. {
  921. dspAssert(nLen >= 0);
  922. if (nLen == 0)
  923. {
  924. Empty();
  925. }
  926. else
  927. {
  928. m_pchData = new WCHAR[nLen+1]; //REVIEW may throw an exception
  929. if (!m_pchData)
  930. {
  931. Empty();
  932. return FALSE;
  933. }
  934. m_pchData[nLen] = '\0';
  935. m_nDataLength = nLen;
  936. m_nAllocLength = nLen;
  937. }
  938. return TRUE;
  939. }
  940. void CStrW::Empty()
  941. {
  942. SafeDelete(m_pchData);
  943. Init();
  944. dspAssert(m_nDataLength == 0);
  945. dspAssert(m_nAllocLength == 0);
  946. }
  947. CStrW::~CStrW()
  948. // free any attached data
  949. {
  950. SafeDelete(m_pchData);
  951. }
  952. //////////////////////////////////////////////////////////////////////////////
  953. // Helpers for the rest of the implementation
  954. static inline int SafeStrlen(LPCWSTR lpsz)
  955. {
  956. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  957. return (int)((lpsz == NULL) ? 0 : wcslen(lpsz));
  958. }
  959. void CStrW::AllocCopy(CStrW& dest, int nCopyLen, int nCopyIndex,
  960. int nExtraLen) const
  961. {
  962. // will clone the data attached to this string
  963. // allocating 'nExtraLen' characters
  964. // Places results in uninitialized string 'dest'
  965. // Will copy the part or all of original data to start of new string
  966. int nNewLen = nCopyLen + nExtraLen;
  967. if (nNewLen == 0)
  968. {
  969. dest.Empty();
  970. }
  971. else
  972. {
  973. if (!dest.AllocBuffer(nNewLen)) return;
  974. memcpy(dest.m_pchData, &m_pchData[nCopyIndex], nCopyLen*sizeof(WCHAR));
  975. }
  976. }
  977. //////////////////////////////////////////////////////////////////////////////
  978. // More sophisticated construction
  979. CStrW::CStrW(LPCWSTR lpsz)
  980. {
  981. int nLen;
  982. if ((nLen = SafeStrlen(lpsz)) == 0)
  983. Init();
  984. else
  985. {
  986. if (!AllocBuffer(nLen))
  987. {
  988. Init();
  989. return;
  990. }
  991. memcpy(m_pchData, lpsz, nLen*sizeof(WCHAR));
  992. }
  993. }
  994. /////////////////////////////////////////////////////////////////////////////
  995. // Special conversion constructors
  996. CStrW::CStrW(LPCSTR lpsz)
  997. {
  998. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  999. if (nSrcLen == 0)
  1000. Init();
  1001. else
  1002. {
  1003. if (!AllocBuffer(nSrcLen))
  1004. {
  1005. Init();
  1006. return;
  1007. }
  1008. mmc_mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  1009. }
  1010. }
  1011. //////////////////////////////////////////////////////////////////////////////
  1012. // Assignment operators
  1013. // All assign a new value to the string
  1014. // (a) first see if the buffer is big enough
  1015. // (b) if enough room, copy on top of old buffer, set size and type
  1016. // (c) otherwise free old string data, and create a new one
  1017. //
  1018. // All routines return the new string (but as a 'const CStrW&' so that
  1019. // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  1020. //
  1021. void CStrW::AssignCopy(int nSrcLen, LPCWSTR lpszSrcData)
  1022. {
  1023. // check if it will fit
  1024. if (nSrcLen > m_nAllocLength)
  1025. {
  1026. // it won't fit, allocate another one
  1027. Empty();
  1028. if (!AllocBuffer(nSrcLen)) return;
  1029. }
  1030. if (nSrcLen != 0)
  1031. memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(WCHAR));
  1032. m_nDataLength = nSrcLen;
  1033. m_pchData[nSrcLen] = '\0';
  1034. }
  1035. const CStrW& CStrW::operator=(const CStrW& stringSrc)
  1036. {
  1037. AssignCopy(stringSrc.m_nDataLength, stringSrc.m_pchData);
  1038. return *this;
  1039. }
  1040. const CStrW& CStrW::operator=(LPCWSTR lpsz)
  1041. {
  1042. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  1043. AssignCopy(SafeStrlen(lpsz), lpsz);
  1044. return *this;
  1045. }
  1046. const CStrW& CStrW::operator=(UNICODE_STRING unistr)
  1047. {
  1048. AssignCopy(unistr.Length/2, unistr.Buffer);
  1049. return *this;
  1050. }
  1051. const CStrW& CStrW::operator=(UNICODE_STRING * punistr)
  1052. {
  1053. AssignCopy(punistr->Length/2, punistr->Buffer);
  1054. return *this;
  1055. }
  1056. /////////////////////////////////////////////////////////////////////////////
  1057. // Special conversion assignment
  1058. const CStrW& CStrW::operator=(LPCSTR lpsz)
  1059. {
  1060. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  1061. // check if it will fit
  1062. if (nSrcLen > m_nAllocLength)
  1063. {
  1064. // it won't fit, allocate another one
  1065. Empty();
  1066. if (!AllocBuffer(nSrcLen)) return *this;
  1067. }
  1068. if (nSrcLen != 0)
  1069. mmc_mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  1070. m_nDataLength = nSrcLen;
  1071. m_pchData[nSrcLen] = '\0';
  1072. return *this;
  1073. }
  1074. //////////////////////////////////////////////////////////////////////////////
  1075. // concatenation
  1076. // NOTE: "operator+" is done as friend functions for simplicity
  1077. // There are three variants:
  1078. // String + String
  1079. // and for ? = WCHAR, LPCWSTR
  1080. // String + ?
  1081. // ? + String
  1082. void CStrW::ConcatCopy(int nSrc1Len, LPCWSTR lpszSrc1Data,
  1083. int nSrc2Len, LPCWSTR lpszSrc2Data)
  1084. {
  1085. // -- master concatenation routine
  1086. // Concatenate two sources
  1087. // -- assume that 'this' is a new String object
  1088. int nNewLen = nSrc1Len + nSrc2Len;
  1089. if (!AllocBuffer(nNewLen)) return;
  1090. memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(WCHAR));
  1091. memcpy(&m_pchData[nSrc1Len], lpszSrc2Data, nSrc2Len*sizeof(WCHAR));
  1092. }
  1093. CStrW STRAPI operator+(const CStrW& string1, const CStrW& string2)
  1094. {
  1095. CStrW s;
  1096. s.ConcatCopy(string1.m_nDataLength, string1.m_pchData,
  1097. string2.m_nDataLength, string2.m_pchData);
  1098. return s;
  1099. }
  1100. CStrW STRAPI operator+(const CStrW& string, LPCWSTR lpsz)
  1101. {
  1102. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  1103. CStrW s;
  1104. s.ConcatCopy(string.m_nDataLength, string.m_pchData, SafeStrlen(lpsz), lpsz);
  1105. return s;
  1106. }
  1107. CStrW STRAPI operator+(LPCWSTR lpsz, const CStrW& string)
  1108. {
  1109. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  1110. CStrW s;
  1111. s.ConcatCopy(SafeStrlen(lpsz), lpsz, string.m_nDataLength, string.m_pchData);
  1112. return s;
  1113. }
  1114. //////////////////////////////////////////////////////////////////////////////
  1115. // concatenate in place
  1116. void CStrW::ConcatInPlace(int nSrcLen, LPCWSTR lpszSrcData)
  1117. {
  1118. // -- the main routine for += operators
  1119. // if the buffer is too small, or we have a width mis-match, just
  1120. // allocate a new buffer (slow but sure)
  1121. if (m_nDataLength + nSrcLen > m_nAllocLength)
  1122. {
  1123. // we have to grow the buffer, use the Concat in place routine
  1124. PWSTR lpszOldData = m_pchData;
  1125. ConcatCopy(m_nDataLength, lpszOldData, nSrcLen, lpszSrcData);
  1126. dspAssert(lpszOldData != NULL);
  1127. SafeDelete(lpszOldData);
  1128. }
  1129. else
  1130. {
  1131. // fast concatenation when buffer big enough
  1132. memcpy(&m_pchData[m_nDataLength], lpszSrcData, nSrcLen*sizeof(WCHAR));
  1133. m_nDataLength += nSrcLen;
  1134. }
  1135. dspAssert(m_nDataLength <= m_nAllocLength);
  1136. m_pchData[m_nDataLength] = '\0';
  1137. }
  1138. const CStrW& CStrW::operator+=(LPCWSTR lpsz)
  1139. {
  1140. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  1141. ConcatInPlace(SafeStrlen(lpsz), lpsz);
  1142. return *this;
  1143. }
  1144. const CStrW& CStrW::operator+=(WCHAR ch)
  1145. {
  1146. ConcatInPlace(1, &ch);
  1147. return *this;
  1148. }
  1149. const CStrW& CStrW::operator+=(const CStrW& string)
  1150. {
  1151. ConcatInPlace(string.m_nDataLength, string.m_pchData);
  1152. return *this;
  1153. }
  1154. ///////////////////////////////////////////////////////////////////////////////
  1155. // Advanced direct buffer access
  1156. PWSTR CStrW::GetBuffer(int nMinBufLength)
  1157. {
  1158. dspAssert(nMinBufLength >= 0);
  1159. if (nMinBufLength > m_nAllocLength)
  1160. {
  1161. // we have to grow the buffer
  1162. PWSTR lpszOldData = m_pchData;
  1163. int nOldLen = m_nDataLength; // AllocBuffer will tromp it
  1164. if (!AllocBuffer(nMinBufLength)) return NULL;
  1165. memcpy(m_pchData, lpszOldData, nOldLen*sizeof(WCHAR));
  1166. m_nDataLength = nOldLen;
  1167. m_pchData[m_nDataLength] = '\0';
  1168. SafeDelete(lpszOldData);
  1169. }
  1170. // return a pointer to the character storage for this string
  1171. dspAssert(m_pchData != NULL);
  1172. return m_pchData;
  1173. }
  1174. void CStrW::ReleaseBuffer(int nNewLength)
  1175. {
  1176. if (nNewLength == -1)
  1177. nNewLength = static_cast<int>(wcslen(m_pchData)); // zero terminated
  1178. dspAssert(nNewLength <= m_nAllocLength);
  1179. m_nDataLength = nNewLength;
  1180. m_pchData[m_nDataLength] = '\0';
  1181. }
  1182. PWSTR CStrW::GetBufferSetLength(int nNewLength)
  1183. {
  1184. dspAssert(nNewLength >= 0);
  1185. GetBuffer(nNewLength);
  1186. m_nDataLength = nNewLength;
  1187. m_pchData[m_nDataLength] = '\0';
  1188. return m_pchData;
  1189. }
  1190. void CStrW::FreeExtra()
  1191. {
  1192. dspAssert(m_nDataLength <= m_nAllocLength);
  1193. if (m_nDataLength != m_nAllocLength)
  1194. {
  1195. PWSTR lpszOldData = m_pchData;
  1196. if (!AllocBuffer(m_nDataLength)) return;
  1197. memcpy(m_pchData, lpszOldData, m_nDataLength*sizeof(WCHAR));
  1198. dspAssert(m_pchData[m_nDataLength] == '\0');
  1199. SafeDelete(lpszOldData);
  1200. }
  1201. dspAssert(m_pchData != NULL);
  1202. }
  1203. ///////////////////////////////////////////////////////////////////////////////
  1204. // Commonly used routines (rarely used routines in STREX.CPP)
  1205. int CStrW::Find(WCHAR ch) const
  1206. {
  1207. // find first single character
  1208. PWSTR lpsz = wcschr(m_pchData, ch);
  1209. // return -1 if not found and index otherwise
  1210. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1211. }
  1212. int CStrW::FindOneOf(LPCWSTR lpszCharSet) const
  1213. {
  1214. dspAssert(IsValidString(lpszCharSet, FALSE));
  1215. PWSTR lpsz = wcspbrk(m_pchData, lpszCharSet);
  1216. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1217. }
  1218. /////////////////////////////////////////////////////////////////////////////
  1219. // Windows extensions to strings
  1220. BOOL CStrW::LoadString(HINSTANCE hInst, UINT nID)
  1221. {
  1222. dspAssert(nID != 0); // 0 is an illegal string ID
  1223. // Note: resource strings limited to 511 characters
  1224. WCHAR szBuffer[512];
  1225. UINT nSize = StrLoadStringW(hInst, nID, szBuffer);
  1226. AssignCopy(nSize, szBuffer);
  1227. return nSize > 0;
  1228. }
  1229. int STRAPI StrLoadStringW(HINSTANCE hInst, UINT nID, LPWSTR lpszBuf)
  1230. {
  1231. dspAssert(IsValidAddressz(lpszBuf, 512)); // must be big enough for 512 bytes
  1232. #ifdef DBG
  1233. // LoadString without annoying warning from the Debug kernel if the
  1234. // segment containing the string is not present
  1235. if (::FindResource(hInst, MAKEINTRESOURCE((nID>>4)+1), RT_STRING) == NULL)
  1236. {
  1237. lpszBuf[0] = '\0';
  1238. return 0; // not found
  1239. }
  1240. #endif //DBG
  1241. int nLen = ::LoadStringW(hInst, nID, lpszBuf, 511);
  1242. dspAssert(nLen);
  1243. if (nLen == 0)
  1244. lpszBuf[0] = '\0';
  1245. return nLen;
  1246. }
  1247. #ifdef OLE_AUTOMATION
  1248. #ifdef UNICODE
  1249. BSTR CStrW::AllocSysString()
  1250. {
  1251. BSTR bstr = ::SysAllocStringLen(m_pchData, m_nDataLength);
  1252. if (bstr == NULL)
  1253. ;//REVIEW AfxThrowMemoryException();
  1254. return bstr;
  1255. }
  1256. BSTR CStrW::SetSysString(BSTR* pbstr)
  1257. {
  1258. dspAssert(IsValidAddressz(pbstr, sizeof(BSTR)));
  1259. if (!::SysReAllocStringLen(pbstr, m_pchData, m_nDataLength))
  1260. ; //REVIEW AfxThrowMemoryException();
  1261. dspAssert(*pbstr != NULL);
  1262. return *pbstr;
  1263. }
  1264. #endif
  1265. #endif // #ifdef OLE_AUTOMATION
  1266. ///////////////////////////////////////////////////////////////////////////////
  1267. // Orginally from StrEx.cpp
  1268. CStrW::CStrW(WCHAR ch, int nLength)
  1269. {
  1270. if (nLength < 1)
  1271. {
  1272. // return empty string if invalid repeat count
  1273. Init();
  1274. }
  1275. else
  1276. {
  1277. if (!AllocBuffer(nLength))
  1278. {
  1279. Init();
  1280. return;
  1281. }
  1282. #ifdef UNICODE
  1283. for (int i = 0; i < nLength; i++)
  1284. m_pchData[i] = ch;
  1285. #else
  1286. memset(m_pchData, ch, nLength);
  1287. #endif
  1288. }
  1289. }
  1290. CStrW::CStrW(LPCWSTR lpch, int nLength)
  1291. {
  1292. if (nLength == 0)
  1293. Init();
  1294. else
  1295. {
  1296. dspAssert(IsValidAddressz(lpch, nLength, FALSE));
  1297. if (!AllocBuffer(nLength))
  1298. {
  1299. Init();
  1300. return;
  1301. }
  1302. memcpy(m_pchData, lpch, nLength*sizeof(WCHAR));
  1303. }
  1304. }
  1305. //////////////////////////////////////////////////////////////////////////////
  1306. // Assignment operators
  1307. const CStrW& CStrW::operator=(WCHAR ch)
  1308. {
  1309. AssignCopy(1, &ch);
  1310. return *this;
  1311. }
  1312. //////////////////////////////////////////////////////////////////////////////
  1313. // less common string expressions
  1314. CStrW STRAPI operator+(const CStrW& string1, WCHAR ch)
  1315. {
  1316. CStrW s;
  1317. s.ConcatCopy(string1.m_nDataLength, string1.m_pchData, 1, &ch);
  1318. return s;
  1319. }
  1320. CStrW STRAPI operator+(WCHAR ch, const CStrW& string)
  1321. {
  1322. CStrW s;
  1323. s.ConcatCopy(1, &ch, string.m_nDataLength, string.m_pchData);
  1324. return s;
  1325. }
  1326. //////////////////////////////////////////////////////////////////////////////
  1327. // Very simple sub-string extraction
  1328. CStrW CStrW::Mid(int nFirst) const
  1329. {
  1330. return Mid(nFirst, m_nDataLength - nFirst);
  1331. }
  1332. CStrW CStrW::Mid(int nFirst, int nCount) const
  1333. {
  1334. dspAssert(nFirst >= 0);
  1335. dspAssert(nCount >= 0);
  1336. // out-of-bounds requests return sensible things
  1337. if (nFirst + nCount > m_nDataLength)
  1338. nCount = m_nDataLength - nFirst;
  1339. if (nFirst > m_nDataLength)
  1340. nCount = 0;
  1341. CStrW dest;
  1342. AllocCopy(dest, nCount, nFirst, 0);
  1343. return dest;
  1344. }
  1345. CStrW CStrW::Right(int nCount) const
  1346. {
  1347. dspAssert(nCount >= 0);
  1348. if (nCount > m_nDataLength)
  1349. nCount = m_nDataLength;
  1350. CStrW dest;
  1351. AllocCopy(dest, nCount, m_nDataLength-nCount, 0);
  1352. return dest;
  1353. }
  1354. CStrW CStrW::Left(int nCount) const
  1355. {
  1356. dspAssert(nCount >= 0);
  1357. if (nCount > m_nDataLength)
  1358. nCount = m_nDataLength;
  1359. CStrW dest;
  1360. AllocCopy(dest, nCount, 0, 0);
  1361. return dest;
  1362. }
  1363. // strspn equivalent
  1364. CStrW CStrW::SpanIncluding(LPCWSTR lpszCharSet) const
  1365. {
  1366. dspAssert(IsValidString(lpszCharSet, FALSE));
  1367. return Left(static_cast<int>(wcsspn(m_pchData, lpszCharSet)));
  1368. }
  1369. // strcspn equivalent
  1370. CStrW CStrW::SpanExcluding(LPCWSTR lpszCharSet) const
  1371. {
  1372. dspAssert(IsValidString(lpszCharSet, FALSE));
  1373. return Left(static_cast<int>(wcscspn(m_pchData, lpszCharSet)));
  1374. }
  1375. //////////////////////////////////////////////////////////////////////////////
  1376. // Finding
  1377. int CStrW::ReverseFind(WCHAR ch) const
  1378. {
  1379. // find last single character
  1380. PWSTR lpsz = wcsrchr(m_pchData, ch);
  1381. // return -1 if not found, distance from beginning otherwise
  1382. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1383. }
  1384. // find a sub-string (like strstr)
  1385. int CStrW::Find(LPCWSTR lpszSub) const
  1386. {
  1387. dspAssert(IsValidString(lpszSub, FALSE));
  1388. // find first matching substring
  1389. PWSTR lpsz = wcsstr(m_pchData, lpszSub);
  1390. // return -1 for not found, distance from beginning otherwise
  1391. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1392. }
  1393. /////////////////////////////////////////////////////////////////////////////
  1394. // String formatting
  1395. #define FORCE_ANSI 0x10000
  1396. #define FORCE_UNICODE 0x20000
  1397. // formatting (using wsprintf style formatting)
  1398. void CStrW::Format(LPCWSTR lpszFormat, ...)
  1399. {
  1400. dspAssert(IsValidString(lpszFormat, FALSE));
  1401. va_list argList;
  1402. va_start(argList, lpszFormat);
  1403. // make a guess at the maximum length of the resulting string
  1404. size_t nMaxLen = 0;
  1405. for (LPCWSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _wcsinc(lpsz))
  1406. {
  1407. // handle '%' character, but watch out for '%%'
  1408. if (*lpsz != '%' || *(lpsz = _wcsinc(lpsz)) == '%')
  1409. {
  1410. nMaxLen += wcslen(lpsz);
  1411. continue;
  1412. }
  1413. size_t nItemLen = 0;
  1414. // handle '%' character with format
  1415. int nWidth = 0;
  1416. for (; *lpsz != '\0'; lpsz = _wcsinc(lpsz))
  1417. {
  1418. // check for valid flags
  1419. if (*lpsz == '#')
  1420. nMaxLen += 2; // for '0x'
  1421. else if (*lpsz == '*')
  1422. nWidth = va_arg(argList, int);
  1423. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  1424. *lpsz == ' ')
  1425. ;
  1426. else // hit non-flag character
  1427. break;
  1428. }
  1429. // get width and skip it
  1430. if (nWidth == 0)
  1431. {
  1432. // width indicated by
  1433. nWidth = _wtoi(lpsz);
  1434. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _wcsinc(lpsz))
  1435. ;
  1436. }
  1437. dspAssert(nWidth >= 0);
  1438. int nPrecision = 0;
  1439. if (*lpsz == '.')
  1440. {
  1441. // skip past '.' separator (width.precision)
  1442. lpsz = _wcsinc(lpsz);
  1443. // get precision and skip it
  1444. if (*lpsz == '*')
  1445. {
  1446. nPrecision = va_arg(argList, int);
  1447. lpsz = _wcsinc(lpsz);
  1448. }
  1449. else
  1450. {
  1451. nPrecision = _wtoi(lpsz);
  1452. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _wcsinc(lpsz))
  1453. ;
  1454. }
  1455. dspAssert(nPrecision >= 0);
  1456. }
  1457. // should be on type modifier or specifier
  1458. int nModifier = 0;
  1459. switch (*lpsz)
  1460. {
  1461. // modifiers that affect size
  1462. case 'h':
  1463. nModifier = FORCE_ANSI;
  1464. lpsz = _wcsinc(lpsz);
  1465. break;
  1466. case 'l':
  1467. nModifier = FORCE_UNICODE;
  1468. lpsz = _wcsinc(lpsz);
  1469. break;
  1470. // modifiers that do not affect size
  1471. case 'F':
  1472. case 'N':
  1473. case 'L':
  1474. lpsz = _wcsinc(lpsz);
  1475. break;
  1476. }
  1477. // now should be on specifier
  1478. switch (*lpsz | nModifier)
  1479. {
  1480. // single characters
  1481. case 'c':
  1482. case 'C':
  1483. nItemLen = 2;
  1484. va_arg(argList, WCHAR);
  1485. break;
  1486. case 'c'|FORCE_ANSI:
  1487. case 'C'|FORCE_ANSI:
  1488. nItemLen = 2;
  1489. va_arg(argList, char);
  1490. break;
  1491. case 'c'|FORCE_UNICODE:
  1492. case 'C'|FORCE_UNICODE:
  1493. nItemLen = 2;
  1494. va_arg(argList, WCHAR);
  1495. break;
  1496. // strings
  1497. case 's':
  1498. case 'S':
  1499. nItemLen = wcslen(va_arg(argList, LPCWSTR));
  1500. nItemLen = __max(1, nItemLen);
  1501. break;
  1502. case 's'|FORCE_ANSI:
  1503. case 'S'|FORCE_ANSI:
  1504. nItemLen = lstrlenA(va_arg(argList, LPCSTR));
  1505. nItemLen = __max(1, nItemLen);
  1506. break;
  1507. #ifndef _MAC
  1508. case 's'|FORCE_UNICODE:
  1509. case 'S'|FORCE_UNICODE:
  1510. nItemLen = wcslen(va_arg(argList, LPWSTR));
  1511. nItemLen = __max(1, nItemLen);
  1512. break;
  1513. #endif
  1514. }
  1515. // adjust nItemLen for strings
  1516. if (nItemLen != 0)
  1517. {
  1518. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth));
  1519. if (nPrecision != 0)
  1520. nItemLen = __min(nItemLen, static_cast<UINT>(nPrecision));
  1521. }
  1522. else
  1523. {
  1524. switch (*lpsz)
  1525. {
  1526. // integers
  1527. case 'd':
  1528. case 'i':
  1529. case 'u':
  1530. case 'x':
  1531. case 'X':
  1532. case 'o':
  1533. va_arg(argList, int);
  1534. nItemLen = 32;
  1535. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth+nPrecision));
  1536. break;
  1537. case 'e':
  1538. case 'f':
  1539. case 'g':
  1540. case 'G':
  1541. va_arg(argList, _STR_DOUBLE);
  1542. nItemLen = 128;
  1543. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth+nPrecision));
  1544. break;
  1545. case 'p':
  1546. va_arg(argList, void*);
  1547. nItemLen = 32;
  1548. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth+nPrecision));
  1549. break;
  1550. // no output
  1551. case 'n':
  1552. va_arg(argList, int*);
  1553. break;
  1554. default:
  1555. dspAssert(FALSE); // unknown formatting option
  1556. }
  1557. }
  1558. // adjust nMaxLen for output nItemLen
  1559. nMaxLen += nItemLen;
  1560. }
  1561. va_end(argList);
  1562. // finally, set the buffer length and format the string
  1563. va_start(argList, lpszFormat); // restart the arg list
  1564. GetBuffer(static_cast<int>(nMaxLen));
  1565. if (vswprintf(m_pchData, lpszFormat, argList) > static_cast<int>(nMaxLen))
  1566. {
  1567. dspAssert(FALSE);
  1568. }
  1569. ReleaseBuffer();
  1570. va_end(argList);
  1571. }
  1572. // formatting (using FormatMessage style formatting)
  1573. void CStrW::FormatMessage(PCWSTR pwzFormat, ...)
  1574. {
  1575. dspAssert(IsValidString(pwzFormat, FALSE));
  1576. // format message into temporary buffer pwzTemp
  1577. va_list argList;
  1578. va_start(argList, pwzFormat);
  1579. PWSTR pwzTemp = 0;
  1580. if (::FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1581. pwzFormat, 0, 0, (PWSTR)&pwzTemp, 0, &argList) == 0 ||
  1582. pwzTemp == NULL)
  1583. {
  1584. ;//REVIEW AfxThrowMemoryException();
  1585. }
  1586. // assign pwzTemp into the resulting string and free the temporary
  1587. *this = pwzTemp;
  1588. LocalFree(pwzTemp);
  1589. va_end(argList);
  1590. }
  1591. void CStrW::FormatMessage(HINSTANCE hInst, UINT nFormatID, ...)
  1592. {
  1593. // get format string from string table
  1594. CStrW strFormat;
  1595. BOOL fLoaded = strFormat.LoadString(hInst, nFormatID);
  1596. dspAssert(fLoaded);
  1597. // format message into temporary buffer pwzTemp
  1598. va_list argList;
  1599. va_start(argList, nFormatID);
  1600. PWSTR pwzTemp;
  1601. if (::FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1602. strFormat, 0, 0, (PWSTR)&pwzTemp, 0, &argList) == 0 ||
  1603. pwzTemp == NULL)
  1604. {
  1605. ;//REVIEW AfxThrowMemoryException();
  1606. }
  1607. // assign pwzTemp into the resulting string and free pwzTemp
  1608. *this = pwzTemp;
  1609. LocalFree(pwzTemp);
  1610. va_end(argList);
  1611. }
  1612. void CStrW::TrimRight()
  1613. {
  1614. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  1615. PWSTR lpsz = m_pchData;
  1616. PWSTR lpszLast = NULL;
  1617. while (*lpsz != '\0')
  1618. {
  1619. if (_istspace(*lpsz))
  1620. {
  1621. if (lpszLast == NULL)
  1622. lpszLast = lpsz;
  1623. }
  1624. else
  1625. lpszLast = NULL;
  1626. lpsz = _wcsinc(lpsz);
  1627. }
  1628. if (lpszLast != NULL)
  1629. {
  1630. // truncate at trailing space start
  1631. *lpszLast = '\0';
  1632. m_nDataLength = (int)(lpszLast - m_pchData);
  1633. }
  1634. }
  1635. void CStrW::TrimLeft()
  1636. {
  1637. // find first non-space character
  1638. LPCWSTR lpsz = m_pchData;
  1639. while (_istspace(*lpsz))
  1640. lpsz = _wcsinc(lpsz);
  1641. // fix up data and length
  1642. int nDataLength = (int)(m_nDataLength - (lpsz - m_pchData));
  1643. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(WCHAR));
  1644. m_nDataLength = nDataLength;
  1645. }
  1646. ///////////////////////////////////////////////////////////////////////////////
  1647. // String support for template collections
  1648. void STRAPI ConstructElements(CStrW* pElements, int nCount)
  1649. {
  1650. dspAssert(IsValidAddressz(pElements, nCount * sizeof(CStrW)));
  1651. for (; nCount--; ++pElements)
  1652. memcpy(pElements, &strEmptyStringW, sizeof(*pElements));
  1653. }
  1654. void STRAPI DestructElements(CStrW* pElements, int nCount)
  1655. {
  1656. dspAssert(IsValidAddressz(pElements, nCount * sizeof(CStrW)));
  1657. for (; nCount--; ++pElements)
  1658. pElements->Empty();
  1659. }