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.

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