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.

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