SpString.cpp
上传用户:zhanglf88
上传日期:2013-11-19
资源大小:6036k
文件大小:33k
源码类别:

金融证券系统

开发平台:

Visual C++

  1. /*
  2. Cross Platform Core Code.
  3. Copyright(R) 2001-2002 Balang Software.
  4. All rights reserved.
  5. Using:
  6. class CSPString;
  7. */
  8. #include "StdAfx.h"
  9. #ifdef _DEBUG
  10. #undef THIS_FILE
  11. static char THIS_FILE[] = __FILE__;
  12. #endif
  13. #ifdef _DEBUG
  14. #define new DEBUG_NEW
  15. #endif
  16. #ifndef _SP_ENABLE_INLINES
  17. #define _SPSTRING_INLINE
  18. #include "../Include/SpString.inl"
  19. #undef _SPSTRING_INLINE
  20. #endif
  21. /////////////////////////////////////////////////////////////////////////////
  22. // static class data, special inlines
  23. // afxSPChNil is left for backward compatibility
  24. TCHAR afxSPChNil = '';
  25. // For an empty string, m_pchData will point here
  26. // (note: avoids special case of checking for NULL m_pchData)
  27. // empty string data (and locked)
  28. int _afxSPInitData[] = { -1, 0, 0, 0 };
  29. CSPStringData* _afxSPDataNil = (CSPStringData*)&_afxSPInitData;
  30. LPCTSTR _afxSPPchNil = (LPCTSTR)(((BYTE*)&_afxSPInitData)+sizeof(CSPStringData));
  31. // special function to make afxEmptyString work even during initialization
  32. const CSPString& __stdcall AfxGetEmptySPString()
  33. { return *(CSPString*)&_afxSPPchNil; }
  34. //////////////////////////////////////////////////////////////////////////////
  35. // Construction/Destruction
  36. #ifdef _AFXDLL
  37. CSPString::CSPString()
  38. {
  39. Init();
  40. }
  41. #endif
  42. CSPString::CSPString(const CSPString& stringSrc)
  43. {
  44. SP_ASSERT(stringSrc.GetData()->nRefs != 0);
  45. if (stringSrc.GetData()->nRefs >= 0)
  46. {
  47. SP_ASSERT(stringSrc.GetData() != _afxSPDataNil);
  48. m_pchData = stringSrc.m_pchData;
  49. InterlockedIncrement(&GetData()->nRefs);
  50. }
  51. else
  52. {
  53. Init();
  54. *this = stringSrc.m_pchData;
  55. }
  56. }
  57. void CSPString::AllocBuffer(int nLen)
  58. // always allocate one extra character for '' termination
  59. // assumes [optimistically] that data length will equal allocation length
  60. {
  61. SP_ASSERT(nLen >= 0);
  62. SP_ASSERT(nLen <= INT_MAX-1);    // max size (enough room for 1 extra)
  63. if (nLen == 0)
  64. Init();
  65. else
  66. {
  67. CSPStringData* pData;
  68. {
  69. pData = (CSPStringData*)
  70. new BYTE[sizeof(CSPStringData) + (nLen+1)*sizeof(TCHAR)];
  71. pData->nAllocLength = nLen;
  72. }
  73. pData->nRefs = 1;
  74. pData->data()[nLen] = '';
  75. pData->nDataLength = nLen;
  76. m_pchData = pData->data();
  77. }
  78. }
  79. void __fastcall CSPString::FreeData(CSPStringData* pData)
  80. {
  81. delete[] (BYTE*)pData;
  82. }
  83. void CSPString::Release()
  84. {
  85. if (GetData() != _afxSPDataNil)
  86. {
  87. SP_ASSERT(GetData()->nRefs != 0);
  88. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  89. FreeData(GetData());
  90. Init();
  91. }
  92. }
  93. void PASCAL CSPString::Release(CSPStringData* pData)
  94. {
  95. if (pData != _afxSPDataNil)
  96. {
  97. SP_ASSERT(pData->nRefs != 0);
  98. if (InterlockedDecrement(&pData->nRefs) <= 0)
  99. FreeData(pData);
  100. }
  101. }
  102. void CSPString::Empty()
  103. {
  104. if (GetData()->nDataLength == 0)
  105. return;
  106. if (GetData()->nRefs >= 0)
  107. Release();
  108. else
  109. *this = &afxSPChNil;
  110. SP_ASSERT(GetData()->nDataLength == 0);
  111. SP_ASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
  112. }
  113. void CSPString::CopyBeforeWrite()
  114. {
  115. if (GetData()->nRefs > 1)
  116. {
  117. CSPStringData* pData = GetData();
  118. Release();
  119. AllocBuffer(pData->nDataLength);
  120. memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR));
  121. }
  122. SP_ASSERT(GetData()->nRefs <= 1);
  123. }
  124. void CSPString::AllocBeforeWrite(int nLen)
  125. {
  126. if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
  127. {
  128. Release();
  129. AllocBuffer(nLen);
  130. }
  131. SP_ASSERT(GetData()->nRefs <= 1);
  132. }
  133. CSPString::~CSPString()
  134. //  free any attached data
  135. {
  136. if (GetData() != _afxSPDataNil)
  137. {
  138. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  139. FreeData(GetData());
  140. }
  141. }
  142. //////////////////////////////////////////////////////////////////////////////
  143. // Helpers for the rest of the implementation
  144. void CSPString::AllocCopy(CSPString& dest, int nCopyLen, int nCopyIndex,
  145.  int nExtraLen) const
  146. {
  147. // will clone the data attached to this string
  148. // allocating 'nExtraLen' characters
  149. // Places results in uninitialized string 'dest'
  150. // Will copy the part or all of original data to start of new string
  151. int nNewLen = nCopyLen + nExtraLen;
  152. if (nNewLen == 0)
  153. {
  154. dest.Init();
  155. }
  156. else
  157. {
  158. dest.AllocBuffer(nNewLen);
  159. memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));
  160. }
  161. }
  162. //////////////////////////////////////////////////////////////////////////////
  163. // More sophisticated construction
  164. CSPString::CSPString(LPCTSTR lpsz)
  165. {
  166. Init();
  167. if (lpsz != NULL && HIWORD(lpsz) == NULL)
  168. {
  169. UINT nID = LOWORD((DWORD)lpsz);
  170. if (!LoadString(nID))
  171. SP_TRACE1("Warning: implicit LoadString(%u) failedn", nID);
  172. }
  173. else
  174. {
  175. int nLen = SafeStrlen(lpsz);
  176. if (nLen != 0)
  177. {
  178. AllocBuffer(nLen);
  179. memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
  180. }
  181. }
  182. }
  183. /////////////////////////////////////////////////////////////////////////////
  184. // Special conversion constructors
  185. #ifdef _UNICODE
  186. CSPString::CSPString(LPCSTR lpsz)
  187. {
  188. Init();
  189. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  190. if (nSrcLen != 0)
  191. {
  192. AllocBuffer(nSrcLen);
  193. mbstowcs(m_pchData, lpsz, nSrcLen+1);
  194. ReleaseBuffer();
  195. }
  196. }
  197. #else //_UNICODE
  198. CSPString::CSPString(LPCWSTR lpsz)
  199. {
  200. Init();
  201. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  202. if (nSrcLen != 0)
  203. {
  204. AllocBuffer(nSrcLen*2);
  205. wcstombs(m_pchData, lpsz, (nSrcLen*2)+1);
  206. ReleaseBuffer();
  207. }
  208. }
  209. #endif //!_UNICODE
  210. //////////////////////////////////////////////////////////////////////////////
  211. // Assignment operators
  212. //  All assign a new value to the string
  213. //      (a) first see if the buffer is big enough
  214. //      (b) if enough room, copy on top of old buffer, set size and type
  215. //      (c) otherwise free old string data, and create a new one
  216. //
  217. //  All routines return the new string (but as a 'const CSPString&' so that
  218. //      assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  219. //
  220. void CSPString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
  221. {
  222. AllocBeforeWrite(nSrcLen);
  223. memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
  224. GetData()->nDataLength = nSrcLen;
  225. m_pchData[nSrcLen] = '';
  226. }
  227. const CSPString& CSPString::operator=(const CSPString& stringSrc)
  228. {
  229. if (m_pchData != stringSrc.m_pchData)
  230. {
  231. if ((GetData()->nRefs < 0 && GetData() != _afxSPDataNil) ||
  232. stringSrc.GetData()->nRefs < 0)
  233. {
  234. // actual copy necessary since one of the strings is locked
  235. AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  236. }
  237. else
  238. {
  239. // can just copy references around
  240. Release();
  241. SP_ASSERT(stringSrc.GetData() != _afxSPDataNil);
  242. m_pchData = stringSrc.m_pchData;
  243. InterlockedIncrement(&GetData()->nRefs);
  244. }
  245. }
  246. return *this;
  247. }
  248. const CSPString& CSPString::operator=(LPCTSTR lpsz)
  249. {
  250. SP_ASSERT(lpsz == NULL || SP_IsValidString(lpsz));
  251. AssignCopy(SafeStrlen(lpsz), lpsz);
  252. return *this;
  253. }
  254. /////////////////////////////////////////////////////////////////////////////
  255. // Special conversion assignment
  256. #ifdef _UNICODE
  257. const CSPString& CSPString::operator=(LPCSTR lpsz)
  258. {
  259. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  260. AllocBeforeWrite(nSrcLen);
  261. mbstowcs(m_pchData, lpsz, nSrcLen+1);
  262. ReleaseBuffer();
  263. return *this;
  264. }
  265. #else //!_UNICODE
  266. const CSPString& CSPString::operator=(LPCWSTR lpsz)
  267. {
  268. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  269. AllocBeforeWrite(nSrcLen*2);
  270. wcstombs(m_pchData, lpsz, (nSrcLen*2)+1);
  271. ReleaseBuffer();
  272. return *this;
  273. }
  274. #endif  //!_UNICODE
  275. //////////////////////////////////////////////////////////////////////////////
  276. // concatenation
  277. // NOTE: "operator+" is done as friend functions for simplicity
  278. //      There are three variants:
  279. //          CSPString + CSPString
  280. // and for ? = TCHAR, LPCTSTR
  281. //          CSPString + ?
  282. //          ? + CSPString
  283. void CSPString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
  284. int nSrc2Len, LPCTSTR lpszSrc2Data)
  285. {
  286.   // -- master concatenation routine
  287.   // Concatenate two sources
  288.   // -- assume that 'this' is a new CSPString object
  289. int nNewLen = nSrc1Len + nSrc2Len;
  290. if (nNewLen != 0)
  291. {
  292. AllocBuffer(nNewLen);
  293. memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
  294. memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
  295. }
  296. }
  297. CSPString __stdcall operator+(const CSPString& string1, const CSPString& string2)
  298. {
  299. CSPString s;
  300. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
  301. string2.GetData()->nDataLength, string2.m_pchData);
  302. return s;
  303. }
  304. CSPString __stdcall operator+(const CSPString& string, LPCTSTR lpsz)
  305. {
  306. SP_ASSERT(lpsz == NULL || SP_IsValidString(lpsz));
  307. CSPString s;
  308. s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
  309. CSPString::SafeStrlen(lpsz), lpsz);
  310. return s;
  311. }
  312. CSPString __stdcall operator+(LPCTSTR lpsz, const CSPString& string)
  313. {
  314. SP_ASSERT(lpsz == NULL || SP_IsValidString(lpsz));
  315. CSPString s;
  316. s.ConcatCopy(CSPString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
  317. string.m_pchData);
  318. return s;
  319. }
  320. //////////////////////////////////////////////////////////////////////////////
  321. // concatenate in place
  322. void CSPString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
  323. {
  324. //  -- the main routine for += operators
  325. // concatenating an empty string is a no-op!
  326. if (nSrcLen == 0)
  327. return;
  328. // if the buffer is too small, or we have a width mis-match, just
  329. //   allocate a new buffer (slow but sure)
  330. if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
  331. {
  332. // we have to grow the buffer, use the ConcatCopy routine
  333. CSPStringData* pOldData = GetData();
  334. ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
  335. SP_ASSERT(pOldData != NULL);
  336. CSPString::Release(pOldData);
  337. }
  338. else
  339. {
  340. // fast concatenation when buffer big enough
  341. memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(TCHAR));
  342. GetData()->nDataLength += nSrcLen;
  343. SP_ASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  344. m_pchData[GetData()->nDataLength] = '';
  345. }
  346. }
  347. const CSPString& CSPString::operator+=(LPCTSTR lpsz)
  348. {
  349. SP_ASSERT(lpsz == NULL || SP_IsValidString(lpsz));
  350. ConcatInPlace(SafeStrlen(lpsz), lpsz);
  351. return *this;
  352. }
  353. const CSPString& CSPString::operator+=(TCHAR ch)
  354. {
  355. ConcatInPlace(1, &ch);
  356. return *this;
  357. }
  358. const CSPString& CSPString::operator+=(const CSPString& string)
  359. {
  360. ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
  361. return *this;
  362. }
  363. ///////////////////////////////////////////////////////////////////////////////
  364. // Advanced direct buffer access
  365. LPTSTR CSPString::GetBuffer(int nMinBufLength)
  366. {
  367. SP_ASSERT(nMinBufLength >= 0);
  368. if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
  369. {
  370. #ifdef _DEBUG
  371. // give a warning in case locked string becomes unlocked
  372. if (GetData() != _afxSPDataNil && GetData()->nRefs < 0)
  373. SP_TRACE0("Warning: GetBuffer on locked CSPString creates unlocked CSPString!n");
  374. #endif
  375. // we have to grow the buffer
  376. CSPStringData* pOldData = GetData();
  377. int nOldLen = GetData()->nDataLength;   // AllocBuffer will tromp it
  378. if (nMinBufLength < nOldLen)
  379. nMinBufLength = nOldLen;
  380. AllocBuffer(nMinBufLength);
  381. memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
  382. GetData()->nDataLength = nOldLen;
  383. CSPString::Release(pOldData);
  384. }
  385. SP_ASSERT(GetData()->nRefs <= 1);
  386. // return a pointer to the character storage for this string
  387. SP_ASSERT(m_pchData != NULL);
  388. return m_pchData;
  389. }
  390. void CSPString::ReleaseBuffer(int nNewLength)
  391. {
  392. CopyBeforeWrite();  // just in case GetBuffer was not called
  393. if (nNewLength == -1)
  394. nNewLength = lstrlen(m_pchData); // zero terminated
  395. SP_ASSERT(nNewLength <= GetData()->nAllocLength);
  396. GetData()->nDataLength = nNewLength;
  397. m_pchData[nNewLength] = '';
  398. }
  399. LPTSTR CSPString::GetBufferSetLength(int nNewLength)
  400. {
  401. SP_ASSERT(nNewLength >= 0);
  402. GetBuffer(nNewLength);
  403. GetData()->nDataLength = nNewLength;
  404. m_pchData[nNewLength] = '';
  405. return m_pchData;
  406. }
  407. void CSPString::FreeExtra()
  408. {
  409. SP_ASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  410. if (GetData()->nDataLength != GetData()->nAllocLength)
  411. {
  412. CSPStringData* pOldData = GetData();
  413. AllocBuffer(GetData()->nDataLength);
  414. memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(TCHAR));
  415. SP_ASSERT(m_pchData[GetData()->nDataLength] == '');
  416. CSPString::Release(pOldData);
  417. }
  418. SP_ASSERT(GetData() != NULL);
  419. }
  420. LPTSTR CSPString::LockBuffer()
  421. {
  422. LPTSTR lpsz = GetBuffer(0);
  423. GetData()->nRefs = -1;
  424. return lpsz;
  425. }
  426. void CSPString::UnlockBuffer()
  427. {
  428. SP_ASSERT(GetData()->nRefs == -1);
  429. if (GetData() != _afxSPDataNil)
  430. GetData()->nRefs = 1;
  431. }
  432. ///////////////////////////////////////////////////////////////////////////////
  433. // Commonly used routines (rarely used routines in STREX.CPP)
  434. int CSPString::Find(TCHAR ch) const
  435. {
  436. return Find(ch, 0);
  437. }
  438. int CSPString::Find(TCHAR ch, int nStart) const
  439. {
  440. int nLength = GetData()->nDataLength;
  441. if (nStart >= nLength)
  442. return -1;
  443. // find first single character
  444. LPTSTR lpsz = _tcschr(m_pchData + nStart, ch);
  445. // return -1 if not found and index otherwise
  446. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  447. }
  448. int CSPString::FindOneOf(LPCTSTR lpszCharSet) const
  449. {
  450. SP_ASSERT(SP_IsValidString(lpszCharSet));
  451. LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);
  452. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  453. }
  454. void CSPString::MakeUpper()
  455. {
  456. CopyBeforeWrite();
  457. _tcsupr(m_pchData);
  458. }
  459. void CSPString::MakeLower()
  460. {
  461. CopyBeforeWrite();
  462. _tcslwr(m_pchData);
  463. }
  464. void CSPString::MakeReverse()
  465. {
  466. CopyBeforeWrite();
  467. _tcsrev(m_pchData);
  468. }
  469. void CSPString::SetAt(int nIndex, TCHAR ch)
  470. {
  471. SP_ASSERT(nIndex >= 0);
  472. SP_ASSERT(nIndex < GetData()->nDataLength);
  473. CopyBeforeWrite();
  474. m_pchData[nIndex] = ch;
  475. }
  476. ///////////////////////////////////////////////////////////////////////////////
  477. //////////////////////////////////////////////////////////////////////////////
  478. // More sophisticated construction
  479. CSPString::CSPString(TCHAR ch, int nLength)
  480. {
  481. Init();
  482. if (nLength >= 1)
  483. {
  484. AllocBuffer(nLength);
  485. #ifdef _UNICODE
  486. for (int i = 0; i < nLength; i++)
  487. m_pchData[i] = ch;
  488. #else
  489. memset(m_pchData, ch, nLength);
  490. #endif
  491. }
  492. }
  493. CSPString::CSPString(LPCTSTR lpch, int nLength)
  494. {
  495. Init();
  496. if (nLength != 0)
  497. {
  498. SP_ASSERT(SP_IsValidAddress((void*)lpch, nLength, FALSE));
  499. AllocBuffer(nLength);
  500. memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
  501. }
  502. }
  503. /////////////////////////////////////////////////////////////////////////////
  504. // Special conversion constructors
  505. #ifdef _UNICODE
  506. CSPString::CSPString(LPCSTR lpsz, int nLength)
  507. {
  508. Init();
  509. if (nLength != 0)
  510. {
  511. AllocBuffer(nLength);
  512. int n = ::MultiByteToWideChar(CP_ACP, 0, lpsz, nLength, m_pchData, nLength+1);
  513. ReleaseBuffer(n >= 0 ? n : -1);
  514. }
  515. }
  516. #else //_UNICODE
  517. CSPString::CSPString(LPCWSTR lpsz, int nLength)
  518. {
  519. Init();
  520. if (nLength != 0)
  521. {
  522. AllocBuffer(nLength*2);
  523. int n = ::WideCharToMultiByte(CP_ACP, 0, lpsz, nLength, m_pchData,
  524. (nLength*2)+1, NULL, NULL);
  525. ReleaseBuffer(n >= 0 ? n : -1);
  526. }
  527. }
  528. #endif //!_UNICODE
  529. //////////////////////////////////////////////////////////////////////////////
  530. // Assignment operators
  531. const CSPString& CSPString::operator=(TCHAR ch)
  532. {
  533. AssignCopy(1, &ch);
  534. return *this;
  535. }
  536. //////////////////////////////////////////////////////////////////////////////
  537. // less common string expressions
  538. CSPString __stdcall operator+(const CSPString& string1, TCHAR ch)
  539. {
  540. CSPString s;
  541. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData, 1, &ch);
  542. return s;
  543. }
  544. CSPString __stdcall operator+(TCHAR ch, const CSPString& string)
  545. {
  546. CSPString s;
  547. s.ConcatCopy(1, &ch, string.GetData()->nDataLength, string.m_pchData);
  548. return s;
  549. }
  550. //////////////////////////////////////////////////////////////////////////////
  551. // Advanced manipulation
  552. int CSPString::Delete(int nIndex, int nCount /* = 1 */)
  553. {
  554. if (nIndex < 0)
  555. nIndex = 0;
  556. int nNewLength = GetData()->nDataLength;
  557. if (nCount > 0 && nIndex < nNewLength)
  558. {
  559. CopyBeforeWrite();
  560. int nBytesToCopy = nNewLength - (nIndex + nCount) + 1;
  561. memcpy(m_pchData + nIndex,
  562. m_pchData + nIndex + nCount, nBytesToCopy * sizeof(TCHAR));
  563. GetData()->nDataLength = nNewLength - nCount;
  564. }
  565. return nNewLength;
  566. }
  567. int CSPString::Insert(int nIndex, TCHAR ch)
  568. {
  569. CopyBeforeWrite();
  570. if (nIndex < 0)
  571. nIndex = 0;
  572. int nNewLength = GetData()->nDataLength;
  573. if (nIndex > nNewLength)
  574. nIndex = nNewLength;
  575. nNewLength++;
  576. if (GetData()->nAllocLength < nNewLength)
  577. {
  578. CSPStringData* pOldData = GetData();
  579. LPTSTR pstr = m_pchData;
  580. AllocBuffer(nNewLength);
  581. memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));
  582. CSPString::Release(pOldData);
  583. }
  584. // move existing bytes down
  585. memcpy(m_pchData + nIndex + 1,
  586. m_pchData + nIndex, (nNewLength-nIndex)*sizeof(TCHAR));
  587. m_pchData[nIndex] = ch;
  588. GetData()->nDataLength = nNewLength;
  589. return nNewLength;
  590. }
  591. int CSPString::Insert(int nIndex, LPCTSTR pstr)
  592. {
  593. if (nIndex < 0)
  594. nIndex = 0;
  595. int nInsertLength = SafeStrlen(pstr);
  596. int nNewLength = GetData()->nDataLength;
  597. if (nInsertLength > 0)
  598. {
  599. CopyBeforeWrite();
  600. if (nIndex > nNewLength)
  601. nIndex = nNewLength;
  602. nNewLength += nInsertLength;
  603. if (GetData()->nAllocLength < nNewLength)
  604. {
  605. CSPStringData* pOldData = GetData();
  606. LPTSTR pstr = m_pchData;
  607. AllocBuffer(nNewLength);
  608. memcpy(m_pchData, pstr, (pOldData->nDataLength+1)*sizeof(TCHAR));
  609. CSPString::Release(pOldData);
  610. }
  611. // move existing bytes down
  612. memcpy(m_pchData + nIndex + nInsertLength,
  613. m_pchData + nIndex,
  614. (nNewLength-nIndex-nInsertLength+1)*sizeof(TCHAR));
  615. memcpy(m_pchData + nIndex,
  616. pstr, nInsertLength*sizeof(TCHAR));
  617. GetData()->nDataLength = nNewLength;
  618. }
  619. return nNewLength;
  620. }
  621. int CSPString::Replace(TCHAR chOld, TCHAR chNew)
  622. {
  623. int nCount = 0;
  624. // short-circuit the nop case
  625. if (chOld != chNew)
  626. {
  627. // otherwise modify each character that matches in the string
  628. CopyBeforeWrite();
  629. LPTSTR psz = m_pchData;
  630. LPTSTR pszEnd = psz + GetData()->nDataLength;
  631. while (psz < pszEnd)
  632. {
  633. // replace instances of the specified character only
  634. if (*psz == chOld)
  635. {
  636. *psz = chNew;
  637. nCount++;
  638. }
  639. psz = _tcsinc(psz);
  640. }
  641. }
  642. return nCount;
  643. }
  644. int CSPString::Replace(LPCTSTR lpszOld, LPCTSTR lpszNew)
  645. {
  646. // can't have empty or NULL lpszOld
  647. int nSourceLen = SafeStrlen(lpszOld);
  648. if (nSourceLen == 0)
  649. return 0;
  650. int nReplacementLen = SafeStrlen(lpszNew);
  651. // loop once to figure out the size of the result string
  652. int nCount = 0;
  653. LPTSTR lpszStart = m_pchData;
  654. LPTSTR lpszEnd = m_pchData + GetData()->nDataLength;
  655. LPTSTR lpszTarget;
  656. while (lpszStart < lpszEnd)
  657. {
  658. while ((lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
  659. {
  660. nCount++;
  661. lpszStart = lpszTarget + nSourceLen;
  662. }
  663. lpszStart += lstrlen(lpszStart) + 1;
  664. }
  665. // if any changes were made, make them
  666. if (nCount > 0)
  667. {
  668. CopyBeforeWrite();
  669. // if the buffer is too small, just
  670. //   allocate a new buffer (slow but sure)
  671. int nOldLength = GetData()->nDataLength;
  672. int nNewLength =  nOldLength + (nReplacementLen-nSourceLen)*nCount;
  673. if (GetData()->nAllocLength < nNewLength || GetData()->nRefs > 1)
  674. {
  675. CSPStringData* pOldData = GetData();
  676. LPTSTR pstr = m_pchData;
  677. AllocBuffer(nNewLength);
  678. memcpy(m_pchData, pstr, pOldData->nDataLength*sizeof(TCHAR));
  679. CSPString::Release(pOldData);
  680. }
  681. // else, we just do it in-place
  682. lpszStart = m_pchData;
  683. lpszEnd = m_pchData + GetData()->nDataLength;
  684. // loop again to actually do the work
  685. while (lpszStart < lpszEnd)
  686. {
  687. while ( (lpszTarget = _tcsstr(lpszStart, lpszOld)) != NULL)
  688. {
  689. int nBalance = nOldLength - (lpszTarget - m_pchData + nSourceLen);
  690. memmove(lpszTarget + nReplacementLen, lpszTarget + nSourceLen,
  691. nBalance * sizeof(TCHAR));
  692. memcpy(lpszTarget, lpszNew, nReplacementLen*sizeof(TCHAR));
  693. lpszStart = lpszTarget + nReplacementLen;
  694. lpszStart[nBalance] = '';
  695. nOldLength += (nReplacementLen - nSourceLen);
  696. }
  697. lpszStart += lstrlen(lpszStart) + 1;
  698. }
  699. SP_ASSERT(m_pchData[nNewLength] == '');
  700. GetData()->nDataLength = nNewLength;
  701. }
  702. return nCount;
  703. }
  704. int CSPString::Remove(TCHAR chRemove)
  705. {
  706. CopyBeforeWrite();
  707. LPTSTR pstrSource = m_pchData;
  708. LPTSTR pstrDest = m_pchData;
  709. LPTSTR pstrEnd = m_pchData + GetData()->nDataLength;
  710. while (pstrSource < pstrEnd)
  711. {
  712. if (*pstrSource != chRemove)
  713. {
  714. *pstrDest = *pstrSource;
  715. pstrDest = _tcsinc(pstrDest);
  716. }
  717. pstrSource = _tcsinc(pstrSource);
  718. }
  719. *pstrDest = '';
  720. int nCount = pstrSource - pstrDest;
  721. GetData()->nDataLength -= nCount;
  722. return nCount;
  723. }
  724. //////////////////////////////////////////////////////////////////////////////
  725. // Very simple sub-string extraction
  726. CSPString CSPString::Mid(int nFirst) const
  727. {
  728. return Mid(nFirst, GetData()->nDataLength - nFirst);
  729. }
  730. CSPString CSPString::Mid(int nFirst, int nCount) const
  731. {
  732. // out-of-bounds requests return sensible things
  733. if (nFirst < 0)
  734. nFirst = 0;
  735. if (nCount < 0)
  736. nCount = 0;
  737. if (nFirst + nCount > GetData()->nDataLength)
  738. nCount = GetData()->nDataLength - nFirst;
  739. if (nFirst > GetData()->nDataLength)
  740. nCount = 0;
  741. SP_ASSERT(nFirst >= 0);
  742. SP_ASSERT(nFirst + nCount <= GetData()->nDataLength);
  743. // optimize case of returning entire string
  744. if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
  745. return *this;
  746. CSPString dest;
  747. AllocCopy(dest, nCount, nFirst, 0);
  748. return dest;
  749. }
  750. CSPString CSPString::Right(int nCount) const
  751. {
  752. if (nCount < 0)
  753. nCount = 0;
  754. if (nCount >= GetData()->nDataLength)
  755. return *this;
  756. CSPString dest;
  757. AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
  758. return dest;
  759. }
  760. CSPString CSPString::Left(int nCount) const
  761. {
  762. if (nCount < 0)
  763. nCount = 0;
  764. if (nCount >= GetData()->nDataLength)
  765. return *this;
  766. CSPString dest;
  767. AllocCopy(dest, nCount, 0, 0);
  768. return dest;
  769. }
  770. // strspn equivalent
  771. CSPString CSPString::SpanIncluding(LPCTSTR lpszCharSet) const
  772. {
  773. SP_ASSERT(SP_IsValidString(lpszCharSet));
  774. return Left(_tcsspn(m_pchData, lpszCharSet));
  775. }
  776. // strcspn equivalent
  777. CSPString CSPString::SpanExcluding(LPCTSTR lpszCharSet) const
  778. {
  779. SP_ASSERT(SP_IsValidString(lpszCharSet));
  780. return Left(_tcscspn(m_pchData, lpszCharSet));
  781. }
  782. //////////////////////////////////////////////////////////////////////////////
  783. // Finding
  784. int CSPString::ReverseFind(TCHAR ch) const
  785. {
  786. // find last single character
  787. LPTSTR lpsz = _tcsrchr(m_pchData, (_TUCHAR) ch);
  788. // return -1 if not found, distance from beginning otherwise
  789. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  790. }
  791. // find a sub-string (like strstr)
  792. int CSPString::Find(LPCTSTR lpszSub) const
  793. {
  794. return Find(lpszSub, 0);
  795. }
  796. int CSPString::Find(LPCTSTR lpszSub, int nStart) const
  797. {
  798. SP_ASSERT(SP_IsValidString(lpszSub));
  799. int nLength = GetData()->nDataLength;
  800. if (nStart > nLength)
  801. return -1;
  802. // find first matching substring
  803. LPTSTR lpsz = _tcsstr(m_pchData + nStart, lpszSub);
  804. // return -1 for not found, distance from beginning otherwise
  805. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  806. }
  807. /////////////////////////////////////////////////////////////////////////////
  808. // CSPString formatting
  809. #define TCHAR_ARG   TCHAR
  810. #define WCHAR_ARG   WCHAR
  811. #define CHAR_ARG    char
  812. struct _AFX_DOUBLE  { BYTE doubleBits[sizeof(double)]; };
  813. struct _AFX_FLOAT   { BYTE floatBits[sizeof(float)]; };
  814. #ifdef _X86_
  815. #define DOUBLE_ARG  _AFX_DOUBLE
  816. #else
  817. #define DOUBLE_ARG  double
  818. #endif
  819. #define FORCE_ANSI      0x10000
  820. #define FORCE_UNICODE   0x20000
  821. #define FORCE_INT64     0x40000
  822. void CSPString::FormatV(LPCTSTR lpszFormat, va_list argList)
  823. {
  824. SP_ASSERT(SP_IsValidString(lpszFormat));
  825. va_list argListSave = argList;
  826. // make a guess at the maximum length of the resulting string
  827. int nMaxLen = 0;
  828. for (LPCTSTR lpsz = lpszFormat; *lpsz != ''; lpsz = _tcsinc(lpsz))
  829. {
  830. // handle '%' character, but watch out for '%%'
  831. if (*lpsz != '%' || *(lpsz = _tcsinc(lpsz)) == '%')
  832. {
  833. nMaxLen += _tclen(lpsz);
  834. continue;
  835. }
  836. int nItemLen = 0;
  837. // handle '%' character with format
  838. int nWidth = 0;
  839. for (; *lpsz != ''; lpsz = _tcsinc(lpsz))
  840. {
  841. // check for valid flags
  842. if (*lpsz == '#')
  843. nMaxLen += 2;   // for '0x'
  844. else if (*lpsz == '*')
  845. nWidth = va_arg(argList, int);
  846. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  847. *lpsz == ' ')
  848. ;
  849. else // hit non-flag character
  850. break;
  851. }
  852. // get width and skip it
  853. if (nWidth == 0)
  854. {
  855. // width indicated by
  856. nWidth = _ttoi(lpsz);
  857. for (; *lpsz != '' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  858. ;
  859. }
  860. SP_ASSERT(nWidth >= 0);
  861. int nPrecision = 0;
  862. if (*lpsz == '.')
  863. {
  864. // skip past '.' separator (width.precision)
  865. lpsz = _tcsinc(lpsz);
  866. // get precision and skip it
  867. if (*lpsz == '*')
  868. {
  869. nPrecision = va_arg(argList, int);
  870. lpsz = _tcsinc(lpsz);
  871. }
  872. else
  873. {
  874. nPrecision = _ttoi(lpsz);
  875. for (; *lpsz != '' && _istdigit(*lpsz); lpsz = _tcsinc(lpsz))
  876. ;
  877. }
  878. SP_ASSERT(nPrecision >= 0);
  879. }
  880. // should be on type modifier or specifier
  881. int nModifier = 0;
  882. if (_tcsncmp(lpsz, _T("I64"), 3) == 0)
  883. {
  884. lpsz += 3;
  885. nModifier = FORCE_INT64;
  886. #if !defined(_X86_) && !defined(_ALPHA_)
  887. // __int64 is only available on X86 and ALPHA platforms
  888. SP_ASSERT(FALSE);
  889. #endif
  890. }
  891. else
  892. {
  893. switch (*lpsz)
  894. {
  895. // modifiers that affect size
  896. case 'h':
  897. nModifier = FORCE_ANSI;
  898. lpsz = _tcsinc(lpsz);
  899. break;
  900. case 'l':
  901. nModifier = FORCE_UNICODE;
  902. lpsz = _tcsinc(lpsz);
  903. break;
  904. // modifiers that do not affect size
  905. case 'F':
  906. case 'N':
  907. case 'L':
  908. lpsz = _tcsinc(lpsz);
  909. break;
  910. }
  911. }
  912. // now should be on specifier
  913. switch (*lpsz | nModifier)
  914. {
  915. // single characters
  916. case 'c':
  917. case 'C':
  918. nItemLen = 2;
  919. va_arg(argList, TCHAR_ARG);
  920. break;
  921. case 'c'|FORCE_ANSI:
  922. case 'C'|FORCE_ANSI:
  923. nItemLen = 2;
  924. va_arg(argList, CHAR_ARG);
  925. break;
  926. case 'c'|FORCE_UNICODE:
  927. case 'C'|FORCE_UNICODE:
  928. nItemLen = 2;
  929. va_arg(argList, WCHAR_ARG);
  930. break;
  931. // strings
  932. case 's':
  933. {
  934. LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
  935. if (pstrNextArg == NULL)
  936.    nItemLen = 6;  // "(null)"
  937. else
  938. {
  939.    nItemLen = lstrlen(pstrNextArg);
  940.    nItemLen = max(1, nItemLen);
  941. }
  942. }
  943. break;
  944. case 'S':
  945. {
  946. #ifndef _UNICODE
  947. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  948. if (pstrNextArg == NULL)
  949.    nItemLen = 6;  // "(null)"
  950. else
  951. {
  952.    nItemLen = wcslen(pstrNextArg);
  953.    nItemLen = max(1, nItemLen);
  954. }
  955. #else
  956. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  957. if (pstrNextArg == NULL)
  958.    nItemLen = 6; // "(null)"
  959. else
  960. {
  961.    nItemLen = lstrlenA(pstrNextArg);
  962.    nItemLen = max(1, nItemLen);
  963. }
  964. #endif
  965. }
  966. break;
  967. case 's'|FORCE_ANSI:
  968. case 'S'|FORCE_ANSI:
  969. {
  970. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  971. if (pstrNextArg == NULL)
  972.    nItemLen = 6; // "(null)"
  973. else
  974. {
  975.    nItemLen = lstrlenA(pstrNextArg);
  976.    nItemLen = max(1, nItemLen);
  977. }
  978. }
  979. break;
  980. case 's'|FORCE_UNICODE:
  981. case 'S'|FORCE_UNICODE:
  982. {
  983. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  984. if (pstrNextArg == NULL)
  985.    nItemLen = 6; // "(null)"
  986. else
  987. {
  988.    nItemLen = wcslen(pstrNextArg);
  989.    nItemLen = max(1, nItemLen);
  990. }
  991. }
  992. break;
  993. }
  994. // adjust nItemLen for strings
  995. if (nItemLen != 0)
  996. {
  997. if (nPrecision != 0)
  998. nItemLen = min(nItemLen, nPrecision);
  999. nItemLen = max(nItemLen, nWidth);
  1000. }
  1001. else
  1002. {
  1003. switch (*lpsz)
  1004. {
  1005. // integers
  1006. case 'd':
  1007. case 'i':
  1008. case 'u':
  1009. case 'x':
  1010. case 'X':
  1011. case 'o':
  1012. if (nModifier & FORCE_INT64)
  1013. va_arg(argList, __int64);
  1014. else
  1015. va_arg(argList, int);
  1016. nItemLen = 32;
  1017. nItemLen = max(nItemLen, nWidth+nPrecision);
  1018. break;
  1019. case 'e':
  1020. case 'g':
  1021. case 'G':
  1022. va_arg(argList, DOUBLE_ARG);
  1023. nItemLen = 128;
  1024. nItemLen = max(nItemLen, nWidth+nPrecision);
  1025. break;
  1026. case 'f':
  1027. va_arg(argList, DOUBLE_ARG);
  1028. nItemLen = 128; // width isn't truncated
  1029. // 312 == strlen("-1+(309 zeroes).")
  1030. // 309 zeroes == max precision of a double
  1031. nItemLen = max(nItemLen, 312+nPrecision);
  1032. break;
  1033. case 'p':
  1034. va_arg(argList, void*);
  1035. nItemLen = 32;
  1036. nItemLen = max(nItemLen, nWidth+nPrecision);
  1037. break;
  1038. // no output
  1039. case 'n':
  1040. va_arg(argList, int*);
  1041. break;
  1042. default:
  1043. SP_ASSERT(FALSE);  // unknown formatting option
  1044. }
  1045. }
  1046. // adjust nMaxLen for output nItemLen
  1047. nMaxLen += nItemLen;
  1048. }
  1049. GetBuffer(nMaxLen);
  1050. SP_VERIFY(_vstprintf(m_pchData, lpszFormat, argListSave) <= GetAllocLength());
  1051. ReleaseBuffer();
  1052. va_end(argListSave);
  1053. }
  1054. /* My Version
  1055. // formatting (using wsprintf style formatting)
  1056. void __cdecl CSPString::Format(LPCTSTR lpszFormat, ...)
  1057. {
  1058. // 暂不支持较长字符串
  1059. SP_ASSERT( NULL != lpszFormat && strlen(lpszFormat) < 1024 );
  1060. size_t nSize = 1024+4*strlen(lpszFormat);
  1061. TCHAR * lpBuf = new TCHAR[nSize];
  1062. va_list argList;
  1063. va_start(argList, lpszFormat);
  1064. vsprintf( lpBuf, lpszFormat, argList);
  1065. va_end(argList);
  1066. *this = lpBuf;
  1067. delete [] lpBuf;
  1068. }
  1069. */
  1070. // formatting (using wsprintf style formatting)
  1071. void __cdecl CSPString::Format(LPCTSTR lpszFormat, ...)
  1072. {
  1073. SP_ASSERT(SP_IsValidString(lpszFormat));
  1074. va_list argList;
  1075. va_start(argList, lpszFormat);
  1076. FormatV(lpszFormat, argList);
  1077. va_end(argList);
  1078. }
  1079. void __cdecl CSPString::Format(UINT nFormatID, ...)
  1080. {
  1081. CSPString strFormat;
  1082. SP_VERIFY(strFormat.LoadString(nFormatID) != 0);
  1083. va_list argList;
  1084. va_start(argList, nFormatID);
  1085. FormatV(strFormat, argList);
  1086. va_end(argList);
  1087. }
  1088. BOOL CSPString::LoadString(UINT nID)
  1089. {
  1090. SP_ASSERT( FALSE ); // Not supported Now!!!
  1091. return FALSE;
  1092. }
  1093. void CSPString::TrimRight(LPCTSTR lpszTargetList)
  1094. {
  1095. // find beginning of trailing matches
  1096. // by starting at beginning (DBCS aware)
  1097. CopyBeforeWrite();
  1098. LPTSTR lpsz = m_pchData;
  1099. LPTSTR lpszLast = NULL;
  1100. while (*lpsz != '')
  1101. {
  1102. if (_tcschr(lpszTargetList, *lpsz) != NULL)
  1103. {
  1104. if (lpszLast == NULL)
  1105. lpszLast = lpsz;
  1106. }
  1107. else
  1108. lpszLast = NULL;
  1109. lpsz = _tcsinc(lpsz);
  1110. }
  1111. if (lpszLast != NULL)
  1112. {
  1113. // truncate at left-most matching character
  1114. *lpszLast = '';
  1115. GetData()->nDataLength = lpszLast - m_pchData;
  1116. }
  1117. }
  1118. void CSPString::TrimRight(TCHAR chTarget)
  1119. {
  1120. // find beginning of trailing matches
  1121. // by starting at beginning (DBCS aware)
  1122. CopyBeforeWrite();
  1123. LPTSTR lpsz = m_pchData;
  1124. LPTSTR lpszLast = NULL;
  1125. while (*lpsz != '')
  1126. {
  1127. if (*lpsz == chTarget)
  1128. {
  1129. if (lpszLast == NULL)
  1130. lpszLast = lpsz;
  1131. }
  1132. else
  1133. lpszLast = NULL;
  1134. lpsz = _tcsinc(lpsz);
  1135. }
  1136. if (lpszLast != NULL)
  1137. {
  1138. // truncate at left-most matching character
  1139. *lpszLast = '';
  1140. GetData()->nDataLength = lpszLast - m_pchData;
  1141. }
  1142. }
  1143. void CSPString::TrimRight()
  1144. {
  1145. // find beginning of trailing spaces by starting at beginning (DBCS aware)
  1146. CopyBeforeWrite();
  1147. LPTSTR lpsz = m_pchData;
  1148. LPTSTR lpszLast = NULL;
  1149. while (*lpsz != '')
  1150. {
  1151. if (_istspace(*lpsz))
  1152. {
  1153. if (lpszLast == NULL)
  1154. lpszLast = lpsz;
  1155. }
  1156. else
  1157. lpszLast = NULL;
  1158. lpsz = _tcsinc(lpsz);
  1159. }
  1160. if (lpszLast != NULL)
  1161. {
  1162. // truncate at trailing space start
  1163. *lpszLast = '';
  1164. GetData()->nDataLength = lpszLast - m_pchData;
  1165. }
  1166. }
  1167. void CSPString::TrimLeft(LPCTSTR lpszTargets)
  1168. {
  1169. // if we're not trimming anything, we're not doing any work
  1170. if (SafeStrlen(lpszTargets) == 0)
  1171. return;
  1172. CopyBeforeWrite();
  1173. LPCTSTR lpsz = m_pchData;
  1174. while (*lpsz != '')
  1175. {
  1176. if (_tcschr(lpszTargets, *lpsz) == NULL)
  1177. break;
  1178. lpsz = _tcsinc(lpsz);
  1179. }
  1180. if (lpsz != m_pchData)
  1181. {
  1182. // fix up data and length
  1183. int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  1184. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  1185. GetData()->nDataLength = nDataLength;
  1186. }
  1187. }
  1188. void CSPString::TrimLeft(TCHAR chTarget)
  1189. {
  1190. // find first non-matching character
  1191. CopyBeforeWrite();
  1192. LPCTSTR lpsz = m_pchData;
  1193. while (chTarget == *lpsz)
  1194. lpsz = _tcsinc(lpsz);
  1195. if (lpsz != m_pchData)
  1196. {
  1197. // fix up data and length
  1198. int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  1199. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  1200. GetData()->nDataLength = nDataLength;
  1201. }
  1202. }
  1203. void CSPString::TrimLeft()
  1204. {
  1205. // find first non-space character
  1206. CopyBeforeWrite();
  1207. LPCTSTR lpsz = m_pchData;
  1208. while (_istspace(*lpsz))
  1209. lpsz = _tcsinc(lpsz);
  1210. if (lpsz != m_pchData)
  1211. {
  1212. // fix up data and length
  1213. int nDataLength = GetData()->nDataLength - (lpsz - m_pchData);
  1214. memmove(m_pchData, lpsz, (nDataLength+1)*sizeof(TCHAR));
  1215. GetData()->nDataLength = nDataLength;
  1216. }
  1217. }