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.

631 lines
19 KiB

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1995 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. #include <urlint.h>
  11. #include <map_kv.h>
  12. #include "coll.hxx"
  13. /*
  14. #include "stdafx.h"
  15. #ifdef AFX_CORE1_SEG
  16. #pragma code_seg(AFX_CORE1_SEG)
  17. #endif
  18. #ifdef _DEBUG
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22. #define new DEBUG_NEW
  23. */
  24. // The following macros are used on data declarations/definitions
  25. // (they are redefined for extension DLLs and the shared MFC DLL)
  26. #define AFX_DATA
  27. #define AFX_DATADEF
  28. // used when building the "core" MFC42.DLL
  29. #ifndef AFX_CORE_DATA
  30. #define AFX_CORE_DATA
  31. #define AFX_CORE_DATADEF
  32. #endif
  33. // used when building the MFC/OLE support MFCO42.DLL
  34. #ifndef AFX_OLE_DATA
  35. #define AFX_OLE_DATA
  36. #define AFX_OLE_DATADEF
  37. #endif
  38. #define TRACE1(x,a)
  39. //int AFX_CDECL _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count);
  40. // conversion helpers
  41. int AFX_CDECL _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count);
  42. int AFX_CDECL _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count);
  43. /////////////////////////////////////////////////////////////////////////////
  44. // static class data, special inlines
  45. // afxChNil is left for backward compatibility
  46. AFX_DATADEF TCHAR afxChNil = '\0';
  47. // For an empty string, m_pchData will point here
  48. // (note: avoids special case of checking for NULL m_pchData)
  49. // empty string data (and locked)
  50. static int rgInitData[] = { -1, 0, 0, 0 };
  51. static AFX_DATADEF CStringData* afxDataNil = (CStringData*)&rgInitData;
  52. static LPCTSTR afxPchNil = (LPCTSTR)(((BYTE*)&rgInitData)+sizeof(CStringData));
  53. // special function to make afxEmptyString work even during initialization
  54. const CString& AFXAPI AfxGetEmptyString()
  55. { return *(CString*)&afxPchNil; }
  56. //////////////////////////////////////////////////////////////////////////////
  57. // Construction/Destruction
  58. CString::CString()
  59. {
  60. Init();
  61. }
  62. CString::CString(const CString& stringSrc)
  63. {
  64. ASSERT(stringSrc.GetData()->nRefs != 0);
  65. if (stringSrc.GetData()->nRefs >= 0)
  66. {
  67. ASSERT(stringSrc.GetData() != afxDataNil);
  68. m_pchData = stringSrc.m_pchData;
  69. InterlockedIncrement(&GetData()->nRefs);
  70. }
  71. else
  72. {
  73. Init();
  74. *this = stringSrc.m_pchData;
  75. }
  76. }
  77. void CString::AllocBuffer(int nLen)
  78. // always allocate one extra character for '\0' termination
  79. // assumes [optimistically] that data length will equal allocation length
  80. {
  81. ASSERT(nLen >= 0);
  82. ASSERT(nLen <= INT_MAX-1); // max size (enough room for 1 extra)
  83. if (nLen == 0)
  84. Init();
  85. else
  86. {
  87. CStringData* pData =
  88. (CStringData*)new BYTE[sizeof(CStringData) + (nLen+1)*sizeof(TCHAR)];
  89. pData->nRefs = 1;
  90. pData->data()[nLen] = '\0';
  91. pData->nDataLength = nLen;
  92. pData->nAllocLength = nLen;
  93. m_pchData = pData->data();
  94. }
  95. }
  96. void CString::Release()
  97. {
  98. if (GetData() != afxDataNil)
  99. {
  100. ASSERT(GetData()->nRefs != 0);
  101. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  102. delete[] (BYTE*)GetData();
  103. Init();
  104. }
  105. }
  106. void PASCAL CString::Release(CStringData* pData)
  107. {
  108. if (pData != afxDataNil)
  109. {
  110. ASSERT(pData->nRefs != 0);
  111. if (InterlockedDecrement(&pData->nRefs) <= 0)
  112. delete[] (BYTE*)pData;
  113. }
  114. }
  115. void CString::Empty()
  116. {
  117. if (GetData()->nDataLength == 0)
  118. return;
  119. if (GetData()->nRefs >= 0)
  120. Release();
  121. else
  122. *this = &afxChNil;
  123. ASSERT(GetData()->nDataLength == 0);
  124. ASSERT(GetData()->nRefs < 0 || GetData()->nAllocLength == 0);
  125. }
  126. void CString::CopyBeforeWrite()
  127. {
  128. if (GetData()->nRefs > 1)
  129. {
  130. CStringData* pData = GetData();
  131. Release();
  132. AllocBuffer(pData->nDataLength);
  133. memcpy(m_pchData, pData->data(), (pData->nDataLength+1)*sizeof(TCHAR));
  134. }
  135. ASSERT(GetData()->nRefs <= 1);
  136. }
  137. void CString::AllocBeforeWrite(int nLen)
  138. {
  139. if (GetData()->nRefs > 1 || nLen > GetData()->nAllocLength)
  140. {
  141. Release();
  142. AllocBuffer(nLen);
  143. }
  144. ASSERT(GetData()->nRefs <= 1);
  145. }
  146. CString::~CString()
  147. // free any attached data
  148. {
  149. if (GetData() != afxDataNil)
  150. {
  151. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  152. delete[] (BYTE*)GetData();
  153. }
  154. }
  155. //////////////////////////////////////////////////////////////////////////////
  156. // Helpers for the rest of the implementation
  157. void CString::AllocCopy(CString& dest, int nCopyLen, int nCopyIndex,
  158. int nExtraLen) const
  159. {
  160. // will clone the data attached to this string
  161. // allocating 'nExtraLen' characters
  162. // Places results in uninitialized string 'dest'
  163. // Will copy the part or all of original data to start of new string
  164. int nNewLen = nCopyLen + nExtraLen;
  165. if (nNewLen == 0)
  166. {
  167. dest.Init();
  168. }
  169. else
  170. {
  171. dest.AllocBuffer(nNewLen);
  172. memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));
  173. }
  174. }
  175. //////////////////////////////////////////////////////////////////////////////
  176. // More sophisticated construction
  177. CString::CString(LPCTSTR lpsz)
  178. {
  179. Init();
  180. if (lpsz != NULL && (DWORD_PTR)lpsz <= 0xFFFF)
  181. {
  182. UINT nID = PtrToUlong(lpsz) & 0xFFFF;
  183. //if (!LoadString(nID))
  184. // TRACE1("Warning: implicit LoadString(%u) failed\n", nID);
  185. }
  186. else
  187. {
  188. int nLen = SafeStrlen(lpsz);
  189. if (nLen != 0)
  190. {
  191. AllocBuffer(nLen);
  192. memcpy(m_pchData, lpsz, nLen*sizeof(TCHAR));
  193. }
  194. }
  195. }
  196. /////////////////////////////////////////////////////////////////////////////
  197. // Special conversion constructors
  198. #ifdef _UNICODE
  199. CString::CString(LPCSTR lpsz)
  200. {
  201. Init();
  202. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  203. if (nSrcLen != 0)
  204. {
  205. AllocBuffer(nSrcLen);
  206. _mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  207. ReleaseBuffer();
  208. }
  209. }
  210. #else //_UNICODE
  211. CString::CString(LPCWSTR lpsz)
  212. {
  213. Init();
  214. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  215. if (nSrcLen != 0)
  216. {
  217. AllocBuffer(nSrcLen*2);
  218. _wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  219. ReleaseBuffer();
  220. }
  221. }
  222. #endif //!_UNICODE
  223. //////////////////////////////////////////////////////////////////////////////
  224. // Diagnostic support
  225. #ifdef _DEBUG
  226. CDumpContext& AFXAPI operator<<(CDumpContext& dc, const CString& string)
  227. {
  228. dc << string.m_pchData;
  229. return dc;
  230. }
  231. #endif //_DEBUG
  232. //////////////////////////////////////////////////////////////////////////////
  233. // Assignment operators
  234. // All assign a new value to the string
  235. // (a) first see if the buffer is big enough
  236. // (b) if enough room, copy on top of old buffer, set size and type
  237. // (c) otherwise free old string data, and create a new one
  238. //
  239. // All routines return the new string (but as a 'const CString&' so that
  240. // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  241. //
  242. void CString::AssignCopy(int nSrcLen, LPCTSTR lpszSrcData)
  243. {
  244. AllocBeforeWrite(nSrcLen);
  245. memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
  246. GetData()->nDataLength = nSrcLen;
  247. m_pchData[nSrcLen] = '\0';
  248. }
  249. const CString& CString::operator=(const CString& stringSrc)
  250. {
  251. if (m_pchData != stringSrc.m_pchData)
  252. {
  253. if ((GetData()->nRefs < 0 && GetData() != afxDataNil) ||
  254. stringSrc.GetData()->nRefs < 0)
  255. {
  256. // actual copy necessary since one of the strings is locked
  257. AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  258. }
  259. else
  260. {
  261. // can just copy references around
  262. Release();
  263. ASSERT(stringSrc.GetData() != afxDataNil);
  264. m_pchData = stringSrc.m_pchData;
  265. InterlockedIncrement(&GetData()->nRefs);
  266. }
  267. }
  268. return *this;
  269. }
  270. const CString& CString::operator=(LPCTSTR lpsz)
  271. {
  272. ASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  273. AssignCopy(SafeStrlen(lpsz), lpsz);
  274. return *this;
  275. }
  276. /////////////////////////////////////////////////////////////////////////////
  277. // Special conversion assignment
  278. #ifdef _UNICODE
  279. const CString& CString::operator=(LPCSTR lpsz)
  280. {
  281. int nSrcLen = lpsz != NULL ? lstrlenA(lpsz) : 0;
  282. AllocBeforeWrite(nSrcLen);
  283. _mbstowcsz(m_pchData, lpsz, nSrcLen+1);
  284. ReleaseBuffer();
  285. return *this;
  286. }
  287. #else //!_UNICODE
  288. const CString& CString::operator=(LPCWSTR lpsz)
  289. {
  290. int nSrcLen = lpsz != NULL ? wcslen(lpsz) : 0;
  291. AllocBeforeWrite(nSrcLen*2);
  292. _wcstombsz(m_pchData, lpsz, (nSrcLen*2)+1);
  293. ReleaseBuffer();
  294. return *this;
  295. }
  296. #endif //!_UNICODE
  297. //////////////////////////////////////////////////////////////////////////////
  298. // concatenation
  299. // NOTE: "operator+" is done as friend functions for simplicity
  300. // There are three variants:
  301. // CString + CString
  302. // and for ? = TCHAR, LPCTSTR
  303. // CString + ?
  304. // ? + CString
  305. void CString::ConcatCopy(int nSrc1Len, LPCTSTR lpszSrc1Data,
  306. int nSrc2Len, LPCTSTR lpszSrc2Data)
  307. {
  308. // -- master concatenation routine
  309. // Concatenate two sources
  310. // -- assume that 'this' is a new CString object
  311. int nNewLen = nSrc1Len + nSrc2Len;
  312. if (nNewLen != 0)
  313. {
  314. AllocBuffer(nNewLen);
  315. memcpy(m_pchData, lpszSrc1Data, nSrc1Len*sizeof(TCHAR));
  316. memcpy(m_pchData+nSrc1Len, lpszSrc2Data, nSrc2Len*sizeof(TCHAR));
  317. }
  318. }
  319. CString AFXAPI operator+(const CString& string1, const CString& string2)
  320. {
  321. CString s;
  322. s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,
  323. string2.GetData()->nDataLength, string2.m_pchData);
  324. return s;
  325. }
  326. CString AFXAPI operator+(const CString& string, LPCTSTR lpsz)
  327. {
  328. ASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  329. CString s;
  330. s.ConcatCopy(string.GetData()->nDataLength, string.m_pchData,
  331. CString::SafeStrlen(lpsz), lpsz);
  332. return s;
  333. }
  334. CString AFXAPI operator+(LPCTSTR lpsz, const CString& string)
  335. {
  336. ASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  337. CString s;
  338. s.ConcatCopy(CString::SafeStrlen(lpsz), lpsz, string.GetData()->nDataLength,
  339. string.m_pchData);
  340. return s;
  341. }
  342. //////////////////////////////////////////////////////////////////////////////
  343. // concatenate in place
  344. void CString::ConcatInPlace(int nSrcLen, LPCTSTR lpszSrcData)
  345. {
  346. // -- the main routine for += operators
  347. // concatenating an empty string is a no-op!
  348. if (nSrcLen == 0)
  349. return;
  350. // if the buffer is too small, or we have a width mis-match, just
  351. // allocate a new buffer (slow but sure)
  352. if (GetData()->nRefs > 1 || GetData()->nDataLength + nSrcLen > GetData()->nAllocLength)
  353. {
  354. // we have to grow the buffer, use the ConcatCopy routine
  355. CStringData* pOldData = GetData();
  356. ConcatCopy(GetData()->nDataLength, m_pchData, nSrcLen, lpszSrcData);
  357. ASSERT(pOldData != NULL);
  358. CString::Release(pOldData);
  359. }
  360. else
  361. {
  362. // fast concatenation when buffer big enough
  363. memcpy(m_pchData+GetData()->nDataLength, lpszSrcData, nSrcLen*sizeof(TCHAR));
  364. GetData()->nDataLength += nSrcLen;
  365. ASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  366. m_pchData[GetData()->nDataLength] = '\0';
  367. }
  368. }
  369. const CString& CString::operator+=(LPCTSTR lpsz)
  370. {
  371. ASSERT(lpsz == NULL || AfxIsValidString(lpsz, FALSE));
  372. ConcatInPlace(SafeStrlen(lpsz), lpsz);
  373. return *this;
  374. }
  375. const CString& CString::operator+=(TCHAR ch)
  376. {
  377. ConcatInPlace(1, &ch);
  378. return *this;
  379. }
  380. const CString& CString::operator+=(const CString& string)
  381. {
  382. ConcatInPlace(string.GetData()->nDataLength, string.m_pchData);
  383. return *this;
  384. }
  385. ///////////////////////////////////////////////////////////////////////////////
  386. // Advanced direct buffer access
  387. LPTSTR CString::GetBuffer(int nMinBufLength)
  388. {
  389. ASSERT(nMinBufLength >= 0);
  390. if (GetData()->nRefs > 1 || nMinBufLength > GetData()->nAllocLength)
  391. {
  392. // we have to grow the buffer
  393. CStringData* pOldData = GetData();
  394. int nOldLen = GetData()->nDataLength; // AllocBuffer will tromp it
  395. if (nMinBufLength < nOldLen)
  396. nMinBufLength = nOldLen;
  397. AllocBuffer(nMinBufLength);
  398. memcpy(m_pchData, pOldData->data(), (nOldLen+1)*sizeof(TCHAR));
  399. GetData()->nDataLength = nOldLen;
  400. CString::Release(pOldData);
  401. }
  402. ASSERT(GetData()->nRefs <= 1);
  403. // return a pointer to the character storage for this string
  404. ASSERT(m_pchData != NULL);
  405. return m_pchData;
  406. }
  407. void CString::ReleaseBuffer(int nNewLength)
  408. {
  409. CopyBeforeWrite(); // just in case GetBuffer was not called
  410. if (nNewLength == -1)
  411. nNewLength = lstrlen(m_pchData); // zero terminated
  412. ASSERT(nNewLength <= GetData()->nAllocLength);
  413. GetData()->nDataLength = nNewLength;
  414. m_pchData[nNewLength] = '\0';
  415. }
  416. LPTSTR CString::GetBufferSetLength(int nNewLength)
  417. {
  418. ASSERT(nNewLength >= 0);
  419. GetBuffer(nNewLength);
  420. GetData()->nDataLength = nNewLength;
  421. m_pchData[nNewLength] = '\0';
  422. return m_pchData;
  423. }
  424. void CString::FreeExtra()
  425. {
  426. ASSERT(GetData()->nDataLength <= GetData()->nAllocLength);
  427. if (GetData()->nDataLength != GetData()->nAllocLength)
  428. {
  429. CStringData* pOldData = GetData();
  430. AllocBuffer(GetData()->nDataLength);
  431. memcpy(m_pchData, pOldData->data(), pOldData->nDataLength*sizeof(TCHAR));
  432. ASSERT(m_pchData[GetData()->nDataLength] == '\0');
  433. CString::Release(pOldData);
  434. }
  435. ASSERT(GetData() != NULL);
  436. }
  437. LPTSTR CString::LockBuffer()
  438. {
  439. LPTSTR lpsz = GetBuffer(0);
  440. GetData()->nRefs = -1;
  441. return lpsz;
  442. }
  443. void CString::UnlockBuffer()
  444. {
  445. ASSERT(GetData()->nRefs == -1);
  446. if (GetData() != afxDataNil)
  447. GetData()->nRefs = 1;
  448. }
  449. ///////////////////////////////////////////////////////////////////////////////
  450. // Commonly used routines (rarely used routines in STREX.CPP)
  451. #ifdef unused
  452. int CString::Find(TCHAR ch) const
  453. {
  454. // find first single character
  455. LPTSTR lpsz = _tcschr(m_pchData, (_TUCHAR)ch);
  456. // return -1 if not found and index otherwise
  457. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  458. }
  459. int CString::FindOneOf(LPCTSTR lpszCharSet) const
  460. {
  461. ASSERT(AfxIsValidString(lpszCharSet, FALSE));
  462. LPTSTR lpsz = _tcspbrk(m_pchData, lpszCharSet);
  463. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  464. }
  465. void CString::MakeReverse()
  466. {
  467. CopyBeforeWrite();
  468. _tcsrev(m_pchData);
  469. }
  470. #endif //unused
  471. void CString::MakeUpper()
  472. {
  473. CopyBeforeWrite();
  474. ::CharUpper(m_pchData);
  475. }
  476. void CString::MakeLower()
  477. {
  478. CopyBeforeWrite();
  479. ::CharLower(m_pchData);
  480. }
  481. void CString::SetAt(int nIndex, TCHAR ch)
  482. {
  483. ASSERT(nIndex >= 0);
  484. ASSERT(nIndex < GetData()->nDataLength);
  485. CopyBeforeWrite();
  486. m_pchData[nIndex] = ch;
  487. }
  488. #ifndef _UNICODE
  489. void CString::AnsiToOem()
  490. {
  491. CopyBeforeWrite();
  492. ::AnsiToOem(m_pchData, m_pchData);
  493. }
  494. void CString::OemToAnsi()
  495. {
  496. CopyBeforeWrite();
  497. #pragma prefast(suppress:56, "We don't hit this piece of code in the current codebase")
  498. ::OemToAnsi(m_pchData, m_pchData);
  499. }
  500. #endif
  501. ///////////////////////////////////////////////////////////////////////////////
  502. // CString conversion helpers (these use the current system locale)
  503. int AFX_CDECL _wcstombsz(char* mbstr, const wchar_t* wcstr, size_t count)
  504. {
  505. if (count == 0 && mbstr != NULL)
  506. return 0;
  507. int result = ::WideCharToMultiByte(CP_ACP, 0, wcstr, -1,
  508. mbstr, count, NULL, NULL);
  509. ASSERT(mbstr == NULL || result <= (int)count);
  510. if (result > 0)
  511. mbstr[result-1] = 0;
  512. return result;
  513. }
  514. int AFX_CDECL _mbstowcsz(wchar_t* wcstr, const char* mbstr, size_t count)
  515. {
  516. if (count == 0 && wcstr != NULL)
  517. return 0;
  518. int result = ::MultiByteToWideChar(CP_ACP, 0, mbstr, -1,
  519. wcstr, count);
  520. ASSERT(wcstr == NULL || result <= (int)count);
  521. if (result > 0)
  522. wcstr[result-1] = 0;
  523. return result;
  524. }
  525. LPWSTR AFXAPI AfxA2WHelper(LPWSTR lpw, LPCSTR lpa, int nChars)
  526. {
  527. if (lpa == NULL)
  528. return NULL;
  529. ASSERT(lpw != NULL);
  530. // verify that no illegal character present
  531. // since lpw was allocated based on the size of lpa
  532. // don't worry about the number of chars
  533. lpw[0] = '\0';
  534. VERIFY(MultiByteToWideChar(CP_ACP, 0, lpa, -1, lpw, nChars));
  535. return lpw;
  536. }
  537. LPSTR AFXAPI AfxW2AHelper(LPSTR lpa, LPCWSTR lpw, int nChars)
  538. {
  539. if (lpw == NULL)
  540. return NULL;
  541. ASSERT(lpa != NULL);
  542. // verify that no illegal character present
  543. // since lpa was allocated based on the size of lpw
  544. // don't worry about the number of chars
  545. lpa[0] = '\0';
  546. VERIFY(WideCharToMultiByte(CP_ACP, 0, lpw, -1, lpa, nChars, NULL, NULL));
  547. return lpa;
  548. }
  549. ///////////////////////////////////////////////////////////////////////////////