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.

626 lines
14 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. WSTRING.CPP
  5. Abstract:
  6. Utility string class
  7. History:
  8. a-raymcc 30-May-96 Created.
  9. a-dcrews 16-Mar-99 Added out-of-memory exception handling
  10. --*/
  11. #include "precomp.h"
  12. #include <stdio.h>
  13. #include <wstring.h>
  14. #include <corex.h>
  15. static wchar_t g_szNullString[1] = {0};
  16. /*inline*/ void WString::DeleteString(wchar_t *pStr)
  17. {
  18. if (pStr != g_szNullString)
  19. delete [] pStr;
  20. }
  21. WString::WString()
  22. {
  23. m_pString = g_szNullString;
  24. }
  25. WString::WString(wchar_t *pSrc, BOOL bAcquire)
  26. {
  27. if (bAcquire) {
  28. m_pString = pSrc;
  29. if (m_pString == 0)
  30. m_pString = g_szNullString;
  31. return;
  32. }
  33. if (pSrc == 0) {
  34. m_pString = g_szNullString;
  35. return;
  36. }
  37. m_pString = new wchar_t[wcslen(pSrc) + 1];
  38. // Watch for allocation failures
  39. if ( NULL == m_pString )
  40. {
  41. throw CX_MemoryException();
  42. }
  43. wcscpy(m_pString, pSrc);
  44. }
  45. WString::WString(DWORD dwResourceID, HMODULE hMod)
  46. {
  47. int iSize = 100;
  48. BOOL bNotDone = TRUE;
  49. TCHAR* pTemp = NULL;
  50. // load the string from the string table. Since we dont know what size, try increasing the
  51. // buffer till it works, or until the clearly obsurd case is hit
  52. while (iSize < 10240)
  53. {
  54. pTemp = new TCHAR [iSize];
  55. // Watch for allocation failures
  56. if ( NULL == pTemp )
  57. {
  58. throw CX_MemoryException();
  59. }
  60. int iRead = LoadString(hMod, dwResourceID, pTemp, iSize);
  61. if(iRead == 0)
  62. {
  63. // Bad string
  64. m_pString = g_szNullString;
  65. delete [] pTemp;
  66. return;
  67. }
  68. if(iRead +1 < iSize)
  69. break; // all is well;
  70. iSize += 100; // Try again
  71. delete [] pTemp;
  72. pTemp = NULL;
  73. }
  74. #ifdef UNICODE
  75. //For unicode, this is the string we need!
  76. m_pString = pTemp;
  77. #else
  78. //Only have to convert if we are not using unicode, otherwise it is already in wide mode!
  79. if(pTemp)
  80. {
  81. // got a narrow string, allocate a large string buffer and convert
  82. long len = mbstowcs(NULL, pTemp, lstrlen(pTemp)+1) + 1;
  83. m_pString = new wchar_t[len];
  84. // Watch for allocation failures
  85. if ( NULL == m_pString )
  86. {
  87. delete [] pTemp;
  88. throw CX_MemoryException();
  89. }
  90. mbstowcs(m_pString, pTemp, lstrlen(pTemp)+1);
  91. delete [] pTemp;
  92. }
  93. else
  94. m_pString = g_szNullString;
  95. #endif
  96. }
  97. WString::WString(const wchar_t *pSrc)
  98. {
  99. if (pSrc == 0) {
  100. m_pString = g_szNullString;
  101. return;
  102. }
  103. m_pString = new wchar_t[wcslen(pSrc) + 1];
  104. // Watch for allocation failures
  105. if ( NULL == m_pString )
  106. {
  107. throw CX_MemoryException();
  108. }
  109. wcscpy(m_pString, pSrc);
  110. }
  111. WString::WString(const char *pSrc)
  112. {
  113. m_pString = new wchar_t[strlen(pSrc) + 1];
  114. // Watch for allocation failures
  115. if ( NULL == m_pString )
  116. {
  117. throw CX_MemoryException();
  118. }
  119. mbstowcs(m_pString, pSrc, strlen(pSrc) + 1);
  120. // swprintf(m_pString, L"%S", pSrc);
  121. }
  122. LPSTR WString::GetLPSTR() const
  123. {
  124. long len = 2*(wcslen(m_pString) + 1);
  125. char *pTmp = new char[len];
  126. // Watch for allocation failures
  127. if ( NULL == pTmp )
  128. {
  129. throw CX_MemoryException();
  130. }
  131. wcstombs(pTmp, m_pString, len);
  132. // sprintf(pTmp, "%S", m_pString);
  133. return pTmp;
  134. }
  135. WString& WString::operator =(const WString &Src)
  136. {
  137. DeleteString(m_pString);
  138. m_pString = new wchar_t[wcslen(Src.m_pString) + 1];
  139. // Watch for allocation failures
  140. if ( NULL == m_pString )
  141. {
  142. throw CX_MemoryException();
  143. }
  144. wcscpy(m_pString, Src.m_pString);
  145. return *this;
  146. }
  147. WString& WString::operator =(LPCWSTR pSrc)
  148. {
  149. DeleteString(m_pString);
  150. m_pString = new wchar_t[wcslen(pSrc) + 1];
  151. // Watch for allocation failures
  152. if ( NULL == m_pString )
  153. {
  154. throw CX_MemoryException();
  155. }
  156. wcscpy(m_pString, pSrc);
  157. return *this;
  158. }
  159. WString& WString::operator +=(const wchar_t *pOther)
  160. {
  161. wchar_t *pTmp = new wchar_t[wcslen(m_pString) +
  162. wcslen(pOther) + 1];
  163. // Watch for allocation failures
  164. if ( NULL == pTmp )
  165. {
  166. throw CX_MemoryException();
  167. }
  168. wcscpy(pTmp, m_pString);
  169. wcscat(pTmp, pOther);
  170. DeleteString(m_pString);
  171. m_pString = pTmp;
  172. return *this;
  173. }
  174. WString& WString::operator +=(wchar_t NewChar)
  175. {
  176. wchar_t Copy[2];
  177. Copy[0] = NewChar;
  178. Copy[1] = 0;
  179. wchar_t *pTmp = new wchar_t[wcslen(m_pString) + 2];
  180. // Watch for allocation failures
  181. if ( NULL == pTmp )
  182. {
  183. throw CX_MemoryException();
  184. }
  185. wcscpy(pTmp, m_pString);
  186. wcscat(pTmp, Copy);
  187. DeleteString(m_pString);
  188. m_pString = pTmp;
  189. return *this;
  190. }
  191. WString& WString::operator +=(const WString &Other)
  192. {
  193. wchar_t *pTmp = new wchar_t[wcslen(m_pString) +
  194. wcslen(Other.m_pString) + 1];
  195. // Watch for allocation failures
  196. if ( NULL == pTmp )
  197. {
  198. throw CX_MemoryException();
  199. }
  200. wcscpy(pTmp, m_pString);
  201. wcscat(pTmp, Other.m_pString);
  202. DeleteString(m_pString);
  203. m_pString = pTmp;
  204. return *this;
  205. }
  206. wchar_t WString::operator[](int nIndex) const
  207. {
  208. if (nIndex >= (int) wcslen(m_pString))
  209. return 0;
  210. return m_pString[nIndex];
  211. }
  212. WString& WString::TruncAtRToken(wchar_t Token)
  213. {
  214. for (int i = (int) wcslen(m_pString); i >= 0; i--) {
  215. wchar_t wc = m_pString[i];
  216. m_pString[i] = 0;
  217. if (wc == Token)
  218. break;
  219. }
  220. return *this;
  221. }
  222. WString& WString::TruncAtLToken(wchar_t Token)
  223. {
  224. int nStrlen = wcslen(m_pString);
  225. for (int i = 0; i < nStrlen ; i++)
  226. {
  227. if (Token == m_pString[i])
  228. {
  229. m_pString[i] = 0;
  230. break;
  231. }
  232. }
  233. return *this;
  234. }
  235. WString& WString::StripToToken(wchar_t Token, BOOL bIncludeToken)
  236. {
  237. int nStrlen = wcslen(m_pString);
  238. wchar_t *pTmp = new wchar_t[nStrlen + 1];
  239. // Watch for allocation failures
  240. if ( NULL == pTmp )
  241. {
  242. throw CX_MemoryException();
  243. }
  244. *pTmp = 0;
  245. BOOL bFound = FALSE;
  246. for (int i = 0; i < nStrlen; i++) {
  247. if (m_pString[i] == Token) {
  248. bFound = TRUE;
  249. break;
  250. }
  251. }
  252. if (!bFound)
  253. {
  254. delete [] pTmp;
  255. return *this;
  256. }
  257. if (bIncludeToken) i++;
  258. wcscpy(pTmp, &m_pString[i]);
  259. DeleteString(m_pString);
  260. m_pString = pTmp;
  261. return *this;
  262. }
  263. LPWSTR WString::UnbindPtr()
  264. {
  265. if (m_pString == g_szNullString)
  266. {
  267. m_pString = new wchar_t[1];
  268. // Watch for allocation failures
  269. if ( NULL == m_pString )
  270. {
  271. throw CX_MemoryException();
  272. }
  273. *m_pString = 0;
  274. }
  275. wchar_t *pTmp = m_pString;
  276. m_pString = g_szNullString;
  277. return pTmp;
  278. }
  279. WString& WString::StripWs(int nType)
  280. {
  281. if (nType & leading)
  282. {
  283. wchar_t *pTmp = new wchar_t[wcslen(m_pString) + 1];
  284. // Watch for allocation failures
  285. if ( NULL == pTmp )
  286. {
  287. throw CX_MemoryException();
  288. }
  289. int i = 0;
  290. while (iswspace(m_pString[i]) && m_pString[i]) i++;
  291. wcscpy(pTmp, &m_pString[i]);
  292. DeleteString(m_pString);
  293. m_pString = pTmp;
  294. }
  295. if (nType & trailing)
  296. {
  297. wchar_t *pCursor = m_pString + wcslen(m_pString) - 1;
  298. while (pCursor >= m_pString && iswspace(*pCursor))
  299. *pCursor-- = 0;
  300. }
  301. return *this;
  302. }
  303. wchar_t *WString::GetLToken(wchar_t Tok) const
  304. {
  305. wchar_t *pCursor = m_pString;
  306. while (*pCursor && *pCursor != Tok) pCursor++;
  307. if (*pCursor == Tok)
  308. return pCursor;
  309. return 0;
  310. }
  311. WString WString::operator()(int nLeft, int nRight) const
  312. {
  313. wchar_t *pTmp = new wchar_t[wcslen(m_pString) + 1];
  314. // Watch for allocation failures
  315. if ( NULL == pTmp )
  316. {
  317. throw CX_MemoryException();
  318. }
  319. wchar_t *pCursor = pTmp;
  320. for (int i = nLeft; i < (int) wcslen(m_pString) && i <= nRight; i++)
  321. *pCursor++ = m_pString[i];
  322. *pCursor = 0;
  323. return WString(pTmp, TRUE);
  324. }
  325. BOOL WString::ExtractToken(const wchar_t * pDelimiters, WString &Extract)
  326. {
  327. if(pDelimiters == NULL)
  328. {
  329. Extract.Empty();
  330. return FALSE;
  331. }
  332. // Find which character in the list works. Use the first if none are
  333. // present
  334. int nLen = wcslen(m_pString);
  335. int nDimLen = wcslen(pDelimiters);
  336. for (int i = 0; i < nLen; i++)
  337. for(int j = 0; j < nDimLen; j++)
  338. if (m_pString[i] == pDelimiters[j])
  339. return ExtractToken(pDelimiters[j], Extract);
  340. // If none were found, just use the first.
  341. return ExtractToken(*pDelimiters, Extract);
  342. }
  343. BOOL WString::ExtractToken(wchar_t Delimiter, WString &Extract)
  344. {
  345. int i, i2;
  346. BOOL bTokFound = FALSE;
  347. Extract.Empty();
  348. int nLen = wcslen(m_pString);
  349. wchar_t *pTmp = new wchar_t[nLen + 1];
  350. // Watch for allocation failures
  351. if ( NULL == pTmp )
  352. {
  353. throw CX_MemoryException();
  354. }
  355. for (i = 0; i < nLen; i++)
  356. if (m_pString[i] == Delimiter) {
  357. bTokFound = TRUE;
  358. break;
  359. }
  360. else
  361. pTmp[i] = m_pString[i];
  362. pTmp[i] = 0;
  363. Extract.BindPtr(pTmp);
  364. // Now make *this refer to any leftover stuff.
  365. // ===========================================
  366. pTmp = new wchar_t[nLen - wcslen(pTmp) + 1];
  367. // Watch for allocation failures
  368. if ( NULL == pTmp )
  369. {
  370. throw CX_MemoryException();
  371. }
  372. *pTmp = 0;
  373. for (i2 = 0, i++; i <= nLen; i++)
  374. pTmp[i2++] = m_pString[i];
  375. DeleteString(m_pString);
  376. m_pString = pTmp;
  377. // Return TRUE if the token was encountered, FALSE if not.
  378. // =======================================================
  379. return bTokFound;
  380. }
  381. void WString::Empty()
  382. {
  383. DeleteString(m_pString);
  384. m_pString = g_szNullString;
  385. }
  386. static int _WildcardAux(const wchar_t *pszWildstr, const wchar_t *pszTargetstr,
  387. int iGreedy)
  388. {
  389. enum { start, wild, strip } eState;
  390. wchar_t cInput, cInputw, cLaToken;
  391. if (!wcslen(pszTargetstr) || !wcslen(pszWildstr))
  392. return 0;
  393. for (eState = start;;)
  394. switch (eState)
  395. {
  396. case start:
  397. cInputw = *pszWildstr++; // wildcard input
  398. cInput = *pszTargetstr; // target input
  399. if (!cInputw) // at end of wildcard string?
  400. goto EndScan;
  401. // Check for wildcard chars first
  402. if (cInputw == L'?') { // Simply strips both inputs
  403. if (!cInput) // If end of input, error
  404. return 0;
  405. pszTargetstr++;
  406. continue;
  407. }
  408. if (cInputw == L'*') {
  409. eState = wild;
  410. break;
  411. }
  412. // If here, an exact match is required.
  413. if (cInput != cInputw)
  414. return 0;
  415. // Else remain in same state, since match succeeded
  416. pszTargetstr++;
  417. break;
  418. case wild:
  419. cLaToken = *pszWildstr++; // Establish the lookahead token
  420. eState = strip;
  421. break;
  422. case strip:
  423. cInput = *pszTargetstr;
  424. if (cInput == cLaToken) {
  425. if (!cInput) // Match on a NULL
  426. goto EndScan;
  427. ++pszTargetstr;
  428. // If there is another occurrence of the lookahead
  429. // token in the string, and we are in greedy mode,
  430. // stay in this state
  431. if (!iGreedy)
  432. eState = start;
  433. if (!wcschr(pszTargetstr, cLaToken))
  434. eState = start;
  435. break;
  436. }
  437. if (cLaToken && !cInput) // End of input with a non-null la token
  438. return 0;
  439. ++pszTargetstr; // Still stripping input
  440. break;
  441. }
  442. // Here if the wildcard input is exhausted. If the
  443. // target string is also empty, we have a match,
  444. // otherwise not.
  445. EndScan:
  446. if (wcslen(pszTargetstr))
  447. return 0;
  448. return 1;
  449. }
  450. // Run the test both with greedy and non-greedy matching, allowing the
  451. // greatest possible chance of a match.
  452. BOOL WString::WildcardTest(const wchar_t *pszWildstr) const
  453. {
  454. return (_WildcardAux(pszWildstr, m_pString, 0) |
  455. _WildcardAux(pszWildstr, m_pString, 1));
  456. }
  457. void WString::Unquote()
  458. {
  459. if (!m_pString)
  460. return;
  461. int nLen = wcslen(m_pString);
  462. if (nLen == 0)
  463. return;
  464. // Remove trailing quote.
  465. // ======================
  466. if (m_pString[nLen - 1] == L'"')
  467. m_pString[nLen - 1] = 0;
  468. // Remove leading quote.
  469. // =====================
  470. if (m_pString[0] == L'"')
  471. {
  472. for (int i = 0; i < nLen; i++)
  473. m_pString[i] = m_pString[i + 1];
  474. }
  475. }
  476. WString WString::EscapeQuotes() const
  477. {
  478. WString ws;
  479. int nLen = Length();
  480. for(int i = 0; i < nLen; i++)
  481. {
  482. if(m_pString[i] == '"' || m_pString[i] == '\\')
  483. {
  484. ws += L'\\';
  485. }
  486. ws += m_pString[i];
  487. }
  488. return ws;
  489. }