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.

620 lines
17 KiB

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