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.

730 lines
22 KiB

  1. /*++
  2. Copyright (C) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. CONVERTER.CPP
  5. Abstract:
  6. <sequence> ::= <number> | <number><separator><sequence>
  7. <separator> ::= [<whitespace>],[<whitespace>] | <whitespace>
  8. <number> ::= <whitespace>[-]0x<hexfield>[<comment>] | <whitespace>[-]<digitfield>[<comment>]
  9. <decfield> ::= <decdigit> | <decdigit><decfield>
  10. <decdigit> ::= 0..9
  11. <hexfield> ::= <hexdigit> | <hexdigit><hexfield>
  12. <hexdigit> ::= 1..9 | A | B | C | D | E | F
  13. <comment> ::= [<whitespace>](<string>)[<whitespace>]
  14. <whitespace> ::= SP | TAB | CR | LF
  15. History:
  16. --*/
  17. #include "precomp.h"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <wtypes.h>
  21. #include "wbemcli.h"
  22. #include "var.h"
  23. #include "WT_Converter.h"
  24. //////////////////////////////////////////////////////////////////////
  25. // Construction/Destruction
  26. //////////////////////////////////////////////////////////////////////
  27. CConverter::CConverter(const char* szString, CIMType ct)
  28. {
  29. int nSize = strlen(szString);
  30. m_szString = new char[nSize + 1]; // Made to fit
  31. strcpy(m_szString, szString);
  32. m_ct = ct; // CIM_TYPE
  33. }
  34. CConverter::~CConverter()
  35. {
  36. delete m_szString;
  37. }
  38. /******************************************************************
  39. //
  40. // Helper Functions
  41. //
  42. *******************************************************************/
  43. UINT CConverter::SetBoundary(BOOL bNeg, ULONG *uMaxSize)
  44. //////////////////////////////////////////////////////////////////////
  45. //
  46. // Establishs the outer boundary of a give CIM type. Returns the
  47. // maximum absolute value, including an offset if the value is
  48. // negative. (Compensating for the additional size of 2's complement
  49. // negative values)
  50. //
  51. //////////////////////////////////////////////////////////////////////
  52. {
  53. *uMaxSize = 0;
  54. switch (m_ct)
  55. {
  56. case CIM_UINT8:
  57. *uMaxSize = 0x000000FF; break;
  58. case CIM_SINT8:
  59. *uMaxSize = (bNeg ? 0x00000080 : 0x0000007F); break;
  60. case CIM_UINT16:
  61. *uMaxSize = 0x0000FFFF; break;
  62. case CIM_SINT16:
  63. *uMaxSize = (bNeg ? 0x00008000 : 0x00007FFF); break;
  64. case CIM_UINT32:
  65. *uMaxSize = 0xFFFFFFFF; break;
  66. case CIM_SINT32:
  67. *uMaxSize = (bNeg ? 0x80000000 : 0x7FFFFFFF); break;
  68. case NULL:
  69. return ERR_NULL_CIMTYPE;
  70. default:
  71. return ERR_UNKNOWN;
  72. }
  73. return ERR_NOERROR;
  74. }
  75. BOOL CConverter::IsValidDec(char ch)
  76. //////////////////////////////////////////////////////////////////////
  77. //
  78. // PARAMETERS : a character to be validated as decimal
  79. // RETURNS: TRUE only if the character is a valid decimal character
  80. //
  81. //////////////////////////////////////////////////////////////////////
  82. {
  83. return (('0' <= ch) && ('9' >= ch));
  84. }
  85. BOOL CConverter::IsValidHex(char ch)
  86. //////////////////////////////////////////////////////////////////////
  87. //
  88. // PARAMETERS : a character to be validated as hexadecimal
  89. // RETURNS: TRUE only if the character is a valid hexadecimal character
  90. //
  91. //////////////////////////////////////////////////////////////////////
  92. {
  93. return ((('0' <= ch) && ('9' >= ch)) || (('a' <= ch) && ('f' <= ch)));
  94. }
  95. /******************************************************************
  96. //
  97. // Parser Functions
  98. //
  99. *******************************************************************/
  100. char CConverter::PeekToken(char *ch)
  101. //////////////////////////////////////////////////////////////////////
  102. //
  103. // PARAMETERS: the token pointer (by val)
  104. // RETURNS: the character following the current token pointer. Does
  105. // not increment the token pointer.
  106. //
  107. //////////////////////////////////////////////////////////////////////
  108. {
  109. // ch is passed by value; change is local to method
  110. ch++;
  111. // Ensure lower case
  112. if (('A' <= *ch) && ('Z' >= *ch))
  113. *ch += ('a' - 'A');
  114. return *ch;
  115. }
  116. BOOL CConverter::GetToken(char **ch)
  117. //////////////////////////////////////////////////////////////////////
  118. //
  119. // If the token pointer is not at the end of the string, it will be
  120. // incremented and the current token will be converted into lower
  121. // case and passed back. If the pointer is at the end of the string,
  122. // NULL will be passed and the pointer unaffected.
  123. //
  124. // PARAMETERS: the token pointer (by ref)
  125. //
  126. // RETURNS: TRUE if the token pointer is mid-string, and FALSE if it
  127. // is at the end of the string.
  128. //
  129. //////////////////////////////////////////////////////////////////////
  130. {
  131. // Increment pointer by 1 byte
  132. if ('\0' != **ch)
  133. *ch += 1;
  134. // Ensure lower case
  135. if (('A' <= **ch) && ('Z' >= **ch))
  136. **ch += ('a' - 'A');
  137. // End of the line?
  138. return ('\0' != **ch);
  139. }
  140. void CConverter::ReplaceToken(char **ch)
  141. //////////////////////////////////////////////////////////////////////
  142. //
  143. // If not at the front of the string, the token pointer will be
  144. // decremented one place towards the head of the string.
  145. //
  146. // PARAMETERS: the token pointer (by ref)
  147. //
  148. // RETURNS: void
  149. //
  150. //////////////////////////////////////////////////////////////////////
  151. {
  152. if (*ch != m_szString)
  153. *ch -= 1;
  154. return;
  155. }
  156. BOOL CConverter::Done(char *ch)
  157. //////////////////////////////////////////////////////////////////////
  158. //
  159. // Checks for additional non-whitespace tokens following current
  160. // token. Does not validate token.
  161. //
  162. // PARAMETERS: the token pointer (by ref)
  163. //
  164. // RETURNS: TRUE if no further non-whitespace tokens follow the
  165. // current token pointer
  166. //
  167. //////////////////////////////////////////////////////////////////////
  168. {
  169. if ('\0' == *ch)
  170. return TRUE;
  171. while (isspace(*ch))
  172. ch++;
  173. return ('\0' == *ch);
  174. }
  175. /******************************************************************
  176. //
  177. // Token Functions
  178. //
  179. *******************************************************************/
  180. UINT CConverter::Token_Sequence(CVar *pVar)
  181. //////////////////////////////////////////////////////////////////////
  182. //
  183. // Root of parsing for single (non-array) values. Sets up token
  184. // pointer (ch), and parses one number. If tokens remain in the
  185. // input string following the parsing of the first number, then
  186. // the input string is invalid.
  187. //
  188. // If the parsing fails, the value of pVar is not changed
  189. //
  190. // PARAMETERS: a variant for the result (by ref)
  191. //
  192. // RETURNS: the result state of the parsing
  193. //
  194. //////////////////////////////////////////////////////////////////////
  195. {
  196. CVar aVar; // A temporary result variant
  197. char *ch = m_szString; // The token pointer
  198. UINT uRes; // A generic result sink
  199. // Parse out the number
  200. uRes = Token_Number(&ch, &aVar);
  201. if (ERR_NOERROR != uRes)
  202. return uRes;
  203. // Check for remaining tokens
  204. if (!Done(ch))
  205. return ERR_INVALID_INPUT_STRING;
  206. // Parsing ok, copy temp variant into final destiation
  207. *pVar = aVar;
  208. return ERR_NOERROR;
  209. }
  210. UINT CConverter::Token_Sequence(CVarVector *pVarVec)
  211. //////////////////////////////////////////////////////////////////////
  212. //
  213. // Root of parsing for multiple (array) values. Sets up token
  214. // pointer (ch), and parses the input string. It starts with a
  215. // single number, and then enters the loop, verifying a seperator
  216. // between each subsequent number. Each number is added to the
  217. // variant array as it is parsed.
  218. //
  219. // If the parsing fails, the value if pVarVec is not changed
  220. //
  221. // PARAMETERS: a variant vector for the result (by ref)
  222. //
  223. // RETURNS: the result state of the parsing
  224. //
  225. //////////////////////////////////////////////////////////////////////
  226. {
  227. CVar aVar; // A temporary result variant
  228. char *ch = m_szString; // The token pointer
  229. UINT uRes; // A generic result sink
  230. UINT uVTType;
  231. switch (m_ct)
  232. {
  233. case CIM_UINT8:
  234. uVTType = VT_UI1;break;
  235. case CIM_SINT8:
  236. case CIM_SINT16:
  237. uVTType = VT_I2;break;
  238. case CIM_UINT16:
  239. case CIM_UINT32:
  240. case CIM_SINT32:
  241. uVTType = VT_I4;break;
  242. }
  243. CVarVector aVarVec(uVTType);// A temporary result variant vector
  244. // Parse out the first number
  245. uRes = Token_Number(&ch, &aVar);
  246. if (ERR_NOERROR != uRes)
  247. return uRes;
  248. // Add to array, and clear temporary variant
  249. aVarVec.Add(aVar);
  250. // If more tokens exist, continue
  251. while (!Done(ch))
  252. {
  253. // Verify separator
  254. uRes = Token_Separator(&ch);
  255. if (ERR_NOERROR != uRes)
  256. return uRes;
  257. // Parse out next number
  258. uRes = Token_Number(&ch, &aVar);
  259. if (ERR_NOERROR != uRes)
  260. return uRes;
  261. // Add to array, and clear temporary variant
  262. aVarVec.Add(aVar);
  263. }
  264. // Parsing ok, copy temp variant vector into final destiation
  265. *pVarVec = aVarVec;
  266. return ERR_NOERROR;
  267. }
  268. UINT CConverter::Token_WhiteSpace(char **ch)
  269. //////////////////////////////////////////////////////////////////////
  270. //
  271. // Move token pointer to the next non-white space token
  272. //
  273. // PARAMETERS: the token pointer (by ref)
  274. //
  275. // RETURNS: the result state of the parsing
  276. //
  277. //////////////////////////////////////////////////////////////////////
  278. {
  279. while (isspace(**ch))
  280. GetToken(ch);
  281. return ERR_NOERROR;
  282. }
  283. UINT CConverter::Token_Separator(char **ch)
  284. //////////////////////////////////////////////////////////////////////
  285. //
  286. // A valid separator is either white space or a comma optionally
  287. // preceeded by white space. Parese out white space. Stop when
  288. // a non-whitespace character is encountered. If a comma, then
  289. // there must be a following non-whitespace token.
  290. //
  291. // PARAMETERS: the token pointer (by ref)
  292. //
  293. // RETURNS: the result state of the parsing
  294. //
  295. //////////////////////////////////////////////////////////////////////
  296. {
  297. BOOL bComma = FALSE;
  298. while ((isspace(**ch) || (',' == **ch)) && !bComma)
  299. {
  300. if (',' == **ch)
  301. bComma = TRUE;
  302. // If a comma exists, the string must not be done
  303. if (!GetToken(ch) && bComma)
  304. return ERR_INVALID_TOKEN;
  305. }
  306. return ERR_NOERROR;
  307. }
  308. UINT CConverter::Token_Number(char **ch, CVar *pVar)
  309. //////////////////////////////////////////////////////////////////////
  310. //
  311. // Determines the sign and base values of the number, and then
  312. // calls either Token_HexField or Token_DecField to continue
  313. // parsing the digit fields. The numerical value returned from
  314. // the parsing is unsigned. If the value is signed and negative
  315. // the value is negated. Comments are then parsed out.
  316. //
  317. // If the parsing fails, the value of pVar does not change
  318. //
  319. // PARAMETERS: the token pointer (by ref) and a Variant representing
  320. // the number (by ref)
  321. //
  322. // RETURNS: the result state of the parsing
  323. //
  324. //////////////////////////////////////////////////////////////////////
  325. {
  326. ULONG aVal; // Temp value returned from Token_XXXField
  327. USHORT uBase = BASE_DEC; // Base of number
  328. BOOL bNegative = FALSE; // Sign of number
  329. UINT uRes; // Generic result sink
  330. // Parse out white space
  331. uRes = Token_WhiteSpace(ch);
  332. if (ERR_NOERROR != uRes)
  333. return uRes;
  334. // Determines the sign (assumed positive) and validates against type
  335. if (**ch == '-')
  336. {
  337. if ((CIM_UINT8 == m_ct) || (CIM_UINT16 == m_ct) || (CIM_UINT32 == m_ct))
  338. return ERR_INVALID_SIGNED_VALUE;
  339. //else
  340. bNegative = TRUE;
  341. GetToken(ch); // Get the next token to handle
  342. }
  343. // Determine Base (we have initialized as decimal)
  344. if (**ch == '0')
  345. {
  346. if (PeekToken(*ch) == 'x') // Hexadecimal!
  347. {
  348. uBase = BASE_HEX; // Modify base
  349. GetToken(ch); // Get Rid of the 'x' token
  350. GetToken(ch); // Get the next token to handle
  351. }
  352. }
  353. // Parse digit field and put result in aVal
  354. if (BASE_HEX == uBase)
  355. uRes = Token_HexField(ch, bNegative, &aVal);
  356. else if (BASE_DEC == uBase)
  357. uRes = Token_DecField(ch, bNegative, &aVal);
  358. else
  359. return ERR_UNKNOWN_BASE;
  360. if (ERR_NOERROR != uRes)
  361. return uRes;
  362. // NOTE: signed operation on unsigned value
  363. // -this may cause a problem on some platforms
  364. if (bNegative)
  365. aVal *= (-1);
  366. // Set variant
  367. pVar->SetLong(aVal);
  368. // Parse out comments
  369. uRes = Token_Comment(ch);
  370. if (ERR_NOERROR != uRes)
  371. return uRes;
  372. return ERR_NOERROR;
  373. }
  374. UINT CConverter::Token_DecField(char **ch, BOOL bNeg, ULONG *pVal)
  375. //////////////////////////////////////////////////////////////////////
  376. //
  377. // Token_DecField first determines the maximum possible value of
  378. // the number based on the CIM type for the purpose of bonuds checking.
  379. // The digit field is parsed, withe each token being added to the
  380. // previous tally value after it has increased in magnitude.
  381. //
  382. // Prior to the tally increasing, the proposed tally is validated
  383. // using an algorithm that assumes that the current value is in
  384. // range, and verifies that the proposed value will be in range
  385. // by working back from the maximum value. This algorithm works,
  386. // given that the initial value is 0, which is guarenteed to be
  387. // within range. The difference between the current tally, and the
  388. // proposed tally is subtracted from the maximum value, and if the
  389. // result is larger than the current tally, then the propsed value
  390. // is valid.
  391. //
  392. // This algorithm assumes that we are using unsigend values. Signed
  393. // negative values are constructed as positive values, and then
  394. // converted. In this case, the maximum value is one larger than the
  395. // positive maximum value, according to the rules of 2's complement.
  396. //
  397. // If the parsing fails, the value of pVal does not change
  398. //
  399. // PARAMETERS: the token pointer (by ref), the sign flag (by val)
  400. // and a the unsigned value of the number (by ref)
  401. //
  402. // RETURNS: the result state of the parsing
  403. //
  404. //////////////////////////////////////////////////////////////////////
  405. {
  406. ULONG uMaxSize; // Boundary value
  407. ULONG aVal = 0; // Tally value
  408. ULONG uDigitVal; // Return digit from Token_DecDigit
  409. UINT uRes; // Generic result sink
  410. // Sets the maximum value of the tally
  411. uRes = SetBoundary(bNeg, &uMaxSize);
  412. if (ERR_NOERROR != uRes)
  413. return uRes;
  414. // Pareses the first digit
  415. uRes = Token_DecDigit(ch, &uDigitVal);
  416. if (ERR_NOERROR != uRes)
  417. return uRes;
  418. // Adds to tally
  419. aVal = uDigitVal;
  420. // If more decimal tokens...
  421. while (IsValidDec(**ch))
  422. {
  423. // Parse the token
  424. uRes = Token_DecDigit(ch, &uDigitVal);
  425. if (ERR_NOERROR != uRes)
  426. return uRes;
  427. // Test the bounds of the proposed tally
  428. if (((uMaxSize - uDigitVal) / BASE_DEC ) < aVal)
  429. return ERR_OUT_OF_RANGE;
  430. // Increase the magnitude and add the token digit value
  431. aVal = (aVal * BASE_DEC) + uDigitVal;
  432. }
  433. // Parsing ok, copy the temp to the destination
  434. *pVal = aVal;
  435. return ERR_NOERROR;
  436. }
  437. UINT CConverter::Token_HexField(char **ch, BOOL bNeg, ULONG *pVal)
  438. //////////////////////////////////////////////////////////////////////
  439. //
  440. // See Token_DecField
  441. //
  442. //////////////////////////////////////////////////////////////////////
  443. {
  444. ULONG uMaxSize; // Boundary value
  445. ULONG aVal = 0; // Tally value
  446. ULONG uDigitVal; // Return digit from Token_DecDigit
  447. UINT uRes; // Generic result
  448. // Sets the maximum value of the tally
  449. uRes = SetBoundary(bNeg, &uMaxSize);
  450. if (ERR_NOERROR != uRes)
  451. return uRes;
  452. // Pareses the first digit
  453. uRes = Token_HexDigit(ch, &uDigitVal);
  454. if (ERR_NOERROR != uRes)
  455. return uRes;
  456. // Adds to tally
  457. aVal = uDigitVal;
  458. // If more decimal tokens...
  459. while (IsValidHex(**ch))
  460. {
  461. // Parse the token
  462. uRes = Token_HexDigit(ch, &uDigitVal);
  463. if (ERR_NOERROR != uRes)
  464. return uRes;
  465. // Test the bounds of next tally
  466. if (((uMaxSize - uDigitVal) / BASE_HEX ) < aVal)
  467. return ERR_OUT_OF_RANGE;
  468. // Increase the magnitude and add the token digit value
  469. aVal = (aVal * BASE_HEX) + uDigitVal;
  470. }
  471. // Parsing ok, copy the temp to the destination
  472. *pVal = aVal;
  473. return ERR_NOERROR;
  474. }
  475. UINT CConverter::Token_DecDigit(char **ch, ULONG *pVal)
  476. //////////////////////////////////////////////////////////////////////
  477. //
  478. // Validates the token, and converts to numerical equivalent
  479. //
  480. // If the parsing fails, the value of pVal does not change
  481. //
  482. // PARAMETERS: the token pointer (by ref) and a the value
  483. // of the digit (by ref)
  484. //
  485. // RETURNS: the result state of the parsing
  486. //
  487. //////////////////////////////////////////////////////////////////////
  488. {
  489. ULONG uVal = 0; // Temp value
  490. // Validate digit & convert
  491. if (('0' <= **ch) && ('9' >= **ch))
  492. uVal = **ch - '0';
  493. else if ('\0' == **ch)
  494. return ERR_NULL_TOKEN;
  495. else
  496. return ERR_INVALID_TOKEN;
  497. // Parsing ok, copy value to destination
  498. *pVal = uVal;
  499. // Move token pointer
  500. GetToken(ch);
  501. return ERR_NOERROR;
  502. }
  503. UINT CConverter::Token_HexDigit(char **ch, ULONG *pVal)
  504. //////////////////////////////////////////////////////////////////////
  505. //
  506. // Validates the token, and converts to numerical equivalent
  507. //
  508. // If the parsing fails, the value of pVal does not change
  509. //
  510. // PARAMETERS: the token pointer (by ref) and a the value
  511. // of the digit (by ref)
  512. //
  513. // RETURNS: the result state of the parsing
  514. //
  515. //////////////////////////////////////////////////////////////////////
  516. {
  517. ULONG uVal = 0; // Temp value
  518. // Validate digit & convert
  519. if (('a' <= **ch) && ('f' >= **ch))
  520. uVal = 0xA + (**ch - 'a');
  521. else if (('0' <= **ch) && ('9' >= **ch))
  522. uVal = **ch - '0';
  523. else if ('\0' == **ch)
  524. return ERR_NULL_TOKEN;
  525. else
  526. return ERR_INVALID_TOKEN;
  527. // Parsing ok, copy value to destination
  528. *pVal = uVal;
  529. // Move token pointer
  530. GetToken(ch);
  531. return ERR_NOERROR;
  532. }
  533. UINT CConverter::Token_Comment(char** ch)
  534. //////////////////////////////////////////////////////////////////////
  535. //
  536. // Parses out white space and contents between braces, if they exist.
  537. // If an opening brace is encountered, all of the contents, including
  538. // the braces, are ignored. If an opening brace is encountered, a
  539. // closing brace must follow.
  540. //
  541. // NOTE: Nested comments are not allowed
  542. //
  543. // PARAMETERS: the token pointer (by ref)
  544. //
  545. // RETURNS: the result state of the parsing
  546. //
  547. //////////////////////////////////////////////////////////////////////
  548. {
  549. // Parse out white space
  550. UINT uRes = Token_WhiteSpace(ch);
  551. if (ERR_NOERROR != uRes)
  552. return uRes;
  553. // If the token following the white space is an opening brace,
  554. // parse out the contents, and verify the existance of the
  555. // closing brace
  556. if ('(' == **ch)
  557. {
  558. while ((')' != **ch))
  559. {
  560. if (!GetToken(ch))
  561. return ERR_UNMATCHED_BRACE;
  562. }
  563. GetToken(ch); // Purge closing brace
  564. }
  565. return ERR_NOERROR;
  566. }
  567. /******************************************************************
  568. //
  569. // Static Functions
  570. //
  571. *******************************************************************/
  572. UINT CConverter::Convert(const char* szString, CIMType ct, CVar *pVar)
  573. /////////////////////////////////////////////////////////////////////
  574. //
  575. // Convert is a static method that creates an instance of the
  576. // Converter object and converts the string to a variant. If an
  577. // error occurs, the value of pVar is not affected.
  578. //
  579. // PARAMETERS: the input string (by val), the CIM type (by val) and
  580. // the outout variant (by ref)
  581. //
  582. // RETURNS: the result state of the parsing
  583. //
  584. /////////////////////////////////////////////////////////////////////
  585. {
  586. // Checks the CIM type is initialized
  587. if (NULL == ct)
  588. return ERR_NULL_CIMTYPE;
  589. CConverter converter(szString, ct); // The converter object
  590. CVar aVar; // Temp variant
  591. // Parse out the first number
  592. UINT uRes = converter.Token_Sequence(&aVar);
  593. // Check return code
  594. if (ERR_NOERROR != uRes)
  595. return uRes;
  596. // Parsing ok, copy temp to destination
  597. *pVar = aVar;
  598. return ERR_NOERROR;
  599. }
  600. UINT CConverter::Convert(const char* szString, CIMType ct, CVarVector *pVarVec)
  601. /////////////////////////////////////////////////////////////////////
  602. //
  603. // Convert is a static method that creates an instance of the
  604. // Converter object and converts the string to an array of values.
  605. // If an error occurs, the value of pVarVec is not affected.
  606. //
  607. // PARAMETERS: the input string (by val), the CIM type (by val) and
  608. // the outout variant vecter (by ref)
  609. //
  610. // Returns the result state of the parsing
  611. //
  612. /////////////////////////////////////////////////////////////////////
  613. {
  614. // Checks the CIM type is initialized
  615. if (NULL == ct)
  616. return ERR_NULL_CIMTYPE;
  617. CConverter converter(szString, ct); // The converter object
  618. CVarVector aVarVec; // Temp variant vector
  619. // Parse out the first number
  620. UINT uRes = converter.Token_Sequence(&aVarVec);
  621. // Check return code
  622. if (ERR_NOERROR != uRes)
  623. return uRes;
  624. // Parsing ok, copy temp to destination
  625. *pVarVec = aVarVec;
  626. return ERR_NOERROR;
  627. }