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.

473 lines
9.8 KiB

  1. //
  2. // IISCStringImpl.cpp
  3. //
  4. //////////////////////////////////////////////////////////////////////////////
  5. #include "stdafx.h"
  6. #pragma warning(disable:4786) // Disable warning for names > 256
  7. #include "common.h"
  8. #include <algorithm>
  9. #include <deque>
  10. #include <TCHAR.h>
  11. #include "IISCString.h"
  12. //////////////////////////////////////////////////////////////////////////////
  13. ///////////////////////////////////////////////////////////////////////////
  14. // Constructors
  15. ///////////////////////////////////////////////////////////////////////////
  16. CString::CString()
  17. : std::basic_string<TCHAR>()
  18. {
  19. }
  20. CString::CString(const CString& strInput)
  21. : std::basic_string<TCHAR>(strInput)
  22. {
  23. }
  24. CString::CString(const std::basic_string<TCHAR>& strInput)
  25. : std::basic_string<TCHAR>(strInput)
  26. {
  27. }
  28. CString::CString(TCHAR ch, int nRepeat /* = 1*/)
  29. : std::basic_string<TCHAR>(nRepeat, ch)
  30. {
  31. }
  32. CString::CString(LPCTSTR p)
  33. : std::basic_string<TCHAR>(p)
  34. {
  35. }
  36. #ifdef _UNICODE
  37. CString::CString(LPCSTR strInput)
  38. {
  39. int len = strlen(strInput);
  40. TCHAR * buf = (TCHAR *)_alloca(len * (sizeof(TCHAR) + 1));
  41. if (0 != MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED,
  42. strInput, len, buf, len))
  43. {
  44. assign(buf);
  45. }
  46. else
  47. {
  48. ATLASSERT(FALSE);
  49. }
  50. }
  51. #endif
  52. #ifndef _UNICODE
  53. CString::CString(LPCWSTR strInput)
  54. {
  55. int len = wstrlen(strInput);
  56. int buflen = len * (sizeof(TCHAR) + 1);
  57. TCHAR * buf = (TCHAR *)_alloca(buflen);
  58. if (0 != WideCharToMultiByte(CP_THREAD_ACP, 0,
  59. strInput, len, buf, buflen))
  60. {
  61. assign(buf);
  62. }
  63. else
  64. {
  65. ATLASSERT(FALSE);
  66. }
  67. }
  68. #endif
  69. CString::CString(const CComBSTR& bstr)
  70. {
  71. assign((LPCTSTR)bstr.m_str);
  72. }
  73. CString::~CString()
  74. {
  75. }
  76. ///////////////////////////////////////////////////////////////////////////
  77. // The string as an array
  78. ///////////////////////////////////////////////////////////////////////////
  79. int CString::GetLength() const
  80. {
  81. return length();
  82. };
  83. bool CString::IsEmpty() const
  84. {
  85. return empty();
  86. };
  87. void CString::Empty()
  88. {
  89. erase();
  90. };
  91. TCHAR CString::GetAt(int nIndex) const
  92. {
  93. ATLASSERT(nIndex >= 0);
  94. return at(nIndex);
  95. };
  96. TCHAR CString::operator[](int nIndex) const
  97. {
  98. // same as GetAt
  99. ATLASSERT(nIndex >= 0);
  100. return at(nIndex);
  101. }
  102. void CString::SetAt(int nIndex, TCHAR ch)
  103. {
  104. at(nIndex) = ch;
  105. };
  106. const CString& CString::operator=(const CString& stringSrc)
  107. {
  108. assign(stringSrc);
  109. return *this;
  110. }
  111. const CString& CString::operator=(LPCTSTR p)
  112. {
  113. // Here we will have a problem if NULL pointer is passed because
  114. // later STL will call wcslen(NULL) which uses *p without test.
  115. // We will emulate the result by erasing current string
  116. if (p == NULL)
  117. erase();
  118. // another problem is when we assign string to self, like str = str.c_str()
  119. // STL deletes data and then assign it resulting in garbage
  120. else if (p != this->data())
  121. assign(p);
  122. return *this;
  123. }
  124. #ifdef _UNICODE
  125. const CString& CString::operator=(const unsigned char * lpsz)
  126. {
  127. int len = strlen((const char *)lpsz);
  128. TCHAR * buf = (TCHAR *)_alloca(len * (sizeof(TCHAR) + 1));
  129. if (0 != MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED, (const char *)lpsz, -1, buf, len))
  130. {
  131. assign(buf);
  132. }
  133. else
  134. {
  135. ATLASSERT(FALSE);
  136. }
  137. return *this;
  138. }
  139. #endif
  140. const CString& CString::operator=(TCHAR c)
  141. {
  142. assign(1, c);
  143. return *this;
  144. }
  145. #ifdef _UNICODE
  146. const CString& CString::operator+=(char ch)
  147. {
  148. *this += (TCHAR)ch;
  149. return *this;
  150. }
  151. const CString& CString::operator=(char ch)
  152. {
  153. *this = (TCHAR)ch;
  154. return *this;
  155. }
  156. CString __stdcall operator+(const CString& string, char ch)
  157. {
  158. return string + (TCHAR)ch;
  159. }
  160. CString __stdcall operator+(char ch, const CString& string)
  161. {
  162. return (TCHAR)ch + string;
  163. }
  164. #endif
  165. const CString& CString::operator+=(TCHAR ch)
  166. {
  167. append(1, ch);
  168. return *this;
  169. }
  170. const CString& CString::operator+=(const CString& s)
  171. {
  172. append(s);
  173. return *this;
  174. }
  175. const CString& CString::operator+=(LPCTSTR p)
  176. {
  177. append(p);
  178. return *this;
  179. }
  180. static int __stdcall _LoadString(HINSTANCE hInstance, UINT nID, LPTSTR lpszBuf, UINT nMaxBuf)
  181. {
  182. #ifdef _DEBUG
  183. // LoadString without annoying warning from the Debug kernel if the
  184. // segment containing the string is not present
  185. if (::FindResource(hInstance, MAKEINTRESOURCE((nID>>4)+1), RT_STRING) == NULL)
  186. {
  187. lpszBuf[0] = '\0';
  188. return 0; // not found
  189. }
  190. #endif //_DEBUG
  191. int nLen = ::LoadString(hInstance, nID, lpszBuf, nMaxBuf);
  192. if (nLen == 0)
  193. lpszBuf[0] = '\0';
  194. return nLen;
  195. }
  196. #ifdef _UNICODE
  197. #define CHAR_FUDGE 1 // one TCHAR unused is good enough
  198. #else
  199. #define CHAR_FUDGE 2 // two BYTES unused for case of DBC last char
  200. #endif
  201. #define INITIAL_SIZE 256
  202. BOOL CString::LoadString(HINSTANCE hInstance, UINT id)
  203. {
  204. // try fixed buffer first (to avoid wasting space in the heap)
  205. TCHAR szTemp[INITIAL_SIZE];
  206. int nCount = sizeof(szTemp) / sizeof(szTemp[0]);
  207. int nLen = _LoadString(hInstance, id, szTemp, nCount);
  208. if (nCount - nLen > CHAR_FUDGE)
  209. {
  210. *this = szTemp;
  211. return nLen > 0;
  212. }
  213. // try buffer size of 512, then larger size until entire string is retrieved
  214. int nSize = INITIAL_SIZE;
  215. LPTSTR p = NULL;
  216. do
  217. {
  218. nSize += INITIAL_SIZE;
  219. p = get_allocator().allocate(nSize, p);
  220. nLen = _LoadString(hInstance, id, p, nSize - 1);
  221. } while (nSize - nLen <= CHAR_FUDGE);
  222. if (nLen > 0)
  223. assign(p, nLen);
  224. return nLen > 0;
  225. }
  226. ///////////////////////////////////////////////////////////////////////////
  227. // Comparison
  228. ///////////////////////////////////////////////////////////////////////////
  229. int CString::Compare(const TCHAR * psz) const
  230. {
  231. if (psz == NULL)
  232. return this->empty() ? 0 : 1;
  233. return compare(psz);
  234. };
  235. int CString::CompareNoCase(const TCHAR * psz) const
  236. {
  237. if (psz == NULL)
  238. return this->empty() ? 0 : 1;
  239. return _tcsicmp(c_str(), psz);
  240. };
  241. int CString::Collate(const TCHAR * psz) const
  242. {
  243. if (psz == NULL)
  244. return this->empty() ? 0 : 1;
  245. return _tcscoll(c_str(), psz);
  246. };
  247. ///////////////////////////////////////////////////////////////////////////
  248. // Extraction
  249. ///////////////////////////////////////////////////////////////////////////
  250. CString CString::Mid(int nFirst) const
  251. {
  252. return substr(nFirst);
  253. };
  254. CString CString::Mid(int nFirst, int nCount) const
  255. {
  256. return substr(nFirst, nCount);
  257. };
  258. CString CString::Left(int nCount) const
  259. {
  260. return substr(0, nCount);
  261. };
  262. CString CString::Right(int nCount) const
  263. {
  264. return substr(length() - nCount, nCount);
  265. };
  266. CString CString::SpanIncluding(const TCHAR * pszCharSet) const
  267. {
  268. return substr(0, find_first_not_of(pszCharSet));
  269. };
  270. CString CString::SpanExcluding(const TCHAR * pszCharSet) const
  271. {
  272. return substr(0, find_first_of(pszCharSet));
  273. };
  274. ///////////////////////////////////////////////////////////////////////////
  275. // Other Conversions
  276. ///////////////////////////////////////////////////////////////////////////
  277. void CString::MakeUpper()
  278. {
  279. std::for_each(begin(), end(), _totupper);
  280. };
  281. void CString::MakeLower()
  282. {
  283. std::for_each(begin(), end(), _totlower);
  284. };
  285. void CString::MakeReverse()
  286. {
  287. std::reverse(begin(), end());
  288. };
  289. void CString::TrimLeft()
  290. {
  291. while (_istspace(at(0)))
  292. erase(0, 1);
  293. };
  294. void CString::TrimRight()
  295. {
  296. while (_istspace(at(length() - 1)))
  297. erase(length() - 1, 1);
  298. };
  299. #define BUFFER_SIZE 1024
  300. void __cdecl CString::FormatV(LPCTSTR lpszFormat, va_list argList)
  301. {
  302. TCHAR buf[BUFFER_SIZE];
  303. if (-1 != _vsntprintf(buf, BUFFER_SIZE, lpszFormat, argList))
  304. {
  305. assign(buf);
  306. }
  307. }
  308. // formatting (using wsprintf style formatting)
  309. void __cdecl CString::Format(LPCTSTR lpszFormat, ...)
  310. {
  311. va_list argList;
  312. va_start(argList, lpszFormat);
  313. FormatV(lpszFormat, argList);
  314. va_end(argList);
  315. }
  316. void __cdecl CString::Format(HINSTANCE hInst, UINT nFormatID, ...)
  317. {
  318. CString strFormat;
  319. BOOL bRet = strFormat.LoadString(hInst, nFormatID);
  320. bRet; // ref
  321. ATLASSERT(bRet != 0);
  322. va_list argList;
  323. va_start(argList, nFormatID);
  324. FormatV(strFormat, argList);
  325. va_end(argList);
  326. }
  327. // formatting (using FormatMessage style formatting)
  328. BOOL CString::FormatMessage(LPCTSTR lpszFormat, ...)
  329. {
  330. // format message into temporary buffer lpszTemp
  331. va_list argList;
  332. va_start(argList, lpszFormat);
  333. LPTSTR lpszTemp;
  334. BOOL bRet = TRUE;
  335. if (::FormatMessage(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  336. lpszFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 ||
  337. lpszTemp == NULL)
  338. bRet = FALSE;
  339. // assign lpszTemp into the resulting string and free the temporary
  340. *this = lpszTemp;
  341. LocalFree(lpszTemp);
  342. va_end(argList);
  343. return bRet;
  344. }
  345. BOOL CString::FormatMessage(HINSTANCE hInst, UINT nFormatID, ...)
  346. {
  347. // get format string from string table
  348. CString strFormat;
  349. BOOL bRetTmp = strFormat.LoadString(hInst, nFormatID);
  350. bRetTmp; // ref
  351. ATLASSERT(bRetTmp != 0);
  352. // format message into temporary buffer lpszTemp
  353. va_list argList;
  354. va_start(argList, nFormatID);
  355. LPTSTR lpszTemp;
  356. BOOL bRet = TRUE;
  357. if (::FormatMessage(
  358. FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
  359. strFormat, 0, 0, (LPTSTR)&lpszTemp, 0, &argList) == 0 || lpszTemp == NULL
  360. )
  361. bRet = FALSE;
  362. // assign lpszTemp into the resulting string and free lpszTemp
  363. *this = lpszTemp;
  364. LocalFree(lpszTemp);
  365. va_end(argList);
  366. return bRet;
  367. }
  368. ///////////////////////////////////////////////////////////////////////////
  369. // Searching
  370. ///////////////////////////////////////////////////////////////////////////
  371. int CString::Find(TCHAR ch) const
  372. {
  373. return find(ch);
  374. };
  375. int CString::Find(const TCHAR * psz) const
  376. {
  377. if (psz == NULL)
  378. return -1;
  379. return find(psz);
  380. };
  381. int CString::ReverseFind(TCHAR ch) const
  382. {
  383. return rfind(ch);
  384. };
  385. int CString::FindOneOf(const TCHAR * psz) const
  386. {
  387. if (psz == NULL)
  388. return -1;
  389. return find_first_of(psz);
  390. };
  391. ///////////////////////////////////////////////////////////////////////////
  392. // Operators
  393. ///////////////////////////////////////////////////////////////////////////
  394. CString::operator const TCHAR *() const
  395. {
  396. return c_str();
  397. };