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.

1458 lines
32 KiB

  1. // FauxMFC.cpp
  2. #include "stdafx.h"
  3. #include "FauxMFC.h"
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <limits.h>
  7. const TCHAR afxChNil = '\0';
  8. const /*AFX_STATIC_DATA*/ int _afxInitData[] = { -1, 0, 0, 0 };
  9. const /*AFX_STATIC_DATA*/ CStringData* _afxDataNil = (CStringData*)&_afxInitData;
  10. const LPCTSTR _afxPchNil = (LPCTSTR)(((BYTE*)&_afxInitData)+sizeof(CStringData));
  11. struct _AFX_DOUBLE { BYTE doubleBits[sizeof(double)]; };
  12. #define TCHAR_ARG TCHAR
  13. #define WCHAR_ARG WCHAR
  14. #define CHAR_ARG char
  15. #define DOUBLE_ARG _AFX_DOUBLE
  16. #define FORCE_ANSI 0x10000
  17. #define FORCE_UNICODE 0x20000
  18. #define FORCE_INT64 0x40000
  19. #define IS_DIGIT(c) ((UINT)(c) - (UINT)('0') <= 9)
  20. //////////////////////////////////////////////////////////////////////////////
  21. // Global MFC stuff
  22. HINSTANCE AFXAPI AfxGetResourceHandle(void)
  23. {
  24. return GetModuleHandle(NULL);
  25. }
  26. BOOL AFXAPI AfxIsValidString(LPCSTR lpsz, int nLength = -1)
  27. {
  28. if (lpsz == NULL)
  29. return FALSE;
  30. return ::IsBadStringPtrA(lpsz, nLength) == 0;
  31. }
  32. //////////////////////////////////////////////////////////////////////////////
  33. // CString
  34. CString::CString(LPCTSTR lpsz)
  35. {
  36. Init();
  37. if (lpsz != NULL && HIWORD(lpsz) == NULL)
  38. {
  39. ASSERT(FALSE);
  40. //UINT nID = LOWORD((DWORD)lpsz);
  41. //LoadString(nID);
  42. }
  43. else
  44. {
  45. int nLen = SafeStrlen(lpsz);
  46. if (nLen != 0)
  47. {
  48. AllocBuffer(nLen);
  49. memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
  50. }
  51. }
  52. }
  53. CString::CString(const CString& stringSrc)
  54. {
  55. ASSERT(stringSrc.GetData()->nRefs != 0);
  56. if (stringSrc.GetData()->nRefs >= 0)
  57. {
  58. ASSERT(stringSrc.GetData() != _afxDataNil);
  59. m_pchData = stringSrc.m_pchData;
  60. InterlockedIncrement(&GetData()->nRefs);
  61. }
  62. else
  63. {
  64. Init();
  65. *this = stringSrc.m_pchData;
  66. }
  67. }
  68. CString::CString(TCHAR ch, int nLength)
  69. {
  70. Init();
  71. if (nLength >= 1)
  72. {
  73. AllocBuffer(nLength);
  74. #ifdef _UNICODE
  75. for (int i = 0; i < nLength; i++)
  76. m_pchData[i] = ch;
  77. #else
  78. memset(m_pchData, ch, nLength);
  79. #endif
  80. }
  81. }
  82. CString::CString(LPCTSTR lpch, int nLength)
  83. {
  84. Init();
  85. if (nLength != 0)
  86. {
  87. // ASSERT(AfxIsValidAddress(lpch, nLength, FALSE));
  88. AllocBuffer(nLength);
  89. memcpy(m_pchData, lpch, nLength*sizeof(TCHAR));
  90. }
  91. }
  92. CString::~CString()
  93. // free any attached data
  94. {
  95. if (GetData() != _afxDataNil)
  96. {
  97. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  98. FreeData(GetData());
  99. }
  100. }
  101. CString AFXAPI operator+(const CString& string1, const CString& string2)
  102. {
  103. CString s;
  104. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
  105. string2.GetData()->nDataLength, string2.m_pchData);
  106. return s;
  107. }
  108. CString AFXAPI operator+(const CString& string, LPCTSTR lpsz)
  109. {
  110. ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
  111. CString s;
  112. s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
  113. CString::SafeStrlen(lpsz), lpsz);
  114. return s;
  115. }
  116. CString AFXAPI operator+(LPCTSTR lpsz, const CString& string)
  117. {
  118. ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
  119. CString s;
  120. s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
  121. string.m_pchData);
  122. return s;
  123. }
  124. BOOL CString::LoadString(UINT nID)
  125. {
  126. HINSTANCE hInst = AfxGetResourceHandle();
  127. int cch;
  128. if (!FindResourceString(hInst, nID, &cch, 0))
  129. return FALSE;
  130. AllocBuffer(cch);
  131. if (cch != 0)
  132. ::LoadString(hInst, nID, this->m_pchData, cch+1);
  133. return TRUE;
  134. }
  135. void CString::FormatV(LPCTSTR lpszFormat, va_list argList)
  136. {
  137. // ASSERT(AfxIsValidString(lpszFormat));
  138. va_list argListSave = argList;
  139. int nMaxLen = 0;
  140. // make a guess at the maximum length of the resulting string
  141. for (LPCTSTR lpsz = lpszFormat; *lpsz != '\0'; ++lpsz)
  142. {
  143. // handle '%' character, but watch out for '%%'
  144. if (*lpsz != '%' || *(++lpsz) == '%')
  145. {
  146. nMaxLen += 2; //_tclen(lpsz);
  147. continue;
  148. }
  149. int nItemLen = 0;
  150. // handle '%' character with format
  151. int nWidth = 0;
  152. for (; *lpsz != '\0'; lpsz = CharNext(lpsz))
  153. {
  154. // check for valid flags
  155. if (*lpsz == '#')
  156. nMaxLen += 2; // for '0x'
  157. else if (*lpsz == '*')
  158. nWidth = va_arg(argList, int);
  159. else if (*lpsz == '-' || *lpsz == '+' || *lpsz == '0' ||
  160. *lpsz == ' ')
  161. ;
  162. else // hit non-flag character
  163. break;
  164. }
  165. // get width and skip it
  166. if (nWidth == 0)
  167. {
  168. // width indicated by
  169. nWidth = MyAtoi(lpsz); //_ttoi(lpsz);
  170. for (; *lpsz != '\0' && IS_DIGIT(*lpsz); lpsz = CharNext(lpsz))
  171. ;
  172. }
  173. ASSERT(nWidth >= 0);
  174. int nPrecision = 0;
  175. if (*lpsz == '.')
  176. {
  177. // skip past '.' separator (width.precision)
  178. lpsz = CharNext(lpsz);
  179. // get precision and skip it
  180. if (*lpsz == '*')
  181. {
  182. nPrecision = va_arg(argList, int);
  183. lpsz = CharNext(lpsz);
  184. }
  185. else
  186. {
  187. nPrecision = MyAtoi(lpsz); //_ttoi(lpsz);
  188. for (; *lpsz != '\0' && IS_DIGIT(*lpsz); lpsz = CharNext(lpsz))
  189. ;
  190. }
  191. ASSERT(nPrecision >= 0);
  192. }
  193. // should be on type modifier or specifier
  194. int nModifier = 0;
  195. #if 0 // we don't need this code -ks 7/26/1999
  196. if (_tcsncmp(lpsz, _T("I64"), 3) == 0)
  197. {
  198. lpsz += 3;
  199. nModifier = FORCE_INT64;
  200. #if !defined(_X86_) && !defined(_ALPHA_)
  201. // __int64 is only available on X86 and ALPHA platforms
  202. ASSERT(FALSE);
  203. #endif
  204. }
  205. else
  206. #endif
  207. {
  208. switch (*lpsz)
  209. {
  210. // modifiers that affect size
  211. case 'h':
  212. nModifier = FORCE_ANSI;
  213. lpsz = CharNext(lpsz);
  214. break;
  215. case 'l':
  216. nModifier = FORCE_UNICODE;
  217. lpsz = CharNext(lpsz);
  218. break;
  219. // modifiers that do not affect size
  220. case 'F':
  221. case 'N':
  222. case 'L':
  223. lpsz = CharNext(lpsz);
  224. break;
  225. }
  226. }
  227. // now should be on specifier
  228. switch (*lpsz | nModifier)
  229. {
  230. // single characters
  231. case 'c':
  232. case 'C':
  233. nItemLen = 2;
  234. va_arg(argList, TCHAR_ARG);
  235. break;
  236. case 'c'|FORCE_ANSI:
  237. case 'C'|FORCE_ANSI:
  238. nItemLen = 2;
  239. va_arg(argList, CHAR_ARG);
  240. break;
  241. case 'c'|FORCE_UNICODE:
  242. case 'C'|FORCE_UNICODE:
  243. nItemLen = 2;
  244. va_arg(argList, WCHAR_ARG);
  245. break;
  246. // strings
  247. case 's':
  248. {
  249. LPCTSTR pstrNextArg = va_arg(argList, LPCTSTR);
  250. if (pstrNextArg == NULL)
  251. nItemLen = 6; // "(null)"
  252. else
  253. {
  254. nItemLen = lstrlen(pstrNextArg);
  255. nItemLen = max(1, nItemLen);
  256. }
  257. }
  258. break;
  259. case 'S':
  260. {
  261. #ifndef _UNICODE
  262. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  263. if (pstrNextArg == NULL)
  264. nItemLen = 6; // "(null)"
  265. else
  266. {
  267. nItemLen = wcslen(pstrNextArg);
  268. nItemLen = max(1, nItemLen);
  269. }
  270. #else
  271. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  272. if (pstrNextArg == NULL)
  273. nItemLen = 6; // "(null)"
  274. else
  275. {
  276. nItemLen = lstrlenA(pstrNextArg);
  277. nItemLen = max(1, nItemLen);
  278. }
  279. #endif
  280. }
  281. break;
  282. case 's'|FORCE_ANSI:
  283. case 'S'|FORCE_ANSI:
  284. {
  285. LPCSTR pstrNextArg = va_arg(argList, LPCSTR);
  286. if (pstrNextArg == NULL)
  287. nItemLen = 6; // "(null)"
  288. else
  289. {
  290. nItemLen = lstrlenA(pstrNextArg);
  291. nItemLen = max(1, nItemLen);
  292. }
  293. }
  294. break;
  295. case 's'|FORCE_UNICODE:
  296. case 'S'|FORCE_UNICODE:
  297. {
  298. LPWSTR pstrNextArg = va_arg(argList, LPWSTR);
  299. if (pstrNextArg == NULL)
  300. nItemLen = 6; // "(null)"
  301. else
  302. {
  303. nItemLen = wcslen(pstrNextArg);
  304. nItemLen = max(1, nItemLen);
  305. }
  306. }
  307. break;
  308. }
  309. // adjust nItemLen for strings
  310. if (nItemLen != 0)
  311. {
  312. if (nPrecision != 0)
  313. nItemLen = min(nItemLen, nPrecision);
  314. nItemLen = max(nItemLen, nWidth);
  315. }
  316. else
  317. {
  318. switch (*lpsz)
  319. {
  320. // integers
  321. case 'd':
  322. case 'i':
  323. case 'u':
  324. case 'x':
  325. case 'X':
  326. case 'o':
  327. if (nModifier & FORCE_INT64)
  328. va_arg(argList, __int64);
  329. else
  330. va_arg(argList, int);
  331. nItemLen = 32;
  332. nItemLen = max(nItemLen, nWidth+nPrecision);
  333. break;
  334. case 'e':
  335. case 'g':
  336. case 'G':
  337. va_arg(argList, DOUBLE_ARG);
  338. nItemLen = 128;
  339. nItemLen = max(nItemLen, nWidth+nPrecision);
  340. break;
  341. case 'f':
  342. va_arg(argList, DOUBLE_ARG);
  343. nItemLen = 128; // width isn't truncated
  344. // 312 == strlen("-1+(309 zeroes).")
  345. // 309 zeroes == max precision of a double
  346. nItemLen = max(nItemLen, 312+nPrecision);
  347. break;
  348. case 'p':
  349. va_arg(argList, void*);
  350. nItemLen = 32;
  351. nItemLen = max(nItemLen, nWidth+nPrecision);
  352. break;
  353. // no output
  354. case 'n':
  355. va_arg(argList, int*);
  356. break;
  357. default:
  358. ASSERT(FALSE); // unknown formatting option
  359. }
  360. }
  361. // adjust nMaxLen for output nItemLen
  362. nMaxLen += nItemLen;
  363. }
  364. GetBuffer(nMaxLen);
  365. #ifdef UNICODE
  366. wvnsprintf(m_pchData, ARRAYSIZE(m_pchData), lpszFormat, argListSave);
  367. #else
  368. wvsprintf(m_pchData, lpszFormat, argListSave);
  369. #endif
  370. ReleaseBuffer();
  371. va_end(argListSave);
  372. }
  373. void AFX_CDECL CString::Format(UINT nFormatID, ...)
  374. {
  375. CString strFormat;
  376. strFormat.LoadString(nFormatID);
  377. va_list argList;
  378. va_start(argList, nFormatID);
  379. FormatV(strFormat, argList);
  380. va_end(argList);
  381. }
  382. // formatting (using wsprintf style formatting)
  383. void AFX_CDECL CString::Format(LPCTSTR lpszFormat, ...)
  384. {
  385. ASSERT(AfxIsValidString(lpszFormat));
  386. va_list argList;
  387. va_start(argList, lpszFormat);
  388. FormatV(lpszFormat, argList);
  389. va_end(argList);
  390. }
  391. void CString::Empty()
  392. {
  393. if (GetData()->nDataLength == 0)
  394. return;
  395. if (GetData()->nRefs >= 0)
  396. Release();
  397. else
  398. *this = &afxChNil;
  399. ASSERT(GetData()->nDataLength == 0);
  400. ASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
  401. }
  402. const CString& CString::operator=(const CString& stringSrc)
  403. {
  404. if (m_pchData != stringSrc.m_pchData)
  405. {
  406. if ((GetData()->nRefs < 0 && GetData() != _afxDataNil) ||
  407. stringSrc.GetData()->nRefs < 0)
  408. {
  409. // actual copy necessary since one of the strings is locked
  410. AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  411. }
  412. else
  413. {
  414. // can just copy references around
  415. Release();
  416. ASSERT(stringSrc.GetData() != _afxDataNil);
  417. m_pchData = stringSrc.m_pchData;
  418. InterlockedIncrement(&GetData()->nRefs);
  419. }
  420. }
  421. return *this;
  422. }
  423. const CString& CString::operator=(LPCTSTR lpsz)
  424. {
  425. ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
  426. AssignCopy(SafeStrlen(lpsz), lpsz);
  427. return *this;
  428. }
  429. int AFX_CDECL _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
  430. {
  431. if (count == 0 && mbstr != NULL)
  432. return 0;
  433. int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1,
  434. mbstr, count, NULL, NULL);
  435. ASSERT(mbstr == NULL || result <= (int)count);
  436. if (result > 0)
  437. mbstr[result-1] = 0;
  438. return result;
  439. }
  440. const CString& CString::operator=(LPCWSTR lpsz)
  441. {
  442. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  443. AllocBeforeWrite(nSrcLen*2);
  444. _wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  445. ReleaseBuffer();
  446. return *this;
  447. }
  448. CString CString::Left(int nCount) const
  449. {
  450. if (nCount < 0)
  451. nCount = 0;
  452. if (nCount >= GetData()->nDataLength)
  453. return *this;
  454. CString dest;
  455. AllocCopy(dest, nCount, 0, 0);
  456. return dest;
  457. }
  458. CString CString::Right(int nCount) const
  459. {
  460. if (nCount < 0)
  461. nCount = 0;
  462. if (nCount >= GetData()->nDataLength)
  463. return *this;
  464. CString dest;
  465. AllocCopy(dest, nCount, GetData()->nDataLength-nCount, 0);
  466. return dest;
  467. }
  468. // find a sub-string (like strstr)
  469. int CString::Find(LPCTSTR lpszSub) const
  470. {
  471. return Find(lpszSub, 0);
  472. }
  473. int CString::Find(LPCTSTR lpszSub, int nStart) const
  474. {
  475. ASSERT(AfxIsValidString(lpszSub));
  476. int nLength = GetData()->nDataLength;
  477. if (nStart > nLength)
  478. return -1;
  479. // find first matching substring
  480. // LPTSTR lpsz = _tcsstr(m_pchData + nStart, lpszSub);
  481. LPTSTR lpsz = strstr(m_pchData + nStart, lpszSub);
  482. // return -1 for not found, distance from beginning otherwise
  483. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  484. }
  485. LPTSTR CString::GetBuffer(int nMinBufLength)
  486. {
  487. ASSERT(nMinBufLength >= 0);
  488. if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
  489. {
  490. // we have to grow the buffer
  491. CStringData* pOldData = GetData();
  492. int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
  493. if (nMinBufLength < nOldLen)
  494. nMinBufLength = nOldLen;
  495. AllocBuffer(nMinBufLength);
  496. memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
  497. GetData()->nDataLength = nOldLen;
  498. CString::Release(pOldData);
  499. }
  500. ASSERT(GetData()->nRefs <= 1);
  501. // return a pointer to the character storage for this string
  502. ASSERT(m_pchData != NULL);
  503. return m_pchData;
  504. }
  505. LPTSTR CString::GetBufferSetLength(int nNewLength)
  506. {
  507. ASSERT(nNewLength >= 0);
  508. GetBuffer(nNewLength);
  509. GetData()->nDataLength = nNewLength;
  510. m_pchData[nNewLength] = '\0';
  511. return m_pchData;
  512. }
  513. void CString::Release()
  514. {
  515. if (GetData() != _afxDataNil)
  516. {
  517. ASSERT(GetData()->nRefs != 0);
  518. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  519. FreeData(GetData());
  520. Init();
  521. }
  522. }
  523. void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
  524. {
  525. if (nSrcLen)
  526. {
  527. AllocBeforeWrite(nSrcLen);
  528. memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
  529. GetData()->nDataLength = nSrcLen;
  530. m_pchData[nSrcLen] = '\0';
  531. }
  532. }
  533. void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
  534. int nExtraLen) const
  535. {
  536. // will clone the data attached to this string
  537. // allocating 'nExtraLen' characters
  538. // Places results in uninitialized string 'dest'
  539. // Will copy the part or all of original data to start of new string
  540. int nNewLen = nCopyLen + nExtraLen;
  541. if (nNewLen == 0)
  542. {
  543. dest.Init();
  544. }
  545. else
  546. {
  547. dest.AllocBuffer(nNewLen);
  548. memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));
  549. }
  550. }
  551. void CString::AllocBuffer(int nLen)
  552. // always allocate one extra character for '\0' termination
  553. // assumes [optimistically] that data length will equal allocation length
  554. {
  555. ASSERT(nLen >= 0);
  556. ASSERT(nLen <= INT_MAX-1); // max size (enough room for 1 extra)
  557. if (nLen == 0)
  558. Init();
  559. else
  560. {
  561. CStringData* pData;
  562. pData = (CStringData*)new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
  563. if (pData)
  564. {
  565. pData->nAllocLength = nLen;
  566. pData->nRefs = 1;
  567. pData->data()[nLen] = '\0';
  568. pData->nDataLength = nLen;
  569. m_pchData = pData->data();
  570. }
  571. }
  572. }
  573. void CString::CopyBeforeWrite()
  574. {
  575. if (GetData()->nRefs > 1)
  576. {
  577. CStringData* pData = GetData();
  578. Release();
  579. AllocBuffer(pData->nDataLength);
  580. memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR));
  581. }
  582. ASSERT(GetData()->nRefs <= 1);
  583. }
  584. void CString::AllocBeforeWrite(int nLen)
  585. {
  586. if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
  587. {
  588. Release();
  589. AllocBuffer(nLen);
  590. }
  591. ASSERT(GetData()->nRefs <= 1);
  592. }
  593. void PASCAL CString::Release(CStringData* pData)
  594. {
  595. if (pData != _afxDataNil)
  596. {
  597. ASSERT(pData->nRefs != 0);
  598. if (InterlockedDecrement(&pData->nRefs) <= 0)
  599. FreeData(pData);
  600. }
  601. }
  602. void CString::ReleaseBuffer(int nNewLength)
  603. {
  604. CopyBeforeWrite(); // just in case GetBuffer was not called
  605. if (nNewLength == -1)
  606. nNewLength = lstrlen(m_pchData); // zero terminated
  607. ASSERT(nNewLength <= GetData()->nAllocLength);
  608. GetData()->nDataLength = nNewLength;
  609. m_pchData[nNewLength] = '\0';
  610. }
  611. void FASTCALL CString::FreeData(CStringData* pData)
  612. {
  613. //#ifndef _DEBUG
  614. #ifdef TEST
  615. int nLen = pData->nAllocLength;
  616. if (nLen == 64)
  617. _afxAlloc64.Free(pData);
  618. else if (nLen == 128)
  619. _afxAlloc128.Free(pData);
  620. else if (nLen == 256)
  621. _afxAlloc256.Free(pData);
  622. else if (nLen == 512)
  623. _afxAlloc512.Free(pData);
  624. else
  625. {
  626. ASSERT(nLen > 512);
  627. delete[] (BYTE*)pData;
  628. }
  629. #else
  630. delete[] (BYTE*)pData;
  631. #endif
  632. }
  633. void CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
  634. int nSrc2Len, LPCTSTR lpszSrc2Data)
  635. {
  636. // -- master concatenation routine
  637. // Concatenate two sources
  638. // -- assume that 'this' is a new CString object
  639. int nNewLen = nSrc1Len + nSrc2Len;
  640. if (nNewLen != 0)
  641. {
  642. AllocBuffer(nNewLen);
  643. memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
  644. memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
  645. }
  646. }
  647. void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
  648. {
  649. // -- the main routine for += operators
  650. // concatenating an empty string is a no-op!
  651. if (nSrcLen == 0)
  652. return;
  653. // if the buffer is too small, or we have a width mis-match, just
  654. // allocate a new buffer (slow but sure)
  655. if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
  656. {
  657. // we have to grow the buffer, use the ConcatCopy routine
  658. CStringData* pOldData = GetData();
  659. ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
  660. ASSERT(pOldData != NULL);
  661. CString::Release(pOldData);
  662. }
  663. else
  664. {
  665. // fast concatenation when buffer big enough
  666. memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(TCHAR));
  667. GetData()->nDataLength += nSrcLen;
  668. ASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  669. m_pchData[GetData()->nDataLength] = '\0';
  670. }
  671. }
  672. const CString& CString::operator+=(LPCTSTR lpsz)
  673. {
  674. ASSERT(lpsz == NULL || AfxIsValidString(lpsz));
  675. ConcatInPlace(SafeStrlen(lpsz), lpsz);
  676. return *this;
  677. }
  678. const CString& CString::operator+=(TCHAR ch)
  679. {
  680. ConcatInPlace(1, &ch);
  681. return *this;
  682. }
  683. const CString& CString::operator+=(const CString& string)
  684. {
  685. ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
  686. return *this;
  687. }
  688. CString CString::Mid(int nFirst) const
  689. {
  690. return Mid(nFirst, GetData()->nDataLength - nFirst);
  691. }
  692. CString CString::Mid(int nFirst, int nCount) const
  693. {
  694. // out-of-bounds requests return sensible things
  695. if (nFirst < 0)
  696. nFirst = 0;
  697. if (nCount < 0)
  698. nCount = 0;
  699. if (nFirst + nCount > GetData()->nDataLength)
  700. nCount = GetData()->nDataLength - nFirst;
  701. if (nFirst > GetData()->nDataLength)
  702. nCount = 0;
  703. ASSERT(nFirst >= 0);
  704. ASSERT(nFirst + nCount <= GetData()->nDataLength);
  705. // optimize case of returning entire string
  706. if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
  707. return *this;
  708. CString dest;
  709. AllocCopy(dest, nCount, nFirst, 0);
  710. return dest;
  711. }
  712. //////////////////////////////////////////////////////////////////////////////
  713. // CWinThread
  714. CWinThread::CWinThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam)
  715. {
  716. m_pfnThreadProc = pfnThreadProc;
  717. m_pThreadParams = pParam;
  718. CommonConstruct();
  719. }
  720. CWinThread::CWinThread()
  721. {
  722. m_pThreadParams = NULL;
  723. m_pfnThreadProc = NULL;
  724. CommonConstruct();
  725. }
  726. void CWinThread::CommonConstruct()
  727. {
  728. // no HTHREAD until it is created
  729. m_hThread = NULL;
  730. m_nThreadID = 0;
  731. }
  732. CWinThread::~CWinThread()
  733. {
  734. // free thread object
  735. if (m_hThread != NULL)
  736. CloseHandle(m_hThread);
  737. //TODO:fix
  738. // cleanup module state
  739. // AFX_MODULE_THREAD_STATE* pState = AfxGetModuleThreadState();
  740. // if (pState->m_pCurrentWinThread == this)
  741. // pState->m_pCurrentWinThread = NULL;
  742. }
  743. CWinThread* AFXAPI AfxBeginThread(AFX_THREADPROC pfnThreadProc, LPVOID pParam,
  744. int nPriority, UINT nStackSize, DWORD dwCreateFlags,
  745. LPSECURITY_ATTRIBUTES lpSecurityAttrs)
  746. {
  747. ASSERT(pfnThreadProc != NULL);
  748. CWinThread* pThread = new CWinThread(pfnThreadProc, pParam);
  749. if (pThread)
  750. {
  751. if (!pThread->CreateThread(dwCreateFlags|CREATE_SUSPENDED, nStackSize, lpSecurityAttrs))
  752. {
  753. pThread->Delete();
  754. return NULL;
  755. }
  756. pThread->SetThreadPriority(nPriority);
  757. if (!(dwCreateFlags & CREATE_SUSPENDED))
  758. pThread->ResumeThread();
  759. }
  760. return pThread;
  761. }
  762. BOOL CWinThread::SetThreadPriority(int nPriority)
  763. { ASSERT(m_hThread != NULL); return ::SetThreadPriority(m_hThread, nPriority); }
  764. BOOL CWinThread::CreateThread(DWORD dwCreateFlags, UINT nStackSize,
  765. LPSECURITY_ATTRIBUTES lpSecurityAttrs)
  766. {
  767. ASSERT(m_hThread == NULL); // already created?
  768. m_hThread = ::CreateThread(lpSecurityAttrs, nStackSize, m_pfnThreadProc,
  769. m_pThreadParams, dwCreateFlags, &m_nThreadID);
  770. if (m_hThread == NULL)
  771. return FALSE;
  772. return TRUE;
  773. }
  774. DWORD CWinThread::ResumeThread()
  775. { ASSERT(m_hThread != NULL); return ::ResumeThread(m_hThread); }
  776. void CWinThread::Delete()
  777. {
  778. delete this;
  779. }
  780. /////////////////////////////////////////////////////////////////////////////
  781. // CWinThread default implementation
  782. BOOL CWinThread::InitInstance()
  783. {
  784. // ASSERT_VALID(this);
  785. return FALSE; // by default don't enter run loop
  786. }
  787. int CWinThread::ExitInstance()
  788. {
  789. // ASSERT_VALID(this);
  790. // ASSERT(AfxGetApp() != this);
  791. // int nResult = m_msgCur.wParam; // returns the value from PostQuitMessage
  792. return 0;
  793. }
  794. //////////////////////////////////////////////////////////////////////////////
  795. // CStringArray
  796. static inline void ConstructElement(CString* pNewData)
  797. {
  798. memcpy(pNewData, &afxEmptyString, sizeof(CString));
  799. }
  800. static inline void DestructElement(CString* pOldData)
  801. {
  802. pOldData->~CString();
  803. }
  804. static inline void CopyElement(CString* pSrc, CString* pDest)
  805. {
  806. *pSrc = *pDest;
  807. }
  808. static void ConstructElements(CString* pNewData, int nCount)
  809. {
  810. ASSERT(nCount >= 0);
  811. while (nCount--)
  812. {
  813. ConstructElement(pNewData);
  814. pNewData++;
  815. }
  816. }
  817. static void DestructElements(CString* pOldData, int nCount)
  818. {
  819. ASSERT(nCount >= 0);
  820. while (nCount--)
  821. {
  822. DestructElement(pOldData);
  823. pOldData++;
  824. }
  825. }
  826. static void CopyElements(CString* pDest, CString* pSrc, int nCount)
  827. {
  828. ASSERT(nCount >= 0);
  829. while (nCount--)
  830. {
  831. *pDest = *pSrc;
  832. ++pDest;
  833. ++pSrc;
  834. }
  835. }
  836. /////////////////////////////////////////////////////////////////////////////
  837. CStringArray::CStringArray()
  838. {
  839. m_pData = NULL;
  840. m_nSize = m_nMaxSize = m_nGrowBy = 0;
  841. }
  842. CStringArray::~CStringArray()
  843. {
  844. // ASSERT_VALID(this);
  845. DestructElements(m_pData, m_nSize);
  846. delete[] (BYTE*)m_pData;
  847. }
  848. void CStringArray::SetSize(int nNewSize, int nGrowBy)
  849. {
  850. // ASSERT_VALID(this);
  851. ASSERT(nNewSize >= 0);
  852. if (nGrowBy != -1)
  853. m_nGrowBy = nGrowBy; // set new size
  854. if (nNewSize == 0)
  855. {
  856. // shrink to nothing
  857. DestructElements(m_pData, m_nSize);
  858. delete[] (BYTE*)m_pData;
  859. m_pData = NULL;
  860. m_nSize = m_nMaxSize = 0;
  861. }
  862. else if (m_pData == NULL)
  863. {
  864. // create one with exact size
  865. #ifdef SIZE_T_MAX
  866. ASSERT(nNewSize <= SIZE_T_MAX/sizeof(CString)); // no overflow
  867. #endif
  868. m_pData = (CString*) new BYTE[nNewSize * sizeof(CString)];
  869. if (m_pData)
  870. {
  871. ConstructElements(m_pData, nNewSize);
  872. m_nSize = m_nMaxSize = nNewSize;
  873. }
  874. }
  875. else if (nNewSize <= m_nMaxSize)
  876. {
  877. // it fits
  878. if (nNewSize > m_nSize)
  879. {
  880. // initialize the new elements
  881. ConstructElements(&m_pData[m_nSize], nNewSize-m_nSize);
  882. }
  883. else if (m_nSize > nNewSize) // destroy the old elements
  884. DestructElements(&m_pData[nNewSize], m_nSize-nNewSize);
  885. m_nSize = nNewSize;
  886. }
  887. else
  888. {
  889. // otherwise, grow array
  890. int nGrowBy = m_nGrowBy;
  891. if (nGrowBy == 0)
  892. {
  893. // heuristically determine growth when nGrowBy == 0
  894. // (this avoids heap fragmentation in many situations)
  895. nGrowBy = min(1024, max(4, m_nSize / 8));
  896. }
  897. int nNewMax;
  898. if (nNewSize < m_nMaxSize + nGrowBy)
  899. nNewMax = m_nMaxSize + nGrowBy; // granularity
  900. else
  901. nNewMax = nNewSize; // no slush
  902. ASSERT(nNewMax >= m_nMaxSize); // no wrap around
  903. #ifdef SIZE_T_MAX
  904. ASSERT(nNewMax <= SIZE_T_MAX/sizeof(CString)); // no overflow
  905. #endif
  906. CString* pNewData = (CString*) new BYTE[nNewMax * sizeof(CString)];
  907. if (pNewData)
  908. {
  909. // copy new data from old
  910. memcpy(pNewData, m_pData, m_nSize * sizeof(CString));
  911. // construct remaining elements
  912. ASSERT(nNewSize > m_nSize);
  913. ConstructElements(&pNewData[m_nSize], nNewSize-m_nSize);
  914. // get rid of old stuff (note: no destructors called)
  915. delete[] (BYTE*)m_pData;
  916. m_pData = pNewData;
  917. m_nSize = nNewSize;
  918. m_nMaxSize = nNewMax;
  919. }
  920. }
  921. }
  922. int CStringArray::Append(const CStringArray& src)
  923. {
  924. // ASSERT_VALID(this);
  925. ASSERT(this != &src); // cannot append to itself
  926. int nOldSize = m_nSize;
  927. SetSize(m_nSize + src.m_nSize);
  928. CopyElements(m_pData + nOldSize, src.m_pData, src.m_nSize);
  929. return nOldSize;
  930. }
  931. void CStringArray::Copy(const CStringArray& src)
  932. {
  933. // ASSERT_VALID(this);
  934. ASSERT(this != &src); // cannot append to itself
  935. SetSize(src.m_nSize);
  936. CopyElements(m_pData, src.m_pData, src.m_nSize);
  937. }
  938. void CStringArray::FreeExtra()
  939. {
  940. // ASSERT_VALID(this);
  941. if (m_nSize != m_nMaxSize)
  942. {
  943. // shrink to desired size
  944. #ifdef SIZE_T_MAX
  945. ASSERT(m_nSize <= SIZE_T_MAX/sizeof(CString)); // no overflow
  946. #endif
  947. CString* pNewData = NULL;
  948. if (m_nSize != 0)
  949. {
  950. pNewData = (CString*) new BYTE[m_nSize * sizeof(CString)];
  951. if (pNewData)
  952. {
  953. // copy new data from old
  954. memcpy(pNewData, m_pData, m_nSize * sizeof(CString));
  955. }
  956. }
  957. // get rid of old stuff (note: no destructors called)
  958. delete[] (BYTE*)m_pData;
  959. m_pData = pNewData;
  960. m_nMaxSize = m_nSize;
  961. }
  962. }
  963. void CStringArray::SetAtGrow(int nIndex, LPCTSTR newElement)
  964. {
  965. // ASSERT_VALID(this);
  966. ASSERT(nIndex >= 0);
  967. if (nIndex >= m_nSize)
  968. SetSize(nIndex+1);
  969. m_pData[nIndex] = newElement;
  970. }
  971. void CStringArray::SetAtGrow(int nIndex, const CString& newElement)
  972. {
  973. // ASSERT_VALID(this);
  974. ASSERT(nIndex >= 0);
  975. if (nIndex >= m_nSize)
  976. SetSize(nIndex+1);
  977. m_pData[nIndex] = newElement;
  978. }
  979. void CStringArray::InsertEmpty(int nIndex, int nCount)
  980. {
  981. // ASSERT_VALID(this);
  982. ASSERT(nIndex >= 0); // will expand to meet need
  983. ASSERT(nCount > 0); // zero or negative size not allowed
  984. if (nIndex >= m_nSize)
  985. {
  986. // adding after the end of the array
  987. SetSize(nIndex + nCount); // grow so nIndex is valid
  988. }
  989. else
  990. {
  991. // inserting in the middle of the array
  992. int nOldSize = m_nSize;
  993. SetSize(m_nSize + nCount); // grow it to new size
  994. // shift old data up to fill gap
  995. memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
  996. (nOldSize-nIndex) * sizeof(CString));
  997. // re-init slots we copied from
  998. ConstructElements(&m_pData[nIndex], nCount);
  999. }
  1000. // insert new value in the gap
  1001. ASSERT(nIndex + nCount <= m_nSize);
  1002. }
  1003. void CStringArray::InsertAt(int nIndex, LPCTSTR newElement, int nCount)
  1004. {
  1005. // make room for new elements
  1006. InsertEmpty(nIndex, nCount);
  1007. // copy elements into the empty space
  1008. CString temp = newElement;
  1009. while (nCount--)
  1010. m_pData[nIndex++] = temp;
  1011. }
  1012. void CStringArray::InsertAt(int nIndex, const CString& newElement, int nCount)
  1013. {
  1014. // make room for new elements
  1015. InsertEmpty(nIndex, nCount);
  1016. // copy elements into the empty space
  1017. while (nCount--)
  1018. m_pData[nIndex++] = newElement;
  1019. }
  1020. void CStringArray::RemoveAt(int nIndex, int nCount)
  1021. {
  1022. // ASSERT_VALID(this);
  1023. ASSERT(nIndex >= 0);
  1024. ASSERT(nCount >= 0);
  1025. ASSERT(nIndex + nCount <= m_nSize);
  1026. // just remove a range
  1027. int nMoveCount = m_nSize - (nIndex + nCount);
  1028. DestructElements(&m_pData[nIndex], nCount);
  1029. if (nMoveCount)
  1030. memmove(&m_pData[nIndex], &m_pData[nIndex + nCount],
  1031. nMoveCount * sizeof(CString));
  1032. m_nSize -= nCount;
  1033. }
  1034. void CStringArray::InsertAt(int nStartIndex, CStringArray* pNewArray)
  1035. {
  1036. // ASSERT_VALID(this);
  1037. ASSERT(pNewArray != NULL);
  1038. // ASSERT_KINDOF(CStringArray, pNewArray);
  1039. // ASSERT_VALID(pNewArray);
  1040. ASSERT(nStartIndex >= 0);
  1041. if (pNewArray->GetSize() > 0)
  1042. {
  1043. InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
  1044. for (int i = 0; i < pNewArray->GetSize(); i++)
  1045. SetAt(nStartIndex + i, pNewArray->GetAt(i));
  1046. }
  1047. }
  1048. //////////////////////////////////////////////////////////////////////////////
  1049. // CPtrArray
  1050. /////////////////////////////////////////////////////////////////////////////
  1051. CPtrArray::CPtrArray()
  1052. {
  1053. m_pData = NULL;
  1054. m_nSize = m_nMaxSize = m_nGrowBy = 0;
  1055. }
  1056. CPtrArray::~CPtrArray()
  1057. {
  1058. // ASSERT_VALID(this);
  1059. delete[] (BYTE*)m_pData;
  1060. }
  1061. void CPtrArray::SetSize(int nNewSize, int nGrowBy)
  1062. {
  1063. // ASSERT_VALID(this);
  1064. ASSERT(nNewSize >= 0);
  1065. if (nGrowBy != -1)
  1066. m_nGrowBy = nGrowBy; // set new size
  1067. if (nNewSize == 0)
  1068. {
  1069. // shrink to nothing
  1070. delete[] (BYTE*)m_pData;
  1071. m_pData = NULL;
  1072. m_nSize = m_nMaxSize = 0;
  1073. }
  1074. else if (m_pData == NULL)
  1075. {
  1076. // create one with exact size
  1077. #ifdef SIZE_T_MAX
  1078. ASSERT(nNewSize <= SIZE_T_MAX/sizeof(void*)); // no overflow
  1079. #endif
  1080. m_pData = (void**) new BYTE[nNewSize * sizeof(void*)];
  1081. if (m_pData)
  1082. {
  1083. memset(m_pData, 0, nNewSize * sizeof(void*)); // zero fill
  1084. m_nSize = m_nMaxSize = nNewSize;
  1085. }
  1086. }
  1087. else if (nNewSize <= m_nMaxSize)
  1088. {
  1089. // it fits
  1090. if (nNewSize > m_nSize)
  1091. {
  1092. // initialize the new elements
  1093. memset(&m_pData[m_nSize], 0, (nNewSize-m_nSize) * sizeof(void*));
  1094. }
  1095. m_nSize = nNewSize;
  1096. }
  1097. else
  1098. {
  1099. // otherwise, grow array
  1100. int nGrowBy = m_nGrowBy;
  1101. if (nGrowBy == 0)
  1102. {
  1103. // heuristically determine growth when nGrowBy == 0
  1104. // (this avoids heap fragmentation in many situations)
  1105. nGrowBy = min(1024, max(4, m_nSize / 8));
  1106. }
  1107. int nNewMax;
  1108. if (nNewSize < m_nMaxSize + nGrowBy)
  1109. nNewMax = m_nMaxSize + nGrowBy; // granularity
  1110. else
  1111. nNewMax = nNewSize; // no slush
  1112. ASSERT(nNewMax >= m_nMaxSize); // no wrap around
  1113. #ifdef SIZE_T_MAX
  1114. ASSERT(nNewMax <= SIZE_T_MAX/sizeof(void*)); // no overflow
  1115. #endif
  1116. void** pNewData = (void**) new BYTE[nNewMax * sizeof(void*)];
  1117. if (pNewData)
  1118. {
  1119. // copy new data from old
  1120. memcpy(pNewData, m_pData, m_nSize * sizeof(void*));
  1121. // construct remaining elements
  1122. ASSERT(nNewSize > m_nSize);
  1123. memset(&pNewData[m_nSize], 0, (nNewSize-m_nSize) * sizeof(void*));
  1124. // get rid of old stuff (note: no destructors called)
  1125. delete[] (BYTE*)m_pData;
  1126. m_pData = pNewData;
  1127. m_nSize = nNewSize;
  1128. m_nMaxSize = nNewMax;
  1129. }
  1130. }
  1131. }
  1132. int CPtrArray::Append(const CPtrArray& src)
  1133. {
  1134. // ASSERT_VALID(this);
  1135. ASSERT(this != &src); // cannot append to itself
  1136. int nOldSize = m_nSize;
  1137. SetSize(m_nSize + src.m_nSize);
  1138. memcpy(m_pData + nOldSize, src.m_pData, src.m_nSize * sizeof(void*));
  1139. return nOldSize;
  1140. }
  1141. void CPtrArray::Copy(const CPtrArray& src)
  1142. {
  1143. // ASSERT_VALID(this);
  1144. ASSERT(this != &src); // cannot append to itself
  1145. SetSize(src.m_nSize);
  1146. memcpy(m_pData, src.m_pData, src.m_nSize * sizeof(void*));
  1147. }
  1148. void CPtrArray::FreeExtra()
  1149. {
  1150. // ASSERT_VALID(this);
  1151. if (m_nSize != m_nMaxSize)
  1152. {
  1153. // shrink to desired size
  1154. #ifdef SIZE_T_MAX
  1155. ASSERT(m_nSize <= SIZE_T_MAX/sizeof(void*)); // no overflow
  1156. #endif
  1157. void** pNewData = NULL;
  1158. if (m_nSize != 0)
  1159. {
  1160. pNewData = (void**) new BYTE[m_nSize * sizeof(void*)];
  1161. if (pNewData)
  1162. {
  1163. // copy new data from old
  1164. memcpy(pNewData, m_pData, m_nSize * sizeof(void*));
  1165. }
  1166. }
  1167. // get rid of old stuff (note: no destructors called)
  1168. delete[] (BYTE*)m_pData;
  1169. m_pData = pNewData;
  1170. m_nMaxSize = m_nSize;
  1171. }
  1172. }
  1173. /////////////////////////////////////////////////////////////////////////////
  1174. void CPtrArray::SetAtGrow(int nIndex, void* newElement)
  1175. {
  1176. // ASSERT_VALID(this);
  1177. ASSERT(nIndex >= 0);
  1178. if (nIndex >= m_nSize)
  1179. SetSize(nIndex+1);
  1180. m_pData[nIndex] = newElement;
  1181. }
  1182. void CPtrArray::InsertAt(int nIndex, void* newElement, int nCount)
  1183. {
  1184. // ASSERT_VALID(this);
  1185. ASSERT(nIndex >= 0); // will expand to meet need
  1186. ASSERT(nCount > 0); // zero or negative size not allowed
  1187. if (nIndex >= m_nSize)
  1188. {
  1189. // adding after the end of the array
  1190. SetSize(nIndex + nCount); // grow so nIndex is valid
  1191. }
  1192. else
  1193. {
  1194. // inserting in the middle of the array
  1195. int nOldSize = m_nSize;
  1196. SetSize(m_nSize + nCount); // grow it to new size
  1197. // shift old data up to fill gap
  1198. memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
  1199. (nOldSize-nIndex) * sizeof(void*));
  1200. // re-init slots we copied from
  1201. memset(&m_pData[nIndex], 0, nCount * sizeof(void*));
  1202. }
  1203. // insert new value in the gap
  1204. ASSERT(nIndex + nCount <= m_nSize);
  1205. // copy elements into the empty space
  1206. while (nCount--)
  1207. m_pData[nIndex++] = newElement;
  1208. }
  1209. void CPtrArray::RemoveAt(int nIndex, int nCount)
  1210. {
  1211. // ASSERT_VALID(this);
  1212. ASSERT(nIndex >= 0);
  1213. ASSERT(nCount >= 0);
  1214. ASSERT(nIndex + nCount <= m_nSize);
  1215. // just remove a range
  1216. int nMoveCount = m_nSize - (nIndex + nCount);
  1217. if (nMoveCount)
  1218. memmove(&m_pData[nIndex], &m_pData[nIndex + nCount],
  1219. nMoveCount * sizeof(void*));
  1220. m_nSize -= nCount;
  1221. }
  1222. void CPtrArray::InsertAt(int nStartIndex, CPtrArray* pNewArray)
  1223. {
  1224. // ASSERT_VALID(this);
  1225. ASSERT(pNewArray != NULL);
  1226. // ASSERT_KINDOF(CPtrArray, pNewArray);
  1227. // ASSERT_VALID(pNewArray);
  1228. ASSERT(nStartIndex >= 0);
  1229. if (pNewArray->GetSize() > 0)
  1230. {
  1231. InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
  1232. for (int i = 0; i < pNewArray->GetSize(); i++)
  1233. SetAt(nStartIndex + i, pNewArray->GetAt(i));
  1234. }
  1235. }
  1236. /////////////////////////////////////////////////////////////////////////////