Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1912 lines
57 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. (void)va_arg(argList, TCHAR);
  702. break;
  703. case 'c'|FORCE_ANSI:
  704. case 'C'|FORCE_ANSI:
  705. nItemLen = 2;
  706. (void)va_arg(argList, char);
  707. break;
  708. case 'c'|FORCE_UNICODE:
  709. case 'C'|FORCE_UNICODE:
  710. nItemLen = 2;
  711. (void)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. (void)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. (void)va_arg(argList, _STR_DOUBLE);
  759. nItemLen = 128;
  760. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth+nPrecision));
  761. break;
  762. case 'p':
  763. (void)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. (void)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. int CountCStrList( IN CStrListItem** ppList )
  862. {
  863. dspAssert( NULL != ppList );
  864. int cCount = 0;
  865. for (CStrListItem* pList = *ppList; NULL != pList; pList = pList->pnext)
  866. {
  867. cCount++;
  868. }
  869. return cCount;
  870. }
  871. /////////////////////////////////////////////////////////////////////////////
  872. // static class data, special inlines
  873. // For an empty string, m_???Data will point here
  874. // (note: avoids a lot of NULL pointer tests when we call standard
  875. // C runtime libraries
  876. WCHAR strChNilW = '\0';
  877. // for creating empty key strings
  878. const CStrW strEmptyStringW;
  879. void CStrW::Init()
  880. {
  881. m_nDataLength = m_nAllocLength = 0;
  882. m_pchData = (PWSTR)&strChNilW;
  883. }
  884. // declared static
  885. void CStrW::SafeDelete(PWSTR& lpch)
  886. {
  887. if (lpch != (PWSTR)&strChNilW &&
  888. lpch)
  889. {
  890. delete[] lpch;
  891. lpch = 0;
  892. }
  893. }
  894. //////////////////////////////////////////////////////////////////////////////
  895. // Construction/Destruction
  896. CStrW::CStrW()
  897. {
  898. Init();
  899. }
  900. CStrW::CStrW(const CStrW& stringSrc)
  901. {
  902. // if constructing a String from another String, we make a copy of the
  903. // original string data to enforce value semantics (i.e. each string
  904. // gets a copy of its own
  905. stringSrc.AllocCopy(*this, stringSrc.m_nDataLength, 0, 0);
  906. }
  907. BOOL CStrW::AllocBuffer(int nLen)
  908. // always allocate one extra character for '\0' termination
  909. // assumes [optimistically] that data length will equal allocation length
  910. {
  911. dspAssert(nLen >= 0);
  912. if (nLen == 0)
  913. {
  914. Empty();
  915. }
  916. else
  917. {
  918. m_pchData = new WCHAR[nLen+1]; //REVIEW may throw an exception
  919. if (!m_pchData)
  920. {
  921. Empty();
  922. return FALSE;
  923. }
  924. m_pchData[nLen] = '\0';
  925. m_nDataLength = nLen;
  926. m_nAllocLength = nLen;
  927. }
  928. return TRUE;
  929. }
  930. void CStrW::Empty()
  931. {
  932. SafeDelete(m_pchData);
  933. Init();
  934. dspAssert(m_nDataLength == 0);
  935. dspAssert(m_nAllocLength == 0);
  936. }
  937. CStrW::~CStrW()
  938. // free any attached data
  939. {
  940. SafeDelete(m_pchData);
  941. }
  942. //////////////////////////////////////////////////////////////////////////////
  943. // Helpers for the rest of the implementation
  944. static inline int SafeStrlen(LPCWSTR lpsz)
  945. {
  946. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  947. return (int)((lpsz == NULL) ? 0 : wcslen(lpsz));
  948. }
  949. void CStrW::AllocCopy(CStrW& dest, int nCopyLen, int nCopyIndex,
  950. int nExtraLen) const
  951. {
  952. // will clone the data attached to this string
  953. // allocating 'nExtraLen' characters
  954. // Places results in uninitialized string 'dest'
  955. // Will copy the part or all of original data to start of new string
  956. int nNewLen = nCopyLen + nExtraLen;
  957. if (nNewLen == 0)
  958. {
  959. dest.Empty();
  960. }
  961. else
  962. {
  963. if (!dest.AllocBuffer(nNewLen)) return;
  964. memcpy(dest.m_pchData, &m_pchData[nCopyIndex], nCopyLen*sizeof(WCHAR));
  965. }
  966. }
  967. //////////////////////////////////////////////////////////////////////////////
  968. // More sophisticated construction
  969. CStrW::CStrW(LPCWSTR lpsz)
  970. {
  971. int nLen;
  972. if ((nLen = SafeStrlen(lpsz)) == 0)
  973. Init();
  974. else
  975. {
  976. if (!AllocBuffer(nLen))
  977. {
  978. Init();
  979. return;
  980. }
  981. memcpy(m_pchData, lpsz, nLen*sizeof(WCHAR));
  982. }
  983. }
  984. /////////////////////////////////////////////////////////////////////////////
  985. // Special conversion constructors
  986. CStrW::CStrW(LPCSTR lpsz)
  987. {
  988. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  989. if (nSrcLen == 0)
  990. Init();
  991. else
  992. {
  993. if (!AllocBuffer(nSrcLen))
  994. {
  995. Init();
  996. return;
  997. }
  998. mmc_mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  999. }
  1000. }
  1001. //////////////////////////////////////////////////////////////////////////////
  1002. // Assignment operators
  1003. // All assign a new value to the string
  1004. // (a) first see if the buffer is big enough
  1005. // (b) if enough room, copy on top of old buffer, set size and type
  1006. // (c) otherwise free old string data, and create a new one
  1007. //
  1008. // All routines return the new string (but as a 'const CStrW&' so that
  1009. // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  1010. //
  1011. void CStrW::AssignCopy(int nSrcLen, LPCWSTR lpszSrcData)
  1012. {
  1013. // NOTICE-2002/03/07-ericb: SecurityPush: check input param.
  1014. if (!lpszSrcData)
  1015. {
  1016. nSrcLen = 0;
  1017. }
  1018. // check if it will fit
  1019. if (nSrcLen > m_nAllocLength)
  1020. {
  1021. // it won't fit, allocate another one
  1022. Empty();
  1023. if (!AllocBuffer(nSrcLen)) return;
  1024. }
  1025. if (nSrcLen != 0)
  1026. memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(WCHAR));
  1027. m_nDataLength = nSrcLen;
  1028. m_pchData[nSrcLen] = '\0';
  1029. }
  1030. const CStrW& CStrW::operator=(const CStrW& stringSrc)
  1031. {
  1032. AssignCopy(stringSrc.m_nDataLength, stringSrc.m_pchData);
  1033. return *this;
  1034. }
  1035. const CStrW& CStrW::operator=(LPCWSTR lpsz)
  1036. {
  1037. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  1038. AssignCopy(SafeStrlen(lpsz), lpsz);
  1039. return *this;
  1040. }
  1041. const CStrW& CStrW::operator=(UNICODE_STRING unistr)
  1042. {
  1043. AssignCopy(unistr.Length/2, unistr.Buffer);
  1044. return *this;
  1045. }
  1046. const CStrW& CStrW::operator=(UNICODE_STRING * punistr)
  1047. {
  1048. AssignCopy(punistr->Length/2, punistr->Buffer);
  1049. return *this;
  1050. }
  1051. /////////////////////////////////////////////////////////////////////////////
  1052. // Special conversion assignment
  1053. const CStrW& CStrW::operator=(LPCSTR lpsz)
  1054. {
  1055. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  1056. // check if it will fit
  1057. if (nSrcLen > m_nAllocLength)
  1058. {
  1059. // it won't fit, allocate another one
  1060. Empty();
  1061. if (!AllocBuffer(nSrcLen)) return *this;
  1062. }
  1063. if (nSrcLen != 0)
  1064. mmc_mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  1065. m_nDataLength = nSrcLen;
  1066. m_pchData[nSrcLen] = '\0';
  1067. return *this;
  1068. }
  1069. //////////////////////////////////////////////////////////////////////////////
  1070. // concatenation
  1071. // NOTE: "operator+" is done as friend functions for simplicity
  1072. // There are three variants:
  1073. // String + String
  1074. // and for ? = WCHAR, LPCWSTR
  1075. // String + ?
  1076. // ? + String
  1077. void CStrW::ConcatCopy(int nSrc1Len, LPCWSTR lpszSrc1Data,
  1078. int nSrc2Len, LPCWSTR lpszSrc2Data)
  1079. {
  1080. // -- master concatenation routine
  1081. // Concatenate two sources
  1082. // -- assume that 'this' is a new String object
  1083. int nNewLen = nSrc1Len + nSrc2Len;
  1084. if (!AllocBuffer(nNewLen)) return;
  1085. memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(WCHAR));
  1086. memcpy(&m_pchData[nSrc1Len], lpszSrc2Data, nSrc2Len*sizeof(WCHAR));
  1087. }
  1088. CStrW STRAPI operator+(const CStrW& string1, const CStrW& string2)
  1089. {
  1090. CStrW s;
  1091. s.ConcatCopy(string1.m_nDataLength, string1.m_pchData,
  1092. string2.m_nDataLength, string2.m_pchData);
  1093. return s;
  1094. }
  1095. CStrW STRAPI operator+(const CStrW& string, LPCWSTR lpsz)
  1096. {
  1097. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  1098. CStrW s;
  1099. s.ConcatCopy(string.m_nDataLength, string.m_pchData, SafeStrlen(lpsz), lpsz);
  1100. return s;
  1101. }
  1102. CStrW STRAPI operator+(LPCWSTR lpsz, const CStrW& string)
  1103. {
  1104. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  1105. CStrW s;
  1106. s.ConcatCopy(SafeStrlen(lpsz), lpsz, string.m_nDataLength, string.m_pchData);
  1107. return s;
  1108. }
  1109. //////////////////////////////////////////////////////////////////////////////
  1110. // concatenate in place
  1111. void CStrW::ConcatInPlace(int nSrcLen, LPCWSTR lpszSrcData)
  1112. {
  1113. // -- the main routine for += operators
  1114. // if the buffer is too small, or we have a width mis-match, just
  1115. // allocate a new buffer (slow but sure)
  1116. if (m_nDataLength + nSrcLen > m_nAllocLength)
  1117. {
  1118. // we have to grow the buffer, use the Concat in place routine
  1119. PWSTR lpszOldData = m_pchData;
  1120. ConcatCopy(m_nDataLength, lpszOldData, nSrcLen, lpszSrcData);
  1121. dspAssert(lpszOldData != NULL);
  1122. SafeDelete(lpszOldData);
  1123. }
  1124. else
  1125. {
  1126. // fast concatenation when buffer big enough
  1127. memcpy(&m_pchData[m_nDataLength], lpszSrcData, nSrcLen*sizeof(WCHAR));
  1128. m_nDataLength += nSrcLen;
  1129. }
  1130. dspAssert(m_nDataLength <= m_nAllocLength);
  1131. m_pchData[m_nDataLength] = '\0';
  1132. }
  1133. const CStrW& CStrW::operator+=(LPCWSTR lpsz)
  1134. {
  1135. dspAssert(lpsz == NULL || IsValidString(lpsz, FALSE));
  1136. ConcatInPlace(SafeStrlen(lpsz), lpsz);
  1137. return *this;
  1138. }
  1139. const CStrW& CStrW::operator+=(WCHAR ch)
  1140. {
  1141. ConcatInPlace(1, &ch);
  1142. return *this;
  1143. }
  1144. const CStrW& CStrW::operator+=(const CStrW& string)
  1145. {
  1146. ConcatInPlace(string.m_nDataLength, string.m_pchData);
  1147. return *this;
  1148. }
  1149. ///////////////////////////////////////////////////////////////////////////////
  1150. // Advanced direct buffer access
  1151. PWSTR CStrW::GetBuffer(int nMinBufLength)
  1152. {
  1153. dspAssert(nMinBufLength >= 0);
  1154. if (nMinBufLength > m_nAllocLength)
  1155. {
  1156. // we have to grow the buffer
  1157. PWSTR lpszOldData = m_pchData;
  1158. int nOldLen = m_nDataLength; // AllocBuffer will tromp it
  1159. if (!AllocBuffer(nMinBufLength)) return NULL;
  1160. memcpy(m_pchData, lpszOldData, nOldLen*sizeof(WCHAR));
  1161. m_nDataLength = nOldLen;
  1162. m_pchData[m_nDataLength] = '\0';
  1163. SafeDelete(lpszOldData);
  1164. }
  1165. // return a pointer to the character storage for this string
  1166. dspAssert(m_pchData != NULL);
  1167. return m_pchData;
  1168. }
  1169. void CStrW::ReleaseBuffer(int nNewLength)
  1170. {
  1171. if (nNewLength == -1)
  1172. nNewLength = static_cast<int>(wcslen(m_pchData)); // zero terminated
  1173. dspAssert(nNewLength <= m_nAllocLength);
  1174. m_nDataLength = nNewLength;
  1175. m_pchData[m_nDataLength] = '\0';
  1176. }
  1177. PWSTR CStrW::GetBufferSetLength(int nNewLength)
  1178. {
  1179. dspAssert(nNewLength >= 0);
  1180. GetBuffer(nNewLength);
  1181. m_nDataLength = nNewLength;
  1182. m_pchData[m_nDataLength] = '\0';
  1183. return m_pchData;
  1184. }
  1185. void CStrW::FreeExtra()
  1186. {
  1187. dspAssert(m_nDataLength <= m_nAllocLength);
  1188. if (m_nDataLength != m_nAllocLength)
  1189. {
  1190. PWSTR lpszOldData = m_pchData;
  1191. if (!AllocBuffer(m_nDataLength)) return;
  1192. memcpy(m_pchData, lpszOldData, m_nDataLength*sizeof(WCHAR));
  1193. dspAssert(m_pchData[m_nDataLength] == '\0');
  1194. SafeDelete(lpszOldData);
  1195. }
  1196. dspAssert(m_pchData != NULL);
  1197. }
  1198. ///////////////////////////////////////////////////////////////////////////////
  1199. // Commonly used routines (rarely used routines in STREX.CPP)
  1200. int CStrW::Find(WCHAR ch) const
  1201. {
  1202. // find first single character
  1203. PWSTR lpsz = wcschr(m_pchData, ch);
  1204. // return -1 if not found and index otherwise
  1205. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1206. }
  1207. int CStrW::FindOneOf(LPCWSTR lpszCharSet) const
  1208. {
  1209. dspAssert(IsValidString(lpszCharSet, FALSE));
  1210. PWSTR lpsz = wcspbrk(m_pchData, lpszCharSet);
  1211. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1212. }
  1213. /////////////////////////////////////////////////////////////////////////////
  1214. // Windows extensions to strings
  1215. BOOL CStrW::LoadString(HINSTANCE hInst, UINT nID)
  1216. {
  1217. dspAssert(nID != 0); // 0 is an illegal string ID
  1218. // Note: resource strings limited to 511 characters
  1219. WCHAR szBuffer[512];
  1220. UINT nSize = StrLoadStringW(hInst, nID, szBuffer);
  1221. AssignCopy(nSize, szBuffer);
  1222. return nSize > 0;
  1223. }
  1224. int STRAPI StrLoadStringW(HINSTANCE hInst, UINT nID, LPWSTR lpszBuf)
  1225. {
  1226. dspAssert(IsValidAddressz(lpszBuf, 512)); // must be big enough for 512 bytes
  1227. #ifdef DBG
  1228. // LoadString without annoying warning from the Debug kernel if the
  1229. // segment containing the string is not present
  1230. if (::FindResource(hInst, MAKEINTRESOURCE((nID>>4)+1), RT_STRING) == NULL)
  1231. {
  1232. lpszBuf[0] = '\0';
  1233. return 0; // not found
  1234. }
  1235. #endif //DBG
  1236. int nLen = ::LoadStringW(hInst, nID, lpszBuf, 511);
  1237. dspAssert(nLen);
  1238. if (nLen == 0)
  1239. lpszBuf[0] = '\0';
  1240. return nLen;
  1241. }
  1242. #ifdef OLE_AUTOMATION
  1243. #ifdef UNICODE
  1244. BSTR CStrW::AllocSysString()
  1245. {
  1246. BSTR bstr = ::SysAllocStringLen(m_pchData, m_nDataLength);
  1247. if (bstr == NULL)
  1248. ;//REVIEW AfxThrowMemoryException();
  1249. return bstr;
  1250. }
  1251. BSTR CStrW::SetSysString(BSTR* pbstr)
  1252. {
  1253. dspAssert(IsValidAddressz(pbstr, sizeof(BSTR)));
  1254. if (!::SysReAllocStringLen(pbstr, m_pchData, m_nDataLength))
  1255. ; //REVIEW AfxThrowMemoryException();
  1256. dspAssert(*pbstr != NULL);
  1257. return *pbstr;
  1258. }
  1259. #endif
  1260. #endif // #ifdef OLE_AUTOMATION
  1261. ///////////////////////////////////////////////////////////////////////////////
  1262. // Orginally from StrEx.cpp
  1263. CStrW::CStrW(WCHAR ch, int nLength)
  1264. {
  1265. if (nLength < 1)
  1266. {
  1267. // return empty string if invalid repeat count
  1268. Init();
  1269. }
  1270. else
  1271. {
  1272. if (!AllocBuffer(nLength))
  1273. {
  1274. Init();
  1275. return;
  1276. }
  1277. #ifdef UNICODE
  1278. for (int i = 0; i < nLength; i++)
  1279. m_pchData[i] = ch;
  1280. #else
  1281. memset(m_pchData, ch, nLength);
  1282. #endif
  1283. }
  1284. }
  1285. CStrW::CStrW(LPCWSTR lpch, int nLength)
  1286. {
  1287. if (nLength == 0)
  1288. Init();
  1289. else
  1290. {
  1291. dspAssert(IsValidAddressz(lpch, nLength, FALSE));
  1292. if (!AllocBuffer(nLength))
  1293. {
  1294. Init();
  1295. return;
  1296. }
  1297. memcpy(m_pchData, lpch, nLength*sizeof(WCHAR));
  1298. }
  1299. }
  1300. //////////////////////////////////////////////////////////////////////////////
  1301. // Assignment operators
  1302. const CStrW& CStrW::operator=(WCHAR ch)
  1303. {
  1304. AssignCopy(1, &ch);
  1305. return *this;
  1306. }
  1307. //////////////////////////////////////////////////////////////////////////////
  1308. // less common string expressions
  1309. CStrW STRAPI operator+(const CStrW& string1, WCHAR ch)
  1310. {
  1311. CStrW s;
  1312. s.ConcatCopy(string1.m_nDataLength, string1.m_pchData, 1, &ch);
  1313. return s;
  1314. }
  1315. CStrW STRAPI operator+(WCHAR ch, const CStrW& string)
  1316. {
  1317. CStrW s;
  1318. s.ConcatCopy(1, &ch, string.m_nDataLength, string.m_pchData);
  1319. return s;
  1320. }
  1321. //////////////////////////////////////////////////////////////////////////////
  1322. // Very simple sub-string extraction
  1323. CStrW CStrW::Mid(int nFirst) const
  1324. {
  1325. return Mid(nFirst, m_nDataLength - nFirst);
  1326. }
  1327. CStrW CStrW::Mid(int nFirst, int nCount) const
  1328. {
  1329. dspAssert(nFirst >= 0);
  1330. dspAssert(nCount >= 0);
  1331. // out-of-bounds requests return sensible things
  1332. if (nFirst + nCount > m_nDataLength)
  1333. nCount = m_nDataLength - nFirst;
  1334. if (nFirst > m_nDataLength)
  1335. nCount = 0;
  1336. CStrW dest;
  1337. AllocCopy(dest, nCount, nFirst, 0);
  1338. return dest;
  1339. }
  1340. CStrW CStrW::Right(int nCount) const
  1341. {
  1342. dspAssert(nCount >= 0);
  1343. if (nCount > m_nDataLength)
  1344. nCount = m_nDataLength;
  1345. CStrW dest;
  1346. AllocCopy(dest, nCount, m_nDataLength-nCount, 0);
  1347. return dest;
  1348. }
  1349. CStrW CStrW::Left(int nCount) const
  1350. {
  1351. dspAssert(nCount >= 0);
  1352. if (nCount > m_nDataLength)
  1353. nCount = m_nDataLength;
  1354. CStrW dest;
  1355. AllocCopy(dest, nCount, 0, 0);
  1356. return dest;
  1357. }
  1358. // strspn equivalent
  1359. CStrW CStrW::SpanIncluding(LPCWSTR lpszCharSet) const
  1360. {
  1361. dspAssert(IsValidString(lpszCharSet, FALSE));
  1362. return Left(static_cast<int>(wcsspn(m_pchData, lpszCharSet)));
  1363. }
  1364. // strcspn equivalent
  1365. CStrW CStrW::SpanExcluding(LPCWSTR lpszCharSet) const
  1366. {
  1367. dspAssert(IsValidString(lpszCharSet, FALSE));
  1368. return Left(static_cast<int>(wcscspn(m_pchData, lpszCharSet)));
  1369. }
  1370. //////////////////////////////////////////////////////////////////////////////
  1371. // Finding
  1372. int CStrW::ReverseFind(WCHAR ch) const
  1373. {
  1374. // find last single character
  1375. PWSTR lpsz = wcsrchr(m_pchData, ch);
  1376. // return -1 if not found, distance from beginning otherwise
  1377. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1378. }
  1379. // find a sub-string (like strstr)
  1380. int CStrW::Find(LPCWSTR lpszSub) const
  1381. {
  1382. dspAssert(IsValidString(lpszSub, FALSE));
  1383. // find first matching substring
  1384. PWSTR lpsz = wcsstr(m_pchData, lpszSub);
  1385. // return -1 for not found, distance from beginning otherwise
  1386. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  1387. }
  1388. /////////////////////////////////////////////////////////////////////////////
  1389. // String formatting
  1390. #define FORCE_ANSI 0x10000
  1391. #define FORCE_UNICODE 0x20000
  1392. // formatting (using wsprintf style formatting)
  1393. void CStrW::Format(LPCWSTR lpszFormat, ...)
  1394. {
  1395. dspAssert(IsValidString(lpszFormat, FALSE));
  1396. va_list argList;
  1397. va_start(argList, lpszFormat);
  1398. // make a guess at the maximum length of the resulting string
  1399. size_t nMaxLen = 0;
  1400. for (LPCWSTR lpsz = lpszFormat; *lpsz != '\0'; lpsz = _wcsinc(lpsz))
  1401. {
  1402. // handle '%' character, but watch out for '%%'
  1403. if (*lpsz != '%' || *(lpsz = _wcsinc(lpsz)) == '%')
  1404. {
  1405. nMaxLen += wcslen(lpsz);
  1406. continue;
  1407. }
  1408. size_t nItemLen = 0;
  1409. // handle '%' character with format
  1410. int nWidth = 0;
  1411. for (; *lpsz != '\0'; lpsz = _wcsinc(lpsz))
  1412. {
  1413. // check for valid flags
  1414. if (*lpsz == '#')
  1415. nMaxLen += 2; // for '0x'
  1416. else if (*lpsz == '*')
  1417. nWidth = va_arg(argList, int);
  1418. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  1419. *lpsz == ' ')
  1420. ;
  1421. else // hit non-flag character
  1422. break;
  1423. }
  1424. // get width and skip it
  1425. if (nWidth == 0)
  1426. {
  1427. // width indicated by
  1428. nWidth = _wtoi(lpsz);
  1429. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _wcsinc(lpsz))
  1430. ;
  1431. }
  1432. dspAssert(nWidth >= 0);
  1433. int nPrecision = 0;
  1434. if (*lpsz == '.')
  1435. {
  1436. // skip past '.' separator (width.precision)
  1437. lpsz = _wcsinc(lpsz);
  1438. // get precision and skip it
  1439. if (*lpsz == '*')
  1440. {
  1441. nPrecision = va_arg(argList, int);
  1442. lpsz = _wcsinc(lpsz);
  1443. }
  1444. else
  1445. {
  1446. nPrecision = _wtoi(lpsz);
  1447. for (; *lpsz != '\0' && _istdigit(*lpsz); lpsz = _wcsinc(lpsz))
  1448. ;
  1449. }
  1450. dspAssert(nPrecision >= 0);
  1451. }
  1452. // should be on type modifier or specifier
  1453. int nModifier = 0;
  1454. switch (*lpsz)
  1455. {
  1456. // modifiers that affect size
  1457. case 'h':
  1458. nModifier = FORCE_ANSI;
  1459. lpsz = _wcsinc(lpsz);
  1460. break;
  1461. case 'l':
  1462. nModifier = FORCE_UNICODE;
  1463. lpsz = _wcsinc(lpsz);
  1464. break;
  1465. // modifiers that do not affect size
  1466. case 'F':
  1467. case 'N':
  1468. case 'L':
  1469. lpsz = _wcsinc(lpsz);
  1470. break;
  1471. }
  1472. // now should be on specifier
  1473. switch (*lpsz | nModifier)
  1474. {
  1475. // single characters
  1476. case 'c':
  1477. case 'C':
  1478. nItemLen = 2;
  1479. (void)va_arg(argList, WCHAR);
  1480. break;
  1481. case 'c'|FORCE_ANSI:
  1482. case 'C'|FORCE_ANSI:
  1483. nItemLen = 2;
  1484. (void)va_arg(argList, char);
  1485. break;
  1486. case 'c'|FORCE_UNICODE:
  1487. case 'C'|FORCE_UNICODE:
  1488. nItemLen = 2;
  1489. (void)va_arg(argList, WCHAR);
  1490. break;
  1491. // strings
  1492. case 's':
  1493. case 'S':
  1494. nItemLen = wcslen(va_arg(argList, LPCWSTR));
  1495. nItemLen = __max(1, nItemLen);
  1496. break;
  1497. case 's'|FORCE_ANSI:
  1498. case 'S'|FORCE_ANSI:
  1499. nItemLen = lstrlenA(va_arg(argList, LPCSTR));
  1500. nItemLen = __max(1, nItemLen);
  1501. break;
  1502. #ifndef _MAC
  1503. case 's'|FORCE_UNICODE:
  1504. case 'S'|FORCE_UNICODE:
  1505. nItemLen = wcslen(va_arg(argList, LPWSTR));
  1506. nItemLen = __max(1, nItemLen);
  1507. break;
  1508. #endif
  1509. }
  1510. // adjust nItemLen for strings
  1511. if (nItemLen != 0)
  1512. {
  1513. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth));
  1514. if (nPrecision != 0)
  1515. nItemLen = __min(nItemLen, static_cast<UINT>(nPrecision));
  1516. }
  1517. else
  1518. {
  1519. switch (*lpsz)
  1520. {
  1521. // integers
  1522. case 'd':
  1523. case 'i':
  1524. case 'u':
  1525. case 'x':
  1526. case 'X':
  1527. case 'o':
  1528. (void)va_arg(argList, int);
  1529. nItemLen = 32;
  1530. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth+nPrecision));
  1531. break;
  1532. case 'e':
  1533. case 'f':
  1534. case 'g':
  1535. case 'G':
  1536. (void)va_arg(argList, _STR_DOUBLE);
  1537. nItemLen = 128;
  1538. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth+nPrecision));
  1539. break;
  1540. case 'p':
  1541. (void)va_arg(argList, void*);
  1542. nItemLen = 32;
  1543. nItemLen = __max(nItemLen, static_cast<UINT>(nWidth+nPrecision));
  1544. break;
  1545. // no output
  1546. case 'n':
  1547. (void)va_arg(argList, int*);
  1548. break;
  1549. default:
  1550. dspAssert(FALSE); // unknown formatting option
  1551. }
  1552. }
  1553. // adjust nMaxLen for output nItemLen
  1554. nMaxLen += nItemLen;
  1555. }
  1556. va_end(argList);
  1557. // finally, set the buffer length and format the string
  1558. va_start(argList, lpszFormat); // restart the arg list
  1559. GetBuffer(static_cast<int>(nMaxLen));
  1560. if (vswprintf(m_pchData, lpszFormat, argList) > static_cast<int>(nMaxLen))
  1561. {
  1562. dspAssert(FALSE);
  1563. }
  1564. ReleaseBuffer();
  1565. va_end(argList);
  1566. }
  1567. // formatting (using FormatMessage style formatting)
  1568. void CStrW::FormatMessage(PCWSTR pwzFormat, ...)
  1569. {
  1570. dspAssert(IsValidString(pwzFormat, FALSE));
  1571. // format message into temporary buffer pwzTemp
  1572. va_list argList;
  1573. va_start(argList, pwzFormat);
  1574. PWSTR pwzTemp = 0;
  1575. if (::FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1576. pwzFormat, 0, 0, (PWSTR)&pwzTemp, 0, &argList) == 0 ||
  1577. pwzTemp == NULL)
  1578. {
  1579. ;//REVIEW AfxThrowMemoryException();
  1580. }
  1581. // assign pwzTemp into the resulting string and free the temporary
  1582. *this = pwzTemp;
  1583. LocalFree(pwzTemp);
  1584. va_end(argList);
  1585. }
  1586. void CStrW::FormatMessage(HINSTANCE hInst, UINT nFormatID, ...)
  1587. {
  1588. // get format string from string table
  1589. CStrW strFormat;
  1590. BOOL fLoaded = strFormat.LoadString(hInst, nFormatID);
  1591. dspAssert(fLoaded);
  1592. // format message into temporary buffer pwzTemp
  1593. va_list argList;
  1594. va_start(argList, nFormatID);
  1595. PWSTR pwzTemp = NULL;
  1596. if (::FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1597. strFormat, 0, 0, (PWSTR)&pwzTemp, 0, &argList) == 0 ||
  1598. pwzTemp == NULL)
  1599. {
  1600. ;//REVIEW AfxThrowMemoryException();
  1601. }
  1602. // assign pwzTemp into the resulting string and free pwzTemp
  1603. *this = pwzTemp;
  1604. LocalFree(pwzTemp);
  1605. va_end(argList);
  1606. }
  1607. void CStrW::TrimRight()
  1608. {
  1609. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  1610. PWSTR lpsz = m_pchData;
  1611. PWSTR lpszLast = NULL;
  1612. while (*lpsz != '\0')
  1613. {
  1614. if (_istspace(*lpsz))
  1615. {
  1616. if (lpszLast == NULL)
  1617. lpszLast = lpsz;
  1618. }
  1619. else
  1620. lpszLast = NULL;
  1621. lpsz = _wcsinc(lpsz);
  1622. }
  1623. if (lpszLast != NULL)
  1624. {
  1625. // truncate at trailing space start
  1626. *lpszLast = '\0';
  1627. m_nDataLength = (int)(lpszLast - m_pchData);
  1628. }
  1629. }
  1630. void CStrW::TrimLeft()
  1631. {
  1632. // find first non-space character
  1633. LPCWSTR lpsz = m_pchData;
  1634. while (_istspace(*lpsz))
  1635. lpsz = _wcsinc(lpsz);
  1636. // fix up data and length
  1637. int nDataLength = (int)(m_nDataLength - (lpsz - m_pchData));
  1638. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(WCHAR));
  1639. m_nDataLength = nDataLength;
  1640. }