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.

382 lines
7.5 KiB

  1. /*++
  2. Copyright (c) 1985 - 1999, Microsoft Corporation
  3. Module Name:
  4. cstring.cpp
  5. Abstract:
  6. This file implements the CString class.
  7. Author:
  8. Revision History:
  9. Notes:
  10. --*/
  11. #include "private.h"
  12. #include <tchar.h>
  13. #include "cstring.h"
  14. /////////////////////////////////////////////////////////////////////////////
  15. // static class data
  16. // afxChNil is left for backward compatibility
  17. TCHAR afxChNil = TEXT('\0');
  18. // For an empty string, m_pchData will point here
  19. // (note: avoids special case of checking for NULL m_pchData)
  20. // empty string data (and locked)
  21. int _afxInitData[] = { -1, 0, 0, 0 };
  22. CStringData* _afxDataNil = (CStringData*)&_afxInitData;
  23. LPCTSTR _afxPchNil = (LPCTSTR)(((BYTE*)&_afxInitData)+sizeof(CStringData));
  24. /////////////////////////////////////////////////////////////////////////////
  25. // CString
  26. CString::CString(
  27. )
  28. {
  29. Init();
  30. }
  31. CString::CString(
  32. const CString& stringSrc
  33. )
  34. {
  35. ASSERT(stringSrc.GetData()->nRefs != 0);
  36. if (stringSrc.GetData()->nRefs >= 0) {
  37. ASSERT(stringSrc.GetData() != _afxDataNil);
  38. m_pchData = stringSrc.m_pchData;
  39. InterlockedIncrement(&GetData()->nRefs);
  40. }
  41. else {
  42. Init();
  43. *this = stringSrc.m_pchData;
  44. }
  45. }
  46. CString::CString(
  47. LPCSTR lpsz
  48. )
  49. {
  50. Init();
  51. *this = lpsz;
  52. }
  53. CString::CString(
  54. LPCSTR lpsz,
  55. int nLength
  56. )
  57. {
  58. Init();
  59. if (nLength != 0) {
  60. AllocBuffer(nLength);
  61. memcpy(m_pchData, lpsz, nLength*sizeof(TCHAR));
  62. }
  63. }
  64. CString::~CString(
  65. )
  66. {
  67. // free any attached data
  68. if (GetData() != _afxDataNil) {
  69. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  70. FreeData(GetData());
  71. }
  72. }
  73. void
  74. CString::AllocCopy(
  75. CString& dest,
  76. int nCopyLen,
  77. int nCopyIndex,
  78. int nExtraLen
  79. ) const
  80. {
  81. // will clone the data attached to this string
  82. // allocating 'nExtraLen' characters
  83. // Places results in uninitialized string 'dest'
  84. // Will copy the part or all of original data to start of new string
  85. int nNewLen = nCopyLen + nExtraLen;
  86. if (nNewLen == 0) {
  87. dest.Init();
  88. }
  89. else {
  90. dest.AllocBuffer(nNewLen);
  91. memcpy(dest.m_pchData, m_pchData+nCopyIndex, nCopyLen*sizeof(TCHAR));
  92. }
  93. }
  94. void
  95. CString::AllocBuffer(
  96. int nLen
  97. )
  98. {
  99. // always allocate one extra character for '\0' termination
  100. // assumes [optimistically] that data length will equal allocation length
  101. ASSERT(nLen >= 0);
  102. ASSERT(nLen <= INT_MAX-1); // max size (enough room for 1 extra)
  103. if (nLen == 0)
  104. Init();
  105. else {
  106. CStringData* pData;
  107. pData = (CStringData*) new BYTE[ sizeof(CStringData) + (nLen+1)*sizeof(TCHAR) ];
  108. if (pData)
  109. {
  110. pData->nAllocLength = nLen;
  111. pData->nRefs = 1;
  112. pData->data()[nLen] = TEXT('\0');
  113. pData->nDataLength = nLen;
  114. m_pchData = pData->data();
  115. }
  116. }
  117. }
  118. void
  119. CString::FreeData(
  120. CStringData* pData
  121. )
  122. {
  123. delete [] (BYTE*)pData;
  124. }
  125. void
  126. CString::Release(
  127. )
  128. {
  129. if (GetData() != _afxDataNil) {
  130. ASSERT(GetData()->nRefs != 0);
  131. if (InterlockedDecrement(&GetData()->nRefs) <= 0)
  132. FreeData(GetData());
  133. Init();
  134. }
  135. }
  136. void PASCAL
  137. CString::Release(
  138. CStringData* pData
  139. )
  140. {
  141. if (pData != _afxDataNil) {
  142. ASSERT(pData->nRefs != 0);
  143. if (InterlockedDecrement(&pData->nRefs) <= 0)
  144. FreeData(pData);
  145. }
  146. }
  147. void
  148. CString::AllocBeforeWrite(
  149. int nLen
  150. )
  151. {
  152. if (GetData()->nRefs > 1 ||
  153. nLen > GetData()->nAllocLength) {
  154. Release();
  155. AllocBuffer(nLen);
  156. }
  157. ASSERT(GetData()->nRefs <= 1);
  158. }
  159. int
  160. CString::Compare(
  161. LPCTSTR lpsz
  162. ) const
  163. {
  164. return _tcscmp(m_pchData, lpsz); // MBSC/Unicode aware
  165. }
  166. int
  167. CString::CompareNoCase(
  168. LPCTSTR lpsz
  169. ) const
  170. {
  171. return _tcsicmp(m_pchData, lpsz); // MBCS/Unicode aware
  172. }
  173. CString
  174. CString::Mid(
  175. int nFirst
  176. ) const
  177. {
  178. return Mid(nFirst, GetData()->nDataLength - nFirst);
  179. }
  180. CString
  181. CString::Mid(
  182. int nFirst,
  183. int nCount
  184. ) const
  185. {
  186. // out-of-bounds requests return sensible things
  187. if (nFirst < 0)
  188. nFirst = 0;
  189. if (nCount < 0)
  190. nCount = 0;
  191. if (nFirst + nCount > GetData()->nDataLength)
  192. nCount = GetData()->nDataLength - nFirst;
  193. if (nFirst > GetData()->nDataLength)
  194. nCount = 0;
  195. ASSERT(nFirst >= 0);
  196. ASSERT(nFirst + nCount <= GetData()->nDataLength);
  197. // optimize case of returning entire string
  198. if (nFirst == 0 && nFirst + nCount == GetData()->nDataLength)
  199. return *this;
  200. CString dest;
  201. AllocCopy(dest, nCount, nFirst, 0);
  202. return dest;
  203. }
  204. int
  205. CString::Find(
  206. TCHAR ch
  207. ) const
  208. {
  209. return Find(ch, 0);
  210. }
  211. int
  212. CString::Find(
  213. TCHAR ch,
  214. int nStart
  215. ) const
  216. {
  217. int nLength = GetData()->nDataLength;
  218. if (nStart >= nLength)
  219. return -1;
  220. // find first single character
  221. LPTSTR lpsz = _tcschr(m_pchData + nStart, (_TUCHAR)ch);
  222. // return -1 if not found and index otherwise
  223. return (lpsz == NULL) ? -1 : (int)(lpsz - m_pchData);
  224. }
  225. /////////////////////////////////////////////////////////////////////////////
  226. // Assignment opeators
  227. // All assign a new value to the string
  228. // (a) first see if the buffer is big enough
  229. // (b) if enough room, copy on top of old buffer, set size and type
  230. // (c) otherwise free old string data, and create a new one
  231. //
  232. // All routines return the new string (but as a 'const CString&' so that
  233. // assigning it again will cause a copy, eg: s1 = s2 = "hi there".
  234. //
  235. void
  236. CString::AssignCopy(
  237. int nSrcLen,
  238. LPCTSTR lpszSrcData
  239. )
  240. {
  241. AllocBeforeWrite(nSrcLen);
  242. memcpy(m_pchData, lpszSrcData, nSrcLen*sizeof(TCHAR));
  243. GetData()->nDataLength = nSrcLen;
  244. m_pchData[nSrcLen] = TEXT('\0');
  245. }
  246. const CString&
  247. CString::operator=(
  248. const CString& stringSrc
  249. )
  250. {
  251. if (m_pchData != stringSrc.m_pchData) {
  252. if ((GetData()->nRefs < 0 && GetData() != _afxDataNil) ||
  253. stringSrc.GetData()->nRefs < 0) {
  254. // actual copy necessary since one of the strings is locked
  255. AssignCopy(stringSrc.GetData()->nDataLength, stringSrc.m_pchData);
  256. }
  257. else {
  258. // can just copy reference around
  259. Release();
  260. ASSERT(stringSrc.GetData() != _afxDataNil);
  261. m_pchData = stringSrc.m_pchData;
  262. InterlockedIncrement(&GetData()->nRefs);
  263. }
  264. }
  265. return *this;
  266. }
  267. const CString&
  268. CString::operator=(
  269. char ch
  270. )
  271. {
  272. AssignCopy(1, &ch);
  273. return *this;
  274. }
  275. const CString&
  276. CString::operator=(
  277. LPCTSTR lpsz
  278. )
  279. {
  280. ASSERT(lpsz != NULL);
  281. AssignCopy(SafeStrlen(lpsz), lpsz);
  282. return *this;
  283. }
  284. CString::operator LPCTSTR(
  285. ) const
  286. {
  287. return m_pchData;
  288. }
  289. int PASCAL
  290. CString::SafeStrlen(
  291. LPCTSTR lpsz
  292. )
  293. {
  294. return (lpsz == NULL) ? 0 : lstrlen(lpsz);
  295. }
  296. // Compare helpers
  297. bool
  298. operator==(
  299. const CString& s1,
  300. const CString& s2
  301. )
  302. {
  303. return s1.Compare(s2) == 0;
  304. }
  305. bool
  306. operator==(
  307. const CString& s1,
  308. LPCTSTR s2
  309. )
  310. {
  311. return s1.Compare(s2) == 0;
  312. }
  313. bool
  314. operator==(
  315. LPCTSTR s1,
  316. CString& s2
  317. )
  318. {
  319. return s2.Compare(s1) == 0;
  320. }