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.

587 lines
16 KiB

  1. // --------------------------------------------------------------------------------
  2. // wstrpar.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // --------------------------------------------------------------------------------
  5. #include "pch.hxx"
  6. #include "wstrpar.h"
  7. // --------------------------------------------------------------------------------
  8. // FGROWNEEDED - Determines if we need to call _HrGrowDestination
  9. // --------------------------------------------------------------------------------
  10. #define FGROWNEEDED(_cchWrite) (m_cchDest + _cchWrite + sizeof(WCHAR) > m_cchDestMax)
  11. // --------------------------------------------------------------------------------
  12. // CStringParserW::CStringParserW
  13. // --------------------------------------------------------------------------------
  14. CStringParserW::CStringParserW(void)
  15. {
  16. m_cRef = 1;
  17. m_pszSource = NULL;
  18. m_cchSource = 0;
  19. m_iSource = 0;
  20. m_pszDest = NULL;
  21. m_cchDest = 0;
  22. m_cchDestMax = 0;
  23. m_dwFlags = 0;
  24. m_pszTokens = NULL;
  25. m_cCommentNest = 0;
  26. ZeroMemory(&m_rLiteral, sizeof(m_rLiteral));
  27. }
  28. // --------------------------------------------------------------------------------
  29. // CStringParserW::~CStringParserW
  30. // --------------------------------------------------------------------------------
  31. CStringParserW::~CStringParserW(void)
  32. {
  33. if (m_pszDest && m_pszDest != m_szScratch)
  34. g_pMalloc->Free(m_pszDest);
  35. }
  36. // --------------------------------------------------------------------------------
  37. // CStringParserW::AddRef
  38. // --------------------------------------------------------------------------------
  39. ULONG CStringParserW::AddRef(void)
  40. {
  41. return ++m_cRef;
  42. }
  43. // --------------------------------------------------------------------------------
  44. // CStringParserW::AddRef
  45. // --------------------------------------------------------------------------------
  46. ULONG CStringParserW::Release(void)
  47. {
  48. if (0 != --m_cRef)
  49. return m_cRef;
  50. delete this;
  51. return 0;
  52. }
  53. // --------------------------------------------------------------------------------
  54. // CStringParserW::Init
  55. // --------------------------------------------------------------------------------
  56. void CStringParserW::Init(LPCWSTR pszParseMe, ULONG cchParseMe, DWORD dwFlags)
  57. {
  58. // Invalid Args
  59. Assert(NULL == m_pszSource && NULL == m_pszDest && pszParseMe && L'\0' == pszParseMe[cchParseMe]);
  60. // Save Parse Flags
  61. m_dwFlags = dwFlags;
  62. // Safe the String
  63. m_pszSource = pszParseMe;
  64. m_cchSource = cchParseMe;
  65. // Setup Dest
  66. m_pszDest = m_szScratch;
  67. m_cchDestMax = ARRAYSIZE(m_szScratch);
  68. }
  69. // --------------------------------------------------------------------------------
  70. // CStringParserW::SetTokens
  71. // --------------------------------------------------------------------------------
  72. void CStringParserW::SetTokens(LPCWSTR pszTokens)
  73. {
  74. // Save Tokens
  75. m_pszTokens = pszTokens;
  76. }
  77. // --------------------------------------------------------------------------------
  78. // CStringParserW::_HrGrowDestination
  79. // --------------------------------------------------------------------------------
  80. HRESULT CStringParserW::_HrGrowDestination(ULONG cchWrite)
  81. {
  82. // Locals
  83. HRESULT hr=S_OK;
  84. ULONG cbAlloc;
  85. // We should need to grow, should have called FGROWNEEDED
  86. Assert(FGROWNEEDED(cchWrite));
  87. // Is this the first realloc
  88. if (m_pszDest == m_szScratch)
  89. {
  90. // Validate Current Size
  91. Assert(m_cchDestMax == ARRAYSIZE(m_szScratch));
  92. // Compute New Size
  93. cbAlloc = (max(m_cchSource + 1, m_cchDest + 256 + cchWrite) * sizeof(WCHAR));
  94. // Init pszValue
  95. CHECKALLOC(m_pszDest = (LPWSTR)g_pMalloc->Alloc(cbAlloc));
  96. // Copy Current Value
  97. CopyMemory((LPBYTE)m_pszDest, (LPBYTE)m_szScratch, (m_cchDest * sizeof(WCHAR)));
  98. // Set Max Val
  99. m_cchDestMax = (cbAlloc / sizeof(WCHAR));
  100. }
  101. // Otherwise, need to realloc
  102. else
  103. {
  104. // Locals
  105. LPBYTE pbTemp;
  106. // Should already be bigger than m_cchSource + 1
  107. Assert(m_cchDestMax >= m_cchSource + 1);
  108. // Compute New Size
  109. cbAlloc = ((m_cchDestMax + 256 + cchWrite) * sizeof(WCHAR));
  110. // Realloc
  111. CHECKALLOC(pbTemp = (LPBYTE)g_pMalloc->Realloc((LPBYTE)m_pszDest, cbAlloc));
  112. // Save new pointer
  113. m_pszDest = (LPWSTR)pbTemp;
  114. // Save new Size
  115. m_cchDestMax = (cbAlloc / sizeof(WCHAR));
  116. }
  117. exit:
  118. // Done
  119. return hr;
  120. }
  121. // --------------------------------------------------------------------------------
  122. // CStringParserW::FIsParseSpace
  123. // --------------------------------------------------------------------------------
  124. BOOL CStringParserW::FIsParseSpace(WCHAR ch, BOOL *pfCommentChar)
  125. {
  126. // Locals
  127. WORD wType;
  128. // Comment Char
  129. *pfCommentChar = FALSE;
  130. // NoComments
  131. if (ISFLAGSET(m_dwFlags, PSF_NOCOMMENTS))
  132. {
  133. // Comment Start ?
  134. if (L'(' == ch)
  135. {
  136. // Increment Nested Count
  137. m_cCommentNest++;
  138. // Comment Char
  139. *pfCommentChar = TRUE;
  140. // Treat it as a space
  141. return TRUE;
  142. }
  143. // Comment End ?
  144. else if (L')' == ch && m_cCommentNest)
  145. {
  146. // Decrement Nested Count
  147. m_cCommentNest--;
  148. // Comment Char
  149. *pfCommentChar = TRUE;
  150. // Treat it as a space
  151. return TRUE;
  152. }
  153. // Inside a Comment ?
  154. else if (m_cCommentNest)
  155. {
  156. // Comment Char
  157. *pfCommentChar = TRUE;
  158. // Treat it as a space
  159. return TRUE;
  160. }
  161. }
  162. // Get StringType
  163. if (L' ' == ch || L'\t' == ch || L'\r' == ch || L'\n' == ch)
  164. return(TRUE);
  165. // Not a space
  166. return(FALSE);
  167. }
  168. // --------------------------------------------------------------------------------
  169. // CStringParserW::ChSkip - Returns TRUE if done parsing
  170. // --------------------------------------------------------------------------------
  171. WCHAR CStringParserW::ChSkipWhite(void)
  172. {
  173. // Locals
  174. WCHAR ch=0;
  175. BOOL fCommentChar;
  176. // Loop
  177. while (1)
  178. {
  179. // Get Current Character
  180. ch = *(m_pszSource + m_iSource);
  181. // Are we done
  182. if (L'\0' == ch)
  183. break;
  184. // Better not be done
  185. Assert(m_iSource < m_cchSource);
  186. // Not a space
  187. if (!FIsParseSpace(ch, &fCommentChar))
  188. break;
  189. // Goto Next Char
  190. m_iSource++;
  191. }
  192. // Done
  193. return ch;
  194. }
  195. // --------------------------------------------------------------------------------
  196. // CStringParserW::ChSkip - Returns TRUE if done parsing
  197. // --------------------------------------------------------------------------------
  198. WCHAR CStringParserW::ChSkip(void)
  199. {
  200. // Locals
  201. WCHAR ch=L'\0';
  202. LPWSTR pszT;
  203. // Loop
  204. while (1)
  205. {
  206. // Get Current Character
  207. ch = *(m_pszSource + m_iSource);
  208. // Are we done
  209. if (L'\0' == ch)
  210. break;
  211. // Better not be done
  212. Assert(m_iSource < m_cchSource);
  213. // Tokens ?
  214. if (m_pszTokens)
  215. {
  216. // Compare Against Tokens..
  217. for (pszT=(LPWSTR)m_pszTokens; *pszT != L'\0'; pszT++)
  218. {
  219. // Token Match ?
  220. if (ch == *pszT)
  221. break;
  222. }
  223. // If we didn't match a token, then we are done
  224. if (L'\0' == *pszT)
  225. break;
  226. }
  227. // Goto Next Char
  228. m_iSource++;
  229. }
  230. // Done
  231. return ch;
  232. }
  233. // --------------------------------------------------------------------------------
  234. // CStringParserW::ChPeekNext
  235. // --------------------------------------------------------------------------------
  236. WCHAR CStringParserW::ChPeekNext(ULONG cchFromCurrent)
  237. {
  238. // Locals
  239. CHAR ch=0;
  240. BOOL fCommentChar;
  241. // Past the end of the source
  242. if (m_iSource + cchFromCurrent >= m_cchSource)
  243. return L'\0';
  244. // Return the character
  245. return *(m_pszSource + m_iSource + cchFromCurrent);
  246. }
  247. // --------------------------------------------------------------------------------
  248. // CStringParserW::ChParse
  249. // --------------------------------------------------------------------------------
  250. WCHAR CStringParserW::ChParse(LPCWSTR pszTokens, DWORD dwFlags)
  251. {
  252. // Save Flags
  253. DWORD dwCurrFlags=m_dwFlags;
  254. // Reset Flags
  255. m_dwFlags = dwFlags;
  256. // Set Parsing Tokens
  257. SetTokens(pszTokens);
  258. // Parse
  259. WCHAR chToken = ChParse();
  260. // Set Flags
  261. m_dwFlags = dwCurrFlags;
  262. // Return the Token
  263. return chToken;
  264. }
  265. // --------------------------------------------------------------------------------
  266. // CStringParserW::ChParse
  267. // --------------------------------------------------------------------------------
  268. WCHAR CStringParserW::ChParse(WCHAR chStart, WCHAR chEnd, DWORD dwFlags)
  269. {
  270. // We really should have finished the last literal
  271. Assert(FALSE == m_rLiteral.fInside);
  272. // Save Flags
  273. DWORD dwCurrFlags = m_dwFlags;
  274. // Reset Flags
  275. m_dwFlags = dwFlags;
  276. // Set Parsing Tokens
  277. SetTokens(NULL);
  278. // Save Literal Info
  279. m_rLiteral.fInside = TRUE;
  280. m_rLiteral.chStart = chStart;
  281. m_rLiteral.chEnd = chEnd;
  282. m_rLiteral.cNested = 0;
  283. // Quoted String
  284. Assert(L'\"' == chStart ? L'\"' == chEnd : TRUE);
  285. // Parse
  286. WCHAR chToken = ChParse();
  287. // Not in a literal
  288. m_rLiteral.fInside = FALSE;
  289. // Reset Flags
  290. m_dwFlags = dwCurrFlags;
  291. // Return the Token
  292. return chToken;
  293. }
  294. // --------------------------------------------------------------------------------
  295. // CStringParserW::HrAppendValue
  296. // --------------------------------------------------------------------------------
  297. HRESULT CStringParserW::HrAppendValue(WCHAR ch)
  298. {
  299. // Locals
  300. HRESULT hr=S_OK;
  301. // Just copy this character
  302. if (FGROWNEEDED(1))
  303. {
  304. // Otherwise, grow the buffer
  305. CHECKHR(hr = _HrGrowDestination(1));
  306. }
  307. // Insert the Character
  308. m_pszDest[m_cchDest++] = ch;
  309. // There is always room for a Null, look at FGROWNEEDED and _HrGrowDestination
  310. m_pszDest[m_cchDest] = L'\0';
  311. exit:
  312. // Done
  313. return hr;
  314. }
  315. // --------------------------------------------------------------------------------
  316. // CStringParserW::ChParse
  317. // --------------------------------------------------------------------------------
  318. WCHAR CStringParserW::ChParse(void)
  319. {
  320. // Locals
  321. HRESULT hr=S_OK;
  322. WCHAR ch;
  323. ULONG iStart=m_iSource;
  324. LONG iLastSpace=-1;
  325. WCHAR chToken;
  326. BOOL fCommentChar;
  327. BOOL fIsSpace;
  328. LPWSTR pszT;
  329. // Invalid Arg
  330. Assert(m_iSource <= m_cchSource && m_pszDest);
  331. // Init chToken
  332. chToken = L'\0';
  333. // No Reset
  334. if (!ISFLAGSET(m_dwFlags, PSF_NORESET))
  335. {
  336. m_pszDest[0] = L'\0';
  337. m_cchDest = 0;
  338. }
  339. // Skip Forward Whitespace
  340. if (ISFLAGSET(m_dwFlags, PSF_NOFRONTWS) && FALSE == m_rLiteral.fInside && L'\0' == ChSkipWhite())
  341. goto TokenFound;
  342. // Save Starting Position
  343. while(1)
  344. {
  345. // Get the Next Character
  346. ch = *(m_pszSource + m_iSource);
  347. // Done
  348. if (L'\0' == ch)
  349. {
  350. chToken = L'\0';
  351. goto TokenFound;
  352. }
  353. // Better not be done
  354. Assert(m_iSource < m_cchSource);
  355. // Check for escaped characters
  356. if (ISFLAGSET(m_dwFlags, PSF_ESCAPED) && L'\\' == ch)
  357. {
  358. // Can I copy two more bytes to pszValue
  359. if (FGROWNEEDED(2))
  360. {
  361. // Otherwise, grow the buffer
  362. CHECKHR(hr = _HrGrowDestination(2));
  363. }
  364. // If Not an Escape Character or the last character is an escape character, then step over it
  365. if (m_iSource + 1 > m_cchSource)
  366. m_pszDest[m_cchDest++] = m_pszSource[m_iSource];
  367. // Next Character
  368. m_iSource++;
  369. // Copy Next Character
  370. if (m_iSource < m_cchSource)
  371. m_pszDest[m_cchDest++] = m_pszSource[m_iSource++];
  372. // Reset space counter
  373. iLastSpace = -1;
  374. // Goto Next Character
  375. continue;
  376. }
  377. // If not inside of a comment
  378. if (0 == m_cCommentNest)
  379. {
  380. if (m_rLiteral.fInside)
  381. {
  382. // End of quoted string
  383. if (ch == m_rLiteral.chEnd)
  384. {
  385. // No nested ?
  386. if (0 == m_rLiteral.cNested)
  387. {
  388. // We found a token
  389. chToken = ch;
  390. // Walk over this item in the string
  391. m_iSource++;
  392. // Ya-hoo, we found a token
  393. hr = S_OK;
  394. // Done
  395. goto TokenFound;
  396. }
  397. // Otherwise, decrement nest
  398. else
  399. m_rLiteral.cNested--;
  400. }
  401. // Otherwise, check for nesting
  402. else if (m_rLiteral.chStart != m_rLiteral.chEnd && ch == m_rLiteral.chStart)
  403. m_rLiteral.cNested++;
  404. }
  405. // Compare for a token - m_cCommentNest is only set if PSF_NOCOMMENTS is set
  406. else if (m_pszTokens)
  407. {
  408. // If this is a token
  409. for (pszT=(LPWSTR)m_pszTokens; *pszT != L'\0'; pszT++)
  410. {
  411. // Is this a token ?
  412. if (ch == *pszT)
  413. break;
  414. }
  415. // Found a token ?
  416. if (*pszT != L'\0')
  417. {
  418. // We found a token
  419. chToken = ch;
  420. // Walk over this item in the string
  421. m_iSource++;
  422. // Ya-hoo, we found a token
  423. hr = S_OK;
  424. // Done
  425. goto TokenFound;
  426. }
  427. }
  428. }
  429. // Always Call
  430. fIsSpace = FIsParseSpace(ch, &fCommentChar);
  431. // Detect Spaces...
  432. if (ISFLAGSET(m_dwFlags, PSF_NOTRAILWS))
  433. {
  434. // If not a space, then kill iLastSpace
  435. if (!fIsSpace)
  436. iLastSpace = -1;
  437. // Otherwise, if not a consecutive space
  438. else if (-1 == iLastSpace)
  439. iLastSpace = m_cchDest;
  440. }
  441. // Copy the next character
  442. if (!fCommentChar)
  443. {
  444. // Make sure we have space
  445. if (FGROWNEEDED(1))
  446. {
  447. // Otherwise, grow the buffer
  448. CHECKHR(hr = _HrGrowDestination(1));
  449. }
  450. // Copy the character
  451. m_pszDest[m_cchDest++] = ch;
  452. }
  453. // Goto next char
  454. m_iSource++;
  455. }
  456. TokenFound:
  457. // Determine correct end of string
  458. if (S_OK == hr && ISFLAGSET(m_dwFlags, PSF_NOTRAILWS) && FALSE == m_rLiteral.fInside)
  459. m_cchDest = (-1 == iLastSpace) ? m_cchDest : iLastSpace;
  460. // Otherwise, just insert a null
  461. Assert(m_cchDest < m_cchDestMax);
  462. // There is always room for a Null, look at FGROWNEEDED and _HrGrowDestination
  463. m_pszDest[m_cchDest] = L'\0';
  464. exit:
  465. // Failure Resets the parse to initial state
  466. if (FAILED(hr))
  467. {
  468. m_iSource = iStart;
  469. chToken = L'\0';
  470. }
  471. // Validate Paren Nesting
  472. // AssertSz(m_cCommentNest == 0, "A string was parsed that has an un-balanced paren nesting.");
  473. // Done
  474. return chToken;
  475. }