Source code of Windows XP (NT5)
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.

2148 lines
57 KiB

  1. //******************************************************************************
  2. //
  3. // ANALYSER.CPP
  4. //
  5. // Copyright (C) 1996-1999 Microsoft Corporation
  6. //
  7. //******************************************************************************
  8. #include "precomp.h"
  9. #include "pragmas.h"
  10. #include "analyser.h"
  11. #include <stack>
  12. #include <strutils.h>
  13. #include <objpath.h>
  14. #include <fastval.h>
  15. #include <genutils.h>
  16. #include <datetimeparser.h>
  17. #include "CWbemTime.h"
  18. #include <wstlallc.h>
  19. CClassInfoArray::CClassInfoArray()
  20. : m_bLimited( FALSE )
  21. {
  22. m_pClasses = new CUniquePointerArray<CClassInformation>;
  23. if ( m_pClasses )
  24. {
  25. m_pClasses->RemoveAll();
  26. }
  27. }
  28. CClassInfoArray::~CClassInfoArray()
  29. {
  30. delete m_pClasses;
  31. }
  32. bool CClassInfoArray::operator=(CClassInfoArray& Other)
  33. {
  34. SetLimited(Other.IsLimited());
  35. m_pClasses->RemoveAll();
  36. for(int i = 0; i < Other.m_pClasses->GetSize(); i++)
  37. {
  38. CClassInformation* pInfo = new CClassInformation(*(*Other.m_pClasses)[i]);
  39. if(pInfo == NULL)
  40. return false;
  41. m_pClasses->Add(pInfo);
  42. }
  43. return true;
  44. }
  45. bool CClassInfoArray::SetOne(LPCWSTR wszClass, BOOL bIncludeChildren)
  46. {
  47. CClassInformation* pNewInfo = _new CClassInformation;
  48. if(pNewInfo == NULL)
  49. return false;
  50. pNewInfo->m_wszClassName = CloneWstr(wszClass);
  51. if(pNewInfo->m_wszClassName == NULL)
  52. {
  53. delete pNewInfo;
  54. return false;
  55. }
  56. pNewInfo->m_bIncludeChildren = bIncludeChildren;
  57. m_pClasses->RemoveAll();
  58. m_pClasses->Add(pNewInfo);
  59. SetLimited(TRUE);
  60. return true;
  61. }
  62. HRESULT CQueryAnalyser::GetPossibleInstanceClasses(
  63. QL_LEVEL_1_RPN_EXPRESSION* pExpr,
  64. CClassInfoArray*& paInfos)
  65. {
  66. // Organize a stack of classinfo arrays
  67. // ====================================
  68. std::stack<CClassInfoArray*,std::deque<CClassInfoArray*,wbem_allocator<CClassInfoArray*> > > InfoStack;
  69. HRESULT hres = WBEM_S_NO_ERROR;
  70. // "Evaluate" the query
  71. // ====================
  72. if(pExpr->nNumTokens == 0)
  73. {
  74. // Empty query --- no information
  75. // ==============================
  76. paInfos = _new CClassInfoArray;
  77. if(paInfos == NULL)
  78. return WBEM_E_OUT_OF_MEMORY;
  79. paInfos->SetLimited(FALSE);
  80. return WBEM_S_NO_ERROR;
  81. }
  82. for(int i = 0; i < pExpr->nNumTokens; i++)
  83. {
  84. QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
  85. CClassInfoArray* paNew = _new CClassInfoArray;
  86. if(paNew == NULL)
  87. return WBEM_E_OUT_OF_MEMORY;
  88. CClassInfoArray* paFirst;
  89. CClassInfoArray* paSecond;
  90. switch(Token.nTokenType)
  91. {
  92. case QL1_OP_EXPRESSION:
  93. hres = GetInstanceClasses(Token, *paNew);
  94. InfoStack.push(paNew);
  95. break;
  96. case QL1_AND:
  97. if(InfoStack.size() < 2)
  98. {
  99. hres = WBEM_E_CRITICAL_ERROR;
  100. break;
  101. }
  102. paFirst = InfoStack.top(); InfoStack.pop();
  103. paSecond = InfoStack.top(); InfoStack.pop();
  104. hres = AndPossibleClassArrays(paFirst, paSecond, paNew);
  105. InfoStack.push(paNew);
  106. delete paFirst;
  107. delete paSecond;
  108. break;
  109. case QL1_OR:
  110. if(InfoStack.size() < 2)
  111. {
  112. hres = WBEM_E_CRITICAL_ERROR;
  113. break;
  114. }
  115. paFirst = InfoStack.top(); InfoStack.pop();
  116. paSecond = InfoStack.top(); InfoStack.pop();
  117. hres = OrPossibleClassArrays(paFirst, paSecond, paNew);
  118. InfoStack.push(paNew);
  119. delete paFirst;
  120. delete paSecond;
  121. break;
  122. case QL1_NOT:
  123. if(InfoStack.size() < 1)
  124. {
  125. hres = WBEM_E_CRITICAL_ERROR;
  126. break;
  127. }
  128. paFirst = InfoStack.top(); InfoStack.pop();
  129. hres = NegatePossibleClassArray(paFirst, paNew);
  130. InfoStack.push(paNew);
  131. delete paFirst;
  132. break;
  133. default:
  134. hres = WBEM_E_CRITICAL_ERROR;
  135. delete paNew;
  136. }
  137. if(FAILED(hres))
  138. {
  139. // An error occurred, break out of the loop
  140. // ========================================
  141. break;
  142. }
  143. }
  144. if(SUCCEEDED(hres) && InfoStack.size() != 1)
  145. {
  146. hres = WBEM_E_CRITICAL_ERROR;
  147. }
  148. if(FAILED(hres))
  149. {
  150. // An error occurred. Clear the stack
  151. // ==================================
  152. while(!InfoStack.empty())
  153. {
  154. delete InfoStack.top();
  155. InfoStack.pop();
  156. }
  157. return hres;
  158. }
  159. // All is good
  160. // ===========
  161. paInfos = InfoStack.top();
  162. return S_OK;
  163. }
  164. HRESULT CQueryAnalyser::AndPossibleClassArrays(IN CClassInfoArray* paFirst,
  165. IN CClassInfoArray* paSecond,
  166. OUT CClassInfoArray* paNew)
  167. {
  168. // For now, simply pick one
  169. // ========================
  170. if(paFirst->IsLimited())
  171. *paNew = *paFirst;
  172. else
  173. *paNew = *paSecond;
  174. return WBEM_S_NO_ERROR;
  175. }
  176. HRESULT CQueryAnalyser::OrPossibleClassArrays(IN CClassInfoArray* paFirst,
  177. IN CClassInfoArray* paSecond,
  178. OUT CClassInfoArray* paNew)
  179. {
  180. // Append them together
  181. // ====================
  182. paNew->Clear();
  183. if(paFirst->IsLimited() && paSecond->IsLimited())
  184. {
  185. paNew->SetLimited(TRUE);
  186. for(int i = 0; i < paFirst->GetNumClasses(); i++)
  187. {
  188. CClassInformation* pInfo =
  189. new CClassInformation(*paFirst->GetClass(i));
  190. if(pInfo == NULL)
  191. return WBEM_E_OUT_OF_MEMORY;
  192. if(!paNew->AddClass(pInfo))
  193. {
  194. delete pInfo;
  195. return WBEM_E_OUT_OF_MEMORY;
  196. }
  197. }
  198. for(i = 0; i < paSecond->GetNumClasses(); i++)
  199. {
  200. CClassInformation* pInfo =
  201. new CClassInformation(*paSecond->GetClass(i));
  202. if(pInfo == NULL)
  203. return WBEM_E_OUT_OF_MEMORY;
  204. if(!paNew->AddClass(pInfo))
  205. {
  206. delete pInfo;
  207. return WBEM_E_OUT_OF_MEMORY;
  208. }
  209. }
  210. }
  211. return WBEM_S_NO_ERROR;
  212. }
  213. HRESULT CQueryAnalyser::NegatePossibleClassArray(IN CClassInfoArray* paOrig,
  214. OUT CClassInfoArray* paNew)
  215. {
  216. // No information!
  217. // ===============
  218. paNew->Clear();
  219. return WBEM_S_NO_ERROR;
  220. }
  221. HRESULT CQueryAnalyser::GetDefiniteInstanceClasses(
  222. QL_LEVEL_1_RPN_EXPRESSION* pExpr,
  223. CClassInfoArray*& paInfos)
  224. {
  225. // Organize a stack of classinfo arrays
  226. // ====================================
  227. std::stack<CClassInfoArray*, std::deque<CClassInfoArray*,wbem_allocator<CClassInfoArray*> > > InfoStack;
  228. HRESULT hres = WBEM_S_NO_ERROR;
  229. // "Evaluate" the query
  230. // ====================
  231. if(pExpr->nNumTokens == 0)
  232. {
  233. // Empty query --- no information
  234. // ==============================
  235. paInfos = _new CClassInfoArray;
  236. if(paInfos == NULL)
  237. return WBEM_E_OUT_OF_MEMORY;
  238. paInfos->SetLimited(FALSE);
  239. return WBEM_S_NO_ERROR;
  240. }
  241. for(int i = 0; i < pExpr->nNumTokens; i++)
  242. {
  243. QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
  244. CClassInfoArray* paNew = _new CClassInfoArray;
  245. if(paNew == NULL)
  246. return WBEM_E_OUT_OF_MEMORY;
  247. CClassInfoArray* paFirst;
  248. CClassInfoArray* paSecond;
  249. switch(Token.nTokenType)
  250. {
  251. case QL1_OP_EXPRESSION:
  252. hres = GetInstanceClasses(Token, *paNew);
  253. InfoStack.push(paNew);
  254. break;
  255. case QL1_AND:
  256. if(InfoStack.size() < 2)
  257. {
  258. hres = WBEM_E_CRITICAL_ERROR;
  259. break;
  260. }
  261. paFirst = InfoStack.top(); InfoStack.pop();
  262. paSecond = InfoStack.top(); InfoStack.pop();
  263. hres = AndDefiniteClassArrays(paFirst, paSecond, paNew);
  264. InfoStack.push(paNew);
  265. delete paFirst;
  266. delete paSecond;
  267. break;
  268. case QL1_OR:
  269. if(InfoStack.size() < 2)
  270. {
  271. hres = WBEM_E_CRITICAL_ERROR;
  272. break;
  273. }
  274. paFirst = InfoStack.top(); InfoStack.pop();
  275. paSecond = InfoStack.top(); InfoStack.pop();
  276. hres = OrDefiniteClassArrays(paFirst, paSecond, paNew);
  277. InfoStack.push(paNew);
  278. delete paFirst;
  279. delete paSecond;
  280. break;
  281. case QL1_NOT:
  282. if(InfoStack.size() < 1)
  283. {
  284. hres = WBEM_E_CRITICAL_ERROR;
  285. break;
  286. }
  287. paFirst = InfoStack.top(); InfoStack.pop();
  288. hres = NegateDefiniteClassArray(paFirst, paNew);
  289. InfoStack.push(paNew);
  290. delete paFirst;
  291. break;
  292. default:
  293. hres = WBEM_E_CRITICAL_ERROR;
  294. delete paNew;
  295. }
  296. if(FAILED(hres))
  297. {
  298. // An error occurred, break out of the loop
  299. // ========================================
  300. break;
  301. }
  302. }
  303. if(SUCCEEDED(hres) && InfoStack.size() != 1)
  304. {
  305. hres = WBEM_E_CRITICAL_ERROR;
  306. }
  307. if(FAILED(hres))
  308. {
  309. // An error occurred. Clear the stack
  310. // ==================================
  311. while(!InfoStack.empty())
  312. {
  313. delete InfoStack.top();
  314. InfoStack.pop();
  315. }
  316. return hres;
  317. }
  318. // All is good
  319. // ===========
  320. paInfos = InfoStack.top();
  321. return S_OK;
  322. }
  323. HRESULT CQueryAnalyser::AndDefiniteClassArrays(IN CClassInfoArray* paFirst,
  324. IN CClassInfoArray* paSecond,
  325. OUT CClassInfoArray* paNew)
  326. {
  327. // Nothing is definite if both conditions have to hold
  328. // ===================================================
  329. paNew->Clear();
  330. paNew->SetLimited(TRUE);
  331. return WBEM_S_NO_ERROR;
  332. }
  333. HRESULT CQueryAnalyser::OrDefiniteClassArrays(IN CClassInfoArray* paFirst,
  334. IN CClassInfoArray* paSecond,
  335. OUT CClassInfoArray* paNew)
  336. {
  337. // Append them together
  338. // ====================
  339. paNew->Clear();
  340. if(paFirst->IsLimited() && paSecond->IsLimited())
  341. {
  342. paNew->SetLimited(TRUE);
  343. for(int i = 0; i < paFirst->GetNumClasses(); i++)
  344. {
  345. CClassInformation* pInfo =
  346. new CClassInformation(*paFirst->GetClass(i));
  347. if(pInfo == NULL)
  348. return WBEM_E_OUT_OF_MEMORY;
  349. if(!paNew->AddClass(pInfo))
  350. {
  351. delete pInfo;
  352. return WBEM_E_OUT_OF_MEMORY;
  353. }
  354. }
  355. for(i = 0; i < paSecond->GetNumClasses(); i++)
  356. {
  357. CClassInformation* pInfo =
  358. new CClassInformation(*paSecond->GetClass(i));
  359. if(pInfo == NULL)
  360. return WBEM_E_OUT_OF_MEMORY;
  361. if(!paNew->AddClass(pInfo))
  362. {
  363. delete pInfo;
  364. return WBEM_E_OUT_OF_MEMORY;
  365. }
  366. }
  367. }
  368. return WBEM_S_NO_ERROR;
  369. }
  370. HRESULT CQueryAnalyser::NegateDefiniteClassArray(IN CClassInfoArray* paOrig,
  371. OUT CClassInfoArray* paNew)
  372. {
  373. // No information
  374. // ==============
  375. paNew->Clear();
  376. paNew->SetLimited(TRUE);
  377. return WBEM_S_NO_ERROR;
  378. }
  379. HRESULT CQueryAnalyser::GetInstanceClasses(QL_LEVEL_1_TOKEN& Token,
  380. CClassInfoArray& aInfos)
  381. {
  382. // Preset aInfos to the "no information" value
  383. // ===========================================
  384. aInfos.Clear();
  385. // See if this token talks about TargetInstance or PreviousInstance
  386. // ================================================================
  387. if(Token.PropertyName.GetNumElements() < 1)
  388. return WBEM_S_NO_ERROR;
  389. LPCWSTR wszPrimaryName = Token.PropertyName.GetStringAt(0);
  390. if(wszPrimaryName == NULL ||
  391. (_wcsicmp(wszPrimaryName, TARGET_INSTANCE_PROPNAME) &&
  392. _wcsicmp(wszPrimaryName, PREVIOUS_INSTANCE_PROPNAME))
  393. )
  394. {
  395. // This token is irrelevant
  396. // =========================
  397. return WBEM_S_NO_ERROR;
  398. }
  399. // TargetInstance or PreviousInstance is found
  400. // ===========================================
  401. if(Token.PropertyName.GetNumElements() == 1)
  402. {
  403. // It's "TargetInstance <op> <const>" : look for ISA
  404. // =================================================
  405. if(Token.nOperator == QL1_OPERATOR_ISA &&
  406. V_VT(&Token.vConstValue) == VT_BSTR)
  407. {
  408. // Of this class; children included
  409. // ================================
  410. if(!aInfos.SetOne(V_BSTR(&Token.vConstValue), TRUE))
  411. return WBEM_E_OUT_OF_MEMORY;
  412. }
  413. else
  414. {
  415. // No information
  416. // ==============
  417. }
  418. return WBEM_S_NO_ERROR;
  419. }
  420. if(Token.PropertyName.GetNumElements() > 2)
  421. {
  422. // X.Y.Z --- too deep to be useful
  423. // ===============================
  424. return WBEM_S_NO_ERROR;
  425. }
  426. // It's "TargetInstance.X <op> <const>" : look for __CLASS
  427. // =======================================================
  428. LPCWSTR wszSecondaryName = Token.PropertyName.GetStringAt(1);
  429. if(wszSecondaryName == NULL || _wcsicmp(wszSecondaryName, L"__CLASS"))
  430. {
  431. // Not __CLASS --- not useful
  432. // ==========================
  433. return WBEM_S_NO_ERROR;
  434. }
  435. else
  436. {
  437. // __CLASS --- check that the operator is =
  438. // ========================================
  439. if(Token.nOperator == QL1_OPERATOR_EQUALS &&
  440. V_VT(&Token.vConstValue) == VT_BSTR)
  441. {
  442. // Of this class -- children not included
  443. // ======================================
  444. if(!aInfos.SetOne(V_BSTR(&Token.vConstValue), FALSE))
  445. return WBEM_E_OUT_OF_MEMORY;
  446. }
  447. return WBEM_S_NO_ERROR;
  448. }
  449. }
  450. HRESULT CQueryAnalyser::GetNecessaryQueryForProperty(
  451. IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
  452. IN CPropertyName& PropName,
  453. DELETE_ME QL_LEVEL_1_RPN_EXPRESSION*& pNewExpr)
  454. {
  455. pNewExpr = NULL;
  456. // Class name and selected properties are ignored; we look at tokens only
  457. // ======================================================================
  458. std::stack<QL_LEVEL_1_RPN_EXPRESSION*, std::deque<QL_LEVEL_1_RPN_EXPRESSION*,wbem_allocator<QL_LEVEL_1_RPN_EXPRESSION*> > > ExprStack;
  459. HRESULT hres = WBEM_S_NO_ERROR;
  460. // "Evaluate" the query
  461. // ====================
  462. if(pExpr->nNumTokens == 0)
  463. {
  464. // Empty query --- no information
  465. // ==============================
  466. pNewExpr = _new QL_LEVEL_1_RPN_EXPRESSION;
  467. if(pNewExpr == NULL)
  468. return WBEM_E_OUT_OF_MEMORY;
  469. return WBEM_S_NO_ERROR;
  470. }
  471. for(int i = 0; i < pExpr->nNumTokens; i++)
  472. {
  473. QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
  474. QL_LEVEL_1_RPN_EXPRESSION* pNew = _new QL_LEVEL_1_RPN_EXPRESSION;
  475. if(pNew == NULL)
  476. return WBEM_E_OUT_OF_MEMORY;
  477. QL_LEVEL_1_RPN_EXPRESSION* pFirst;
  478. QL_LEVEL_1_RPN_EXPRESSION* pSecond;
  479. switch(Token.nTokenType)
  480. {
  481. case QL1_OP_EXPRESSION:
  482. if(IsTokenAboutProperty(Token, PropName))
  483. {
  484. pNew->AddToken(Token);
  485. }
  486. ExprStack.push(pNew);
  487. break;
  488. case QL1_AND:
  489. if(ExprStack.size() < 2)
  490. {
  491. hres = WBEM_E_CRITICAL_ERROR;
  492. break;
  493. }
  494. pFirst = ExprStack.top(); ExprStack.pop();
  495. pSecond = ExprStack.top(); ExprStack.pop();
  496. hres = AndQueryExpressions(pFirst, pSecond, pNew);
  497. ExprStack.push(pNew);
  498. delete pFirst;
  499. delete pSecond;
  500. break;
  501. case QL1_OR:
  502. if(ExprStack.size() < 2)
  503. {
  504. hres = WBEM_E_CRITICAL_ERROR;
  505. break;
  506. }
  507. pFirst = ExprStack.top(); ExprStack.pop();
  508. pSecond = ExprStack.top(); ExprStack.pop();
  509. hres = OrQueryExpressions(pFirst, pSecond, pNew);
  510. ExprStack.push(pNew);
  511. delete pFirst;
  512. delete pSecond;
  513. break;
  514. case QL1_NOT:
  515. if(ExprStack.size() < 1)
  516. {
  517. hres = WBEM_E_CRITICAL_ERROR;
  518. break;
  519. }
  520. pFirst = ExprStack.top(); ExprStack.pop();
  521. // No information
  522. ExprStack.push(pNew);
  523. delete pFirst;
  524. break;
  525. default:
  526. hres = WBEM_E_CRITICAL_ERROR;
  527. delete pNew;
  528. }
  529. if(FAILED(hres))
  530. {
  531. // An error occurred, break out of the loop
  532. // ========================================
  533. break;
  534. }
  535. }
  536. if(SUCCEEDED(hres) && ExprStack.size() != 1)
  537. {
  538. hres = WBEM_E_CRITICAL_ERROR;
  539. }
  540. if(FAILED(hres))
  541. {
  542. // An error occurred. Clear the stack
  543. // ==================================
  544. while(!ExprStack.empty())
  545. {
  546. delete ExprStack.top();
  547. ExprStack.pop();
  548. }
  549. return hres;
  550. }
  551. // All is good
  552. // ===========
  553. pNewExpr = ExprStack.top();
  554. return S_OK;
  555. }
  556. BOOL CQueryAnalyser::IsTokenAboutProperty(
  557. IN QL_LEVEL_1_TOKEN& Token,
  558. IN CPropertyName& PropName)
  559. {
  560. CPropertyName& TokenPropName = Token.PropertyName;
  561. if(PropName.GetNumElements() != TokenPropName.GetNumElements())
  562. return FALSE;
  563. for(int i = 0; i < PropName.GetNumElements(); i++)
  564. {
  565. LPCWSTR wszPropElement = PropName.GetStringAt(i);
  566. LPCWSTR wszTokenElement = TokenPropName.GetStringAt(i);
  567. if(wszPropElement == NULL || wszTokenElement == NULL)
  568. return FALSE;
  569. if(_wcsicmp(wszPropElement, wszTokenElement))
  570. return FALSE;
  571. }
  572. return TRUE;
  573. }
  574. void CQueryAnalyser::AppendQueryExpression(
  575. IN QL_LEVEL_1_RPN_EXPRESSION* pDest,
  576. IN QL_LEVEL_1_RPN_EXPRESSION* pSource)
  577. {
  578. for(int i = 0; i < pSource->nNumTokens; i++)
  579. {
  580. pDest->AddToken(pSource->pArrayOfTokens[i]);
  581. }
  582. }
  583. HRESULT CQueryAnalyser::AndQueryExpressions(
  584. IN QL_LEVEL_1_RPN_EXPRESSION* pFirst,
  585. IN QL_LEVEL_1_RPN_EXPRESSION* pSecond,
  586. OUT QL_LEVEL_1_RPN_EXPRESSION* pNew)
  587. {
  588. // If either one is NULL (false), the result is NULL
  589. // =================================================
  590. if(pFirst == NULL || pSecond == NULL)
  591. return WBEM_S_FALSE;
  592. // If either one is empty, take the other
  593. // ======================================
  594. if(pFirst->nNumTokens == 0)
  595. {
  596. AppendQueryExpression(pNew, pSecond);
  597. return WBEM_S_NO_ERROR;
  598. }
  599. if(pSecond->nNumTokens == 0)
  600. {
  601. AppendQueryExpression(pNew, pFirst);
  602. return WBEM_S_NO_ERROR;
  603. }
  604. // Both are there --- and together
  605. // ===============================
  606. AppendQueryExpression(pNew, pFirst);
  607. AppendQueryExpression(pNew, pSecond);
  608. QL_LEVEL_1_TOKEN Token;
  609. Token.nTokenType = QL1_AND;
  610. pNew->AddToken(Token);
  611. return WBEM_S_NO_ERROR;
  612. }
  613. HRESULT CQueryAnalyser::OrQueryExpressions(
  614. IN QL_LEVEL_1_RPN_EXPRESSION* pFirst,
  615. IN QL_LEVEL_1_RPN_EXPRESSION* pSecond,
  616. OUT QL_LEVEL_1_RPN_EXPRESSION* pNew)
  617. {
  618. // If both are NULL (false) so is the result
  619. // =========================================
  620. if(pFirst == NULL && pSecond == NULL)
  621. return WBEM_S_FALSE;
  622. // If one is NULL (false) return the other
  623. // =======================================
  624. if(pFirst == NULL)
  625. {
  626. AppendQueryExpression(pNew, pSecond);
  627. return WBEM_S_NO_ERROR;
  628. }
  629. if(pSecond == NULL)
  630. {
  631. AppendQueryExpression(pNew, pFirst);
  632. return WBEM_S_NO_ERROR;
  633. }
  634. // If either one is empty, so is the result
  635. // ========================================
  636. if(pFirst->nNumTokens == 0 || pSecond->nNumTokens == 0)
  637. {
  638. return WBEM_S_NO_ERROR;
  639. }
  640. // Both are there --- or together
  641. // ==============================
  642. AppendQueryExpression(pNew, pFirst);
  643. AppendQueryExpression(pNew, pSecond);
  644. QL_LEVEL_1_TOKEN Token;
  645. Token.nTokenType = QL1_OR;
  646. pNew->AddToken(Token);
  647. return WBEM_S_NO_ERROR;
  648. }
  649. HRESULT CQueryAnalyser::GetPropertiesThatMustDiffer(
  650. IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
  651. IN CClassInformation& Info,
  652. CWStringArray& awsProperties)
  653. {
  654. HRESULT hres = WBEM_S_NO_ERROR;
  655. //
  656. // "Evaluate" the query, looking for
  657. // PreviousInstance.Prop != TargetInstance.Prop expressions
  658. //
  659. awsProperties.Empty();
  660. std::stack<CWStringArray*, std::deque<CWStringArray*,wbem_allocator<CWStringArray*> > > PropArrayStack;
  661. for(int i = 0; i < pExpr->nNumTokens; i++)
  662. {
  663. QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
  664. CWStringArray* pNew = NULL;
  665. CWStringArray* pFirst = NULL;
  666. CWStringArray* pSecond = NULL;
  667. switch(Token.nTokenType)
  668. {
  669. case QL1_OP_EXPRESSION:
  670. //
  671. // Check if this token conforms to the
  672. // PreviousInstance.Prop != TargetInstance.Prop format
  673. //
  674. if(Token.m_bPropComp &&
  675. (Token.nOperator == QL1_OPERATOR_NOTEQUALS ||
  676. Token.nOperator == QL1_OPERATOR_LESS ||
  677. Token.nOperator == QL1_OPERATOR_GREATER) &&
  678. Token.PropertyName.GetNumElements() == 2 &&
  679. Token.PropertyName2.GetNumElements() == 2)
  680. {
  681. //
  682. // Make sure that one of them is talking about TargetInstance,
  683. // and another about PreviousInstance.
  684. //
  685. bool bRightForm = false;
  686. if(!wbem_wcsicmp(Token.PropertyName.GetStringAt(0),
  687. L"TargetInstance") &&
  688. !wbem_wcsicmp(Token.PropertyName2.GetStringAt(0),
  689. L"PreviousInstance"))
  690. {
  691. bRightForm = true;
  692. }
  693. if(!wbem_wcsicmp(Token.PropertyName.GetStringAt(0),
  694. L"PreviousInstance") &&
  695. !wbem_wcsicmp(Token.PropertyName2.GetStringAt(0),
  696. L"TargetInstance"))
  697. {
  698. bRightForm = true;
  699. }
  700. if(bRightForm)
  701. {
  702. pNew = new CWStringArray;
  703. if(pNew == NULL)
  704. return WBEM_E_OUT_OF_MEMORY;
  705. pNew->Add(Token.PropertyName.GetStringAt(1));
  706. }
  707. }
  708. PropArrayStack.push(pNew);
  709. break;
  710. case QL1_AND:
  711. if(PropArrayStack.size() < 2)
  712. {
  713. hres = WBEM_E_CRITICAL_ERROR;
  714. break;
  715. }
  716. pFirst = PropArrayStack.top(); PropArrayStack.pop();
  717. pSecond = PropArrayStack.top(); PropArrayStack.pop();
  718. //
  719. // If either one of them is non-NULL, take either --- since every
  720. // array means "no unless one of these properties is different",
  721. // adding them together is at least as good as having one
  722. //
  723. if(pFirst)
  724. {
  725. pNew = pFirst;
  726. delete pSecond;
  727. }
  728. else
  729. pNew = pSecond;
  730. PropArrayStack.push(pNew);
  731. break;
  732. case QL1_OR:
  733. if(PropArrayStack.size() < 2)
  734. {
  735. hres = WBEM_E_CRITICAL_ERROR;
  736. break;
  737. }
  738. pFirst = PropArrayStack.top(); PropArrayStack.pop();
  739. pSecond = PropArrayStack.top(); PropArrayStack.pop();
  740. //
  741. // Concatenate them --- since every
  742. // array means "no unless one of these properties is different",
  743. // oring them together means "no unless one of the properties in
  744. // either list is different". If one is NULL, though, then we know
  745. // nothing
  746. //
  747. if(pFirst && pSecond)
  748. {
  749. pNew = new CWStringArray;
  750. if(pNew == NULL)
  751. return WBEM_E_OUT_OF_MEMORY;
  752. CWStringArray::Union(*pFirst, *pSecond, *pNew);
  753. }
  754. PropArrayStack.push(pNew);
  755. delete pFirst;
  756. delete pSecond;
  757. break;
  758. case QL1_NOT:
  759. if(PropArrayStack.size() < 1)
  760. {
  761. hres = WBEM_E_CRITICAL_ERROR;
  762. break;
  763. }
  764. pFirst = PropArrayStack.top(); PropArrayStack.pop();
  765. // No information
  766. PropArrayStack.push(pNew);
  767. delete pFirst;
  768. break;
  769. default:
  770. hres = WBEM_E_CRITICAL_ERROR;
  771. delete pNew;
  772. }
  773. if(FAILED(hres))
  774. {
  775. // An error occurred, break out of the loop
  776. // ========================================
  777. break;
  778. }
  779. }
  780. if( SUCCEEDED(hres))
  781. {
  782. if( PropArrayStack.size() > 0 && PropArrayStack.top() )
  783. awsProperties = *PropArrayStack.top();
  784. else
  785. return WBEM_S_FALSE;
  786. }
  787. while(!PropArrayStack.empty())
  788. {
  789. delete PropArrayStack.top();
  790. PropArrayStack.pop();
  791. }
  792. return hres;
  793. }
  794. HRESULT CQueryAnalyser::GetLimitingQueryForInstanceClass(
  795. IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
  796. IN CClassInformation& Info,
  797. OUT DELETE_ME LPWSTR& wszQuery)
  798. {
  799. HRESULT hres;
  800. //
  801. // "Evaluate" the query, looking for keys and other properties that do not
  802. // change over the life time of an instance (marked as [fixed]). The idea
  803. // here is that if an instance creation/deletion/modification subscription
  804. // is issue and we need to poll, we can only utilize the parts of the WHERE
  805. // clause that talk about the properties that cannot change during the life
  806. // of an instance. Otherwise, we will not be able to tell if an instance
  807. // changed or was created or deleted (when it walks in or out of our polling
  808. // results.
  809. //
  810. // The way we know that a property is such is if it is marked as [key], or
  811. // if it is marked as [fixed] --- the designation by the schema creator that
  812. // the property never changes.
  813. //
  814. //
  815. // Construct an array of all those property names
  816. //
  817. _IWmiObject* pClass = NULL;
  818. hres = Info.m_pClass->QueryInterface(IID__IWmiObject, (void**)&pClass);
  819. if(FAILED(hres))
  820. return WBEM_E_CRITICAL_ERROR;
  821. CReleaseMe rm1(pClass);
  822. CWStringArray awsFixed;
  823. hres = pClass->BeginEnumeration(0);
  824. if(FAILED(hres))
  825. return hres;
  826. BSTR strPropName = NULL;
  827. while((hres = pClass->Next(0, &strPropName, NULL, NULL, NULL)) == S_OK)
  828. {
  829. CSysFreeMe sfm(strPropName);
  830. //
  831. // Check qualifiers
  832. //
  833. DWORD dwSize;
  834. hres = pClass->GetPropQual(strPropName, L"key", 0, 0, NULL,
  835. NULL, &dwSize, NULL);
  836. if(SUCCEEDED(hres) || hres == WBEM_E_BUFFER_TOO_SMALL)
  837. {
  838. awsFixed.Add(strPropName);
  839. }
  840. else if(hres != WBEM_E_NOT_FOUND)
  841. {
  842. return hres;
  843. }
  844. hres = pClass->GetPropQual(strPropName, L"fixed", 0, 0, NULL,
  845. NULL, &dwSize, NULL);
  846. if(SUCCEEDED(hres) || hres == WBEM_E_BUFFER_TOO_SMALL)
  847. {
  848. awsFixed.Add(strPropName);
  849. }
  850. else if(hres != WBEM_E_NOT_FOUND)
  851. {
  852. return hres;
  853. }
  854. }
  855. pClass->EndEnumeration();
  856. if(FAILED(hres))
  857. return hres;
  858. //
  859. // Now "evaluate" the query
  860. //
  861. std::stack<QL_LEVEL_1_RPN_EXPRESSION*, std::deque<QL_LEVEL_1_RPN_EXPRESSION*,wbem_allocator<QL_LEVEL_1_RPN_EXPRESSION*> > > ExprStack;
  862. for(int i = 0; i < pExpr->nNumTokens; i++)
  863. {
  864. QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
  865. QL_LEVEL_1_RPN_EXPRESSION* pNew = _new QL_LEVEL_1_RPN_EXPRESSION;
  866. if(pNew == NULL)
  867. return WBEM_E_OUT_OF_MEMORY;
  868. QL_LEVEL_1_RPN_EXPRESSION* pFirst;
  869. QL_LEVEL_1_RPN_EXPRESSION* pSecond;
  870. switch(Token.nTokenType)
  871. {
  872. case QL1_OP_EXPRESSION:
  873. if(Token.PropertyName.GetNumElements() > 1 &&
  874. awsFixed.FindStr(Token.PropertyName.GetStringAt(1),
  875. CWStringArray::no_case) != CWStringArray::not_found)
  876. {
  877. //
  878. // This token is about a fixed property --- we can keep it
  879. //
  880. QL_LEVEL_1_TOKEN NewToken = Token;
  881. NewToken.PropertyName.Empty();
  882. NewToken.PropertyName.AddElement(
  883. Token.PropertyName.GetStringAt(1));
  884. pNew->AddToken(NewToken);
  885. }
  886. ExprStack.push(pNew);
  887. break;
  888. case QL1_AND:
  889. if(ExprStack.size() < 2)
  890. {
  891. hres = WBEM_E_CRITICAL_ERROR;
  892. break;
  893. }
  894. pFirst = ExprStack.top(); ExprStack.pop();
  895. pSecond = ExprStack.top(); ExprStack.pop();
  896. hres = AndQueryExpressions(pFirst, pSecond, pNew);
  897. ExprStack.push(pNew);
  898. delete pFirst;
  899. delete pSecond;
  900. break;
  901. case QL1_OR:
  902. if(ExprStack.size() < 2)
  903. {
  904. hres = WBEM_E_CRITICAL_ERROR;
  905. break;
  906. }
  907. pFirst = ExprStack.top(); ExprStack.pop();
  908. pSecond = ExprStack.top(); ExprStack.pop();
  909. hres = OrQueryExpressions(pFirst, pSecond, pNew);
  910. ExprStack.push(pNew);
  911. delete pFirst;
  912. delete pSecond;
  913. break;
  914. case QL1_NOT:
  915. if(ExprStack.size() < 1)
  916. {
  917. hres = WBEM_E_CRITICAL_ERROR;
  918. break;
  919. }
  920. pFirst = ExprStack.top(); ExprStack.pop();
  921. // No information
  922. ExprStack.push(pNew);
  923. delete pFirst;
  924. break;
  925. default:
  926. hres = WBEM_E_CRITICAL_ERROR;
  927. delete pNew;
  928. }
  929. if(FAILED(hres))
  930. {
  931. // An error occurred, break out of the loop
  932. // ========================================
  933. break;
  934. }
  935. }
  936. if(FAILED(hres))
  937. {
  938. //
  939. // An error occurred. Clear the stack
  940. //
  941. while(!ExprStack.empty())
  942. {
  943. delete ExprStack.top();
  944. ExprStack.pop();
  945. }
  946. return hres;
  947. }
  948. QL_LEVEL_1_RPN_EXPRESSION* pNewExpr = NULL;
  949. if(ExprStack.size() != 0)
  950. {
  951. pNewExpr = ExprStack.top();
  952. }
  953. else
  954. {
  955. pNewExpr = new QL_LEVEL_1_RPN_EXPRESSION;
  956. if(pNewExpr == NULL)
  957. return WBEM_E_OUT_OF_MEMORY;
  958. }
  959. CDeleteMe<QL_LEVEL_1_RPN_EXPRESSION> dm1(pNewExpr);
  960. //
  961. // Figure out the list of property names
  962. //
  963. bool bMayLimit;
  964. if(pExpr->bStar)
  965. {
  966. bMayLimit = false;
  967. }
  968. else if(wbem_wcsicmp(pExpr->bsClassName, L"__InstanceCreationEvent") &&
  969. wbem_wcsicmp(pExpr->bsClassName, L"__InstanceDeletionEvent"))
  970. {
  971. //
  972. // Instance modification events are included. That means we need
  973. // to get enough properties from the provider to be able to compare
  974. // instances for changes. Check if this list is smaller than
  975. // everything
  976. //
  977. CWStringArray awsProperties;
  978. hres = GetPropertiesThatMustDiffer(pExpr, Info, awsProperties);
  979. if(hres == S_OK)
  980. {
  981. //
  982. // Got our list --- add it to the properties to get
  983. //
  984. for(int i = 0; i < awsProperties.Size(); i++)
  985. {
  986. CPropertyName NewProp;
  987. NewProp.AddElement(awsProperties[i]);
  988. pNewExpr->AddProperty(NewProp);
  989. }
  990. bMayLimit = true;
  991. }
  992. else
  993. bMayLimit = false;
  994. }
  995. else
  996. {
  997. //
  998. // No * in select and no modification events asked for --- limit
  999. //
  1000. bMayLimit = true;
  1001. }
  1002. if(bMayLimit)
  1003. {
  1004. //
  1005. // Add RELPATH and DERIVATION, for without them filtering is hard
  1006. //
  1007. CPropertyName NewProp;
  1008. NewProp.AddElement(L"__RELPATH");
  1009. pNewExpr->AddProperty(NewProp);
  1010. NewProp.Empty();
  1011. NewProp.AddElement(L"__DERIVATION");
  1012. pNewExpr->AddProperty(NewProp);
  1013. //
  1014. // Add all the proeperties from the select clause, with
  1015. // TargetInstance and PreviousInstance removed
  1016. //
  1017. for(int i = 0; i < pExpr->nNumberOfProperties; i++)
  1018. {
  1019. CPropertyName& Prop = pExpr->pRequestedPropertyNames[i];
  1020. if(Prop.GetNumElements() > 1)
  1021. {
  1022. //
  1023. // Embedded object property --- add it to the list
  1024. //
  1025. CPropertyName LocalProp;
  1026. LocalProp.AddElement(Prop.GetStringAt(1));
  1027. pNewExpr->AddProperty(LocalProp);
  1028. }
  1029. }
  1030. //
  1031. // Add all the properties from the where clause, on both sides of
  1032. // the comparison
  1033. //
  1034. for(i = 0; i < pExpr->nNumTokens; i++)
  1035. {
  1036. QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
  1037. CPropertyName& Prop = Token.PropertyName;
  1038. if(Prop.GetNumElements() > 1)
  1039. {
  1040. //
  1041. // Embedded object property --- add it to the list
  1042. //
  1043. CPropertyName LocalProp;
  1044. LocalProp.AddElement(Prop.GetStringAt(1));
  1045. pNewExpr->AddProperty(LocalProp);
  1046. }
  1047. if(Token.m_bPropComp)
  1048. {
  1049. CPropertyName& Prop2 = Token.PropertyName2;
  1050. if(Prop2.GetNumElements() > 1)
  1051. {
  1052. //
  1053. // Embedded object property --- add it to the list
  1054. //
  1055. CPropertyName LocalProp;
  1056. LocalProp.AddElement(Prop2.GetStringAt(1));
  1057. pNewExpr->AddProperty(LocalProp);
  1058. }
  1059. }
  1060. }
  1061. }
  1062. else
  1063. {
  1064. //
  1065. // May not limit the set of properties to ask for
  1066. //
  1067. pNewExpr->bStar = TRUE;
  1068. }
  1069. //
  1070. // Set the class name
  1071. //
  1072. pNewExpr->SetClassName(Info.m_wszClassName);
  1073. //
  1074. // Produce the text
  1075. //
  1076. wszQuery = pNewExpr->GetText();
  1077. if(wszQuery == NULL)
  1078. return WBEM_E_OUT_OF_MEMORY;
  1079. return WBEM_S_NO_ERROR;
  1080. }
  1081. BOOL CQueryAnalyser::CompareRequestedToProvided(
  1082. CClassInfoArray& aRequestedInstanceClasses,
  1083. CClassInfoArray& aProvidedInstanceClasses)
  1084. {
  1085. if(!aRequestedInstanceClasses.IsLimited() ||
  1086. !aProvidedInstanceClasses.IsLimited())
  1087. {
  1088. // Provided provides all or client wants all --- they intersect.
  1089. // =============================================================
  1090. return TRUE;
  1091. }
  1092. for(int nReqIndex = 0;
  1093. nReqIndex < aRequestedInstanceClasses.GetNumClasses();
  1094. nReqIndex++)
  1095. {
  1096. CClassInformation* pRequestedClass =
  1097. aRequestedInstanceClasses.GetClass(nReqIndex);
  1098. LPWSTR wszRequestedClass = pRequestedClass->m_wszClassName;
  1099. for(int nProvIndex = 0;
  1100. nProvIndex < aProvidedInstanceClasses.GetNumClasses();
  1101. nProvIndex++)
  1102. {
  1103. // Check if this provided class is derived from the requested one
  1104. // ==============================================================
  1105. CClassInformation* pProvClass =
  1106. aProvidedInstanceClasses.GetClass(nProvIndex);
  1107. if(pProvClass->m_pClass != NULL &&
  1108. (pProvClass->m_pClass->InheritsFrom(pRequestedClass->m_wszClassName) == S_OK ||
  1109. pRequestedClass->m_pClass->InheritsFrom(pProvClass->m_wszClassName) == S_OK)
  1110. )
  1111. {
  1112. return TRUE;
  1113. }
  1114. }
  1115. }
  1116. return FALSE;
  1117. }
  1118. HRESULT CQueryAnalyser::NegateQueryExpression(
  1119. IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
  1120. OUT QL_LEVEL_1_RPN_EXPRESSION* pNewExpr)
  1121. {
  1122. if(pExpr == NULL)
  1123. {
  1124. // pNewExpr is empty --- true
  1125. return WBEM_S_NO_ERROR;
  1126. }
  1127. if(pExpr->nNumTokens == 0)
  1128. {
  1129. return WBEM_S_FALSE;
  1130. }
  1131. AppendQueryExpression(pNewExpr, pExpr);
  1132. QL_LEVEL_1_TOKEN Token;
  1133. Token.nTokenType = QL1_NOT;
  1134. pNewExpr->AddToken(Token);
  1135. return WBEM_S_NO_ERROR;
  1136. }
  1137. HRESULT CQueryAnalyser::SimplifyQueryForChild(
  1138. IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
  1139. LPCWSTR wszClassName, IWbemClassObject* pClass,
  1140. CContextMetaData* pMeta,
  1141. DELETE_ME QL_LEVEL_1_RPN_EXPRESSION*& pNewExpr)
  1142. {
  1143. pNewExpr = NULL;
  1144. std::stack<QL_LEVEL_1_RPN_EXPRESSION*, std::deque<QL_LEVEL_1_RPN_EXPRESSION*,wbem_allocator<QL_LEVEL_1_RPN_EXPRESSION*> > > ExprStack;
  1145. HRESULT hres = WBEM_S_NO_ERROR;
  1146. // "Evaluate" the query
  1147. // ====================
  1148. if(pExpr->nNumTokens == 0)
  1149. {
  1150. // Empty query --- no information
  1151. // ==============================
  1152. pNewExpr = _new QL_LEVEL_1_RPN_EXPRESSION;
  1153. if(pNewExpr == NULL)
  1154. return WBEM_E_OUT_OF_MEMORY;
  1155. return WBEM_S_NO_ERROR;
  1156. }
  1157. for(int i = 0; i < pExpr->nNumTokens; i++)
  1158. {
  1159. QL_LEVEL_1_TOKEN Token = pExpr->pArrayOfTokens[i];
  1160. QL_LEVEL_1_RPN_EXPRESSION* pNew = _new QL_LEVEL_1_RPN_EXPRESSION;
  1161. if(pNew == NULL)
  1162. return WBEM_E_OUT_OF_MEMORY;
  1163. QL_LEVEL_1_RPN_EXPRESSION* pFirst;
  1164. QL_LEVEL_1_RPN_EXPRESSION* pSecond;
  1165. int nDisposition;
  1166. switch(Token.nTokenType)
  1167. {
  1168. case QL1_OP_EXPRESSION:
  1169. nDisposition = SimplifyTokenForChild(Token, wszClassName, pClass,
  1170. pMeta);
  1171. if(nDisposition == e_Keep)
  1172. {
  1173. pNew->AddToken(Token);
  1174. }
  1175. else if(nDisposition == e_True)
  1176. {
  1177. }
  1178. else if(nDisposition == e_False)
  1179. {
  1180. delete pNew;
  1181. pNew = NULL;
  1182. }
  1183. else
  1184. {
  1185. // the whole thing is invalid
  1186. hres = WBEM_E_INVALID_QUERY;
  1187. delete pNew;
  1188. break;
  1189. }
  1190. ExprStack.push(pNew);
  1191. break;
  1192. case QL1_AND:
  1193. if(ExprStack.size() < 2)
  1194. {
  1195. hres = WBEM_E_CRITICAL_ERROR;
  1196. break;
  1197. }
  1198. pFirst = ExprStack.top(); ExprStack.pop();
  1199. pSecond = ExprStack.top(); ExprStack.pop();
  1200. hres = AndQueryExpressions(pFirst, pSecond, pNew);
  1201. if(hres != S_OK)
  1202. {
  1203. delete pNew;
  1204. pNew = NULL;
  1205. }
  1206. ExprStack.push(pNew);
  1207. delete pFirst;
  1208. delete pSecond;
  1209. break;
  1210. case QL1_OR:
  1211. if(ExprStack.size() < 2)
  1212. {
  1213. hres = WBEM_E_CRITICAL_ERROR;
  1214. break;
  1215. }
  1216. pFirst = ExprStack.top(); ExprStack.pop();
  1217. pSecond = ExprStack.top(); ExprStack.pop();
  1218. hres = OrQueryExpressions(pFirst, pSecond, pNew);
  1219. if(hres != S_OK)
  1220. {
  1221. delete pNew;
  1222. pNew = NULL;
  1223. }
  1224. ExprStack.push(pNew);
  1225. delete pFirst;
  1226. delete pSecond;
  1227. break;
  1228. case QL1_NOT:
  1229. if(ExprStack.size() < 1)
  1230. {
  1231. hres = WBEM_E_CRITICAL_ERROR;
  1232. break;
  1233. }
  1234. pFirst = ExprStack.top(); ExprStack.pop();
  1235. hres = NegateQueryExpression(pFirst, pNew);
  1236. if(hres != S_OK)
  1237. {
  1238. delete pNew;
  1239. pNew = NULL;
  1240. }
  1241. ExprStack.push(pNew);
  1242. delete pFirst;
  1243. break;
  1244. default:
  1245. hres = WBEM_E_CRITICAL_ERROR;
  1246. delete pNew;
  1247. }
  1248. if(FAILED(hres))
  1249. {
  1250. // An error occurred, break out of the loop
  1251. // ========================================
  1252. break;
  1253. }
  1254. }
  1255. if(SUCCEEDED(hres) && ExprStack.size() != 1)
  1256. {
  1257. hres = WBEM_E_CRITICAL_ERROR;
  1258. }
  1259. if(FAILED(hres))
  1260. {
  1261. // An error occurred. Clear the stack
  1262. // ==================================
  1263. while(!ExprStack.empty())
  1264. {
  1265. delete ExprStack.top();
  1266. ExprStack.pop();
  1267. }
  1268. return hres;
  1269. }
  1270. // All is good
  1271. // ===========
  1272. pNewExpr = ExprStack.top();
  1273. return S_OK;
  1274. }
  1275. int CQueryAnalyser::SimplifyTokenForChild(QL_LEVEL_1_TOKEN& Token,
  1276. LPCWSTR wszClassName, IWbemClassObject* pClass,
  1277. CContextMetaData* pMeta)
  1278. {
  1279. HRESULT hres;
  1280. //
  1281. // Check if the main property exists
  1282. //
  1283. CIMTYPE ct;
  1284. hres = pClass->Get((LPWSTR)Token.PropertyName.GetStringAt(0), 0, NULL,
  1285. &ct, NULL);
  1286. if(FAILED(hres))
  1287. {
  1288. return e_Invalid;
  1289. }
  1290. //
  1291. // Check if it is complex
  1292. //
  1293. if(Token.PropertyName.GetNumElements() > 1 && ct != CIM_OBJECT)
  1294. return e_Invalid;
  1295. //
  1296. // Check if it's an array
  1297. //
  1298. if(ct & CIM_FLAG_ARRAY)
  1299. return e_Invalid;
  1300. //
  1301. // If a CIM DateTime type, normalize it to have a zero UTC offset. Helps
  1302. // providers to cope.
  1303. //
  1304. if (ct == CIM_DATETIME && Token.m_bPropComp == FALSE && V_VT(&Token.vConstValue) == VT_BSTR)
  1305. {
  1306. BSTR strSource = V_BSTR(&Token.vConstValue);
  1307. if (strSource && wcslen(strSource))
  1308. {
  1309. BSTR strAdjusted = 0;
  1310. BOOL bRes = NormalizeCimDateTime(strSource, &strAdjusted);
  1311. if (bRes)
  1312. {
  1313. SysFreeString(strSource);
  1314. V_BSTR(&Token.vConstValue) = strAdjusted;
  1315. }
  1316. }
  1317. }
  1318. //
  1319. // Check operator validity for this type
  1320. //
  1321. //
  1322. // Ensure that only valid operators are applied to boolean props.
  1323. //
  1324. if(ct == CIM_BOOLEAN && (Token.nOperator != QL_LEVEL_1_TOKEN::OP_EQUAL &&
  1325. Token.nOperator != QL_LEVEL_1_TOKEN::OP_NOT_EQUAL))
  1326. return e_Invalid;
  1327. //
  1328. // Ensure that only valid operators are applied to reference props.
  1329. //
  1330. if(ct == CIM_REFERENCE && (Token.nOperator != QL_LEVEL_1_TOKEN::OP_EQUAL &&
  1331. Token.nOperator != QL_LEVEL_1_TOKEN::OP_NOT_EQUAL))
  1332. return e_Invalid;
  1333. if(Token.m_bPropComp)
  1334. {
  1335. //
  1336. // Check if the other property exists
  1337. //
  1338. CIMTYPE ct2;
  1339. hres = pClass->Get((LPWSTR)Token.PropertyName2.GetStringAt(0), 0, NULL,
  1340. &ct2, NULL);
  1341. if(FAILED(hres))
  1342. {
  1343. return e_Invalid;
  1344. }
  1345. //
  1346. // Check if it is complex
  1347. //
  1348. if(Token.PropertyName2.GetNumElements() > 1 && ct2 != CIM_OBJECT)
  1349. return e_Invalid;
  1350. //
  1351. // Check if it's an array
  1352. //
  1353. if(ct2 & CIM_FLAG_ARRAY)
  1354. return e_Invalid;
  1355. //
  1356. // Nothing else to say about prop-to-ptop
  1357. //
  1358. return e_Keep;
  1359. }
  1360. //
  1361. // Check if the value is NULL
  1362. //
  1363. if(V_VT(&Token.vConstValue) == VT_NULL)
  1364. {
  1365. if(Token.nOperator != QL1_OPERATOR_EQUALS &&
  1366. Token.nOperator != QL1_OPERATOR_NOTEQUALS)
  1367. {
  1368. return e_Invalid;
  1369. }
  1370. else
  1371. {
  1372. return e_Keep;
  1373. }
  1374. }
  1375. if(ct == CIM_OBJECT)
  1376. return e_Keep;
  1377. // For boolean props ensure that only 1 or 0 or (-1, 0xFFFF [VARIANT_TRUE])
  1378. // are used as numeric tests.
  1379. // ========================================================================
  1380. if (ct == CIM_BOOLEAN && V_VT(&Token.vConstValue) == VT_I4)
  1381. {
  1382. int n = V_I4(&Token.vConstValue);
  1383. if (n != 0 && n != 1 && n != -1 && n != 0xFFFF)
  1384. return e_Invalid;
  1385. }
  1386. //
  1387. // If the constant is a real and the target is an integer, then fail the
  1388. // query
  1389. //
  1390. if((V_VT(&Token.vConstValue) == VT_R8 || V_VT(&Token.vConstValue) == VT_R4 ) &&
  1391. (ct == CIM_CHAR16 || ct == CIM_UINT8 || ct == CIM_SINT8 ||
  1392. ct == CIM_UINT16 || ct == CIM_SINT16 || ct == CIM_UINT32 ||
  1393. ct == CIM_SINT32 || ct == CIM_UINT64 || ct == CIM_SINT64))
  1394. return e_Invalid;
  1395. // Convert the constant to the right type
  1396. // ======================================
  1397. if(ct == CIM_CHAR16 && V_VT(&Token.vConstValue) == VT_BSTR)
  1398. {
  1399. BSTR str = V_BSTR(&Token.vConstValue);
  1400. if(wcslen(str) != 1)
  1401. return e_Invalid;
  1402. return e_Keep;
  1403. }
  1404. VARTYPE vt = CType::GetVARTYPE(ct);
  1405. if(ct == CIM_UINT32)
  1406. vt = CIM_STRING;
  1407. if(FAILED(VariantChangeType(&Token.vConstValue, &Token.vConstValue, 0, vt)))
  1408. {
  1409. return e_Invalid;
  1410. }
  1411. // Verify ranges
  1412. // =============
  1413. __int64 i64;
  1414. unsigned __int64 ui64;
  1415. switch(ct)
  1416. {
  1417. case CIM_UINT8:
  1418. break;
  1419. case CIM_SINT8:
  1420. if(V_I2(&Token.vConstValue) < -128 || V_I2(&Token.vConstValue) > 127)
  1421. return e_Invalid;
  1422. break;
  1423. case CIM_UINT16:
  1424. if(V_I4(&Token.vConstValue) < 0 || V_I4(&Token.vConstValue) >= 1<<16)
  1425. return e_Invalid;
  1426. break;
  1427. case CIM_SINT16:
  1428. break;
  1429. case CIM_SINT32:
  1430. break;
  1431. case CIM_UINT32:
  1432. if(!ReadI64(V_BSTR(&Token.vConstValue), i64))
  1433. return e_Invalid;
  1434. if(i64 < 0 || i64 >= (__int64)1 << 32)
  1435. return e_Invalid;
  1436. break;
  1437. case CIM_UINT64:
  1438. if(!ReadUI64(V_BSTR(&Token.vConstValue), ui64))
  1439. return e_Invalid;
  1440. break;
  1441. case CIM_SINT64:
  1442. if(!ReadI64(V_BSTR(&Token.vConstValue), i64))
  1443. return e_Invalid;
  1444. break;
  1445. case CIM_REAL32:
  1446. case CIM_REAL64:
  1447. break;
  1448. case CIM_STRING:
  1449. break;
  1450. case CIM_DATETIME:
  1451. if(!ValidateSQLDateTime(V_BSTR(&Token.vConstValue)))
  1452. return e_Invalid;
  1453. case CIM_REFERENCE:
  1454. break;
  1455. }
  1456. // Check if it is a reference
  1457. // ==========================
  1458. if(ct != CIM_REFERENCE)
  1459. return e_Keep;
  1460. // Reference. Parse the path in the value
  1461. // ======================================
  1462. if(V_VT(&Token.vConstValue) != VT_BSTR)
  1463. return e_Keep;
  1464. CObjectPathParser Parser;
  1465. ParsedObjectPath* pOutput = NULL;
  1466. int nRes = Parser.Parse(V_BSTR(&Token.vConstValue), &pOutput);
  1467. if(nRes != CObjectPathParser::NoError)
  1468. return e_Invalid;
  1469. WString wsPathClassName = pOutput->m_pClass;
  1470. BOOL bInstance = (pOutput->m_bSingletonObj || pOutput->m_dwNumKeys != 0);
  1471. // TBD: analyse the path for validity
  1472. delete pOutput;
  1473. hres = CanPointToClass(pClass, (LPWSTR)Token.PropertyName.GetStringAt(0),
  1474. wsPathClassName, pMeta);
  1475. if(FAILED(hres))
  1476. return e_Invalid;
  1477. else if(hres == WBEM_S_NO_ERROR)
  1478. return e_Keep;
  1479. else
  1480. {
  1481. // Equality can never be achieved. The token is either always true,
  1482. // or always false, depending on the operator
  1483. if(Token.nOperator == QL1_OPERATOR_EQUALS)
  1484. return e_False;
  1485. else
  1486. return e_True;
  1487. }
  1488. }
  1489. BOOL CQueryAnalyser::ValidateSQLDateTime(LPCWSTR wszDateTime)
  1490. {
  1491. #ifndef UNICODE
  1492. char* szBuffer = new char[wcslen(wszDateTime)*4+1];
  1493. if(szBuffer == NULL)
  1494. return FALSE;
  1495. sprintf(szBuffer, "%S", wszDateTime);
  1496. CDateTimeParser dtParser(szBuffer);
  1497. delete [] szBuffer;
  1498. #else
  1499. CDateTimeParser dtParser(wszDateTime);
  1500. #endif
  1501. if(!dtParser.IsValidDateTime())
  1502. return FALSE;
  1503. WCHAR wszDMTF[26];
  1504. dtParser.FillDMTF(wszDMTF);
  1505. CWbemTime wt;
  1506. if(!wt.SetDMTF(wszDMTF))
  1507. return FALSE;
  1508. return TRUE;
  1509. }
  1510. HRESULT CQueryAnalyser::CanPointToClass(IWbemClassObject* pRefClass,
  1511. LPCWSTR wszPropName, LPCWSTR wszTargetClassName,
  1512. CContextMetaData* pMeta)
  1513. {
  1514. // Check if the reference is typed
  1515. // ===============================
  1516. IWbemQualifierSet* pSet;
  1517. if(FAILED(pRefClass->GetPropertyQualifierSet((LPWSTR)wszPropName, &pSet)))
  1518. {
  1519. return WBEM_E_INVALID_PROPERTY;
  1520. }
  1521. VARIANT v;
  1522. HRESULT hres;
  1523. hres = pSet->Get(L"cimtype", 0, &v, NULL);
  1524. pSet->Release();
  1525. if(FAILED(hres) || V_VT(&v) != VT_BSTR)
  1526. return WBEM_E_INVALID_PROPERTY;
  1527. CClearMe cm(&v);
  1528. if(wbem_wcsicmp(V_BSTR(&v), L"ref") == 0)
  1529. return WBEM_S_NO_ERROR; // can point to anything
  1530. WString wsPropClassName = V_BSTR(&v) + 4;
  1531. // Reference is strongly typed.
  1532. // ============================
  1533. if(!_wcsicmp(wsPropClassName, wszTargetClassName))
  1534. return WBEM_S_NO_ERROR;
  1535. // Retrieve class def
  1536. // ==================
  1537. _IWmiObject* pPropClass = NULL;
  1538. hres = pMeta->GetClass(wsPropClassName, &pPropClass);
  1539. if(FAILED(hres))
  1540. return hres;
  1541. CReleaseMe rm1((IWbemClassObject*)pPropClass);
  1542. // Make sure that the class in the reference is related to our cimtype
  1543. // ===================================================================
  1544. if(pPropClass->InheritsFrom((LPWSTR)wszTargetClassName) != S_OK)
  1545. {
  1546. // Get the class in the path to see if it inherits from us
  1547. // =======================================================
  1548. _IWmiObject* pPathClass = NULL;
  1549. hres = pMeta->GetClass(wszTargetClassName, &pPathClass);
  1550. if(FAILED(hres))
  1551. return hres;
  1552. hres = pPathClass->InheritsFrom(wsPropClassName);
  1553. pPathClass->Release();
  1554. if(hres != S_OK)
  1555. {
  1556. return WBEM_S_FALSE;
  1557. }
  1558. }
  1559. return WBEM_S_NO_ERROR;
  1560. }
  1561. HRESULT CQueryAnalyser::GetNecessaryQueryForClass(
  1562. IN QL_LEVEL_1_RPN_EXPRESSION* pExpr,
  1563. IWbemClassObject* pClass,
  1564. CWStringArray& awsOverriden,
  1565. DELETE_ME QL_LEVEL_1_RPN_EXPRESSION*& pNewExpr)
  1566. {
  1567. pNewExpr = NULL;
  1568. // Class name and selected properties are ignored; we look at tokens only
  1569. // ======================================================================
  1570. std::stack<QL_LEVEL_1_RPN_EXPRESSION*, std::deque<QL_LEVEL_1_RPN_EXPRESSION*,wbem_allocator<QL_LEVEL_1_RPN_EXPRESSION*> > > ExprStack;
  1571. HRESULT hres = WBEM_S_NO_ERROR;
  1572. // "Evaluate" the query
  1573. // ====================
  1574. for(int i = 0; i < pExpr->nNumTokens; i++)
  1575. {
  1576. QL_LEVEL_1_TOKEN& Token = pExpr->pArrayOfTokens[i];
  1577. QL_LEVEL_1_RPN_EXPRESSION* pNew = _new QL_LEVEL_1_RPN_EXPRESSION;
  1578. if(pNew == NULL)
  1579. return WBEM_E_OUT_OF_MEMORY;
  1580. QL_LEVEL_1_RPN_EXPRESSION* pFirst;
  1581. QL_LEVEL_1_RPN_EXPRESSION* pSecond;
  1582. switch(Token.nTokenType)
  1583. {
  1584. case QL1_OP_EXPRESSION:
  1585. if(IsTokenAboutClass(Token, pClass, awsOverriden))
  1586. {
  1587. pNew->AddToken(Token);
  1588. }
  1589. ExprStack.push(pNew);
  1590. break;
  1591. case QL1_AND:
  1592. if(ExprStack.size() < 2)
  1593. {
  1594. hres = WBEM_E_CRITICAL_ERROR;
  1595. break;
  1596. }
  1597. pFirst = ExprStack.top(); ExprStack.pop();
  1598. pSecond = ExprStack.top(); ExprStack.pop();
  1599. hres = AndQueryExpressions(pFirst, pSecond, pNew);
  1600. ExprStack.push(pNew);
  1601. delete pFirst;
  1602. delete pSecond;
  1603. break;
  1604. case QL1_OR:
  1605. if(ExprStack.size() < 2)
  1606. {
  1607. hres = WBEM_E_CRITICAL_ERROR;
  1608. break;
  1609. }
  1610. pFirst = ExprStack.top(); ExprStack.pop();
  1611. pSecond = ExprStack.top(); ExprStack.pop();
  1612. hres = OrQueryExpressions(pFirst, pSecond, pNew);
  1613. ExprStack.push(pNew);
  1614. delete pFirst;
  1615. delete pSecond;
  1616. break;
  1617. case QL1_NOT:
  1618. if(ExprStack.size() < 1)
  1619. {
  1620. hres = WBEM_E_CRITICAL_ERROR;
  1621. break;
  1622. }
  1623. pFirst = ExprStack.top(); ExprStack.pop();
  1624. // No information
  1625. ExprStack.push(pNew);
  1626. delete pFirst;
  1627. break;
  1628. default:
  1629. hres = WBEM_E_CRITICAL_ERROR;
  1630. delete pNew;
  1631. }
  1632. if(FAILED(hres))
  1633. {
  1634. // An error occurred, break out of the loop
  1635. // ========================================
  1636. break;
  1637. }
  1638. }
  1639. if(FAILED(hres))
  1640. {
  1641. // An error occurred. Clear the stack
  1642. // ==================================
  1643. while(!ExprStack.empty())
  1644. {
  1645. delete ExprStack.top();
  1646. ExprStack.pop();
  1647. }
  1648. return hres;
  1649. }
  1650. if(pExpr->nNumTokens == 0)
  1651. {
  1652. // Empty query --- stays empty
  1653. pNewExpr = _new QL_LEVEL_1_RPN_EXPRESSION;
  1654. if(pNewExpr == NULL)
  1655. return WBEM_E_OUT_OF_MEMORY;
  1656. }
  1657. else if(ExprStack.size() != 1)
  1658. {
  1659. // internal error
  1660. return WBEM_E_CRITICAL_ERROR;
  1661. }
  1662. else
  1663. {
  1664. // All is good
  1665. // ===========
  1666. pNewExpr = ExprStack.top();
  1667. }
  1668. //
  1669. // Copy the class name
  1670. //
  1671. VARIANT vName;
  1672. hres = pClass->Get(L"__CLASS", 0, &vName, NULL, NULL);
  1673. if(FAILED(hres))
  1674. return WBEM_E_CRITICAL_ERROR;
  1675. pNewExpr->bsClassName = V_BSTR(&vName);
  1676. // Variant intentionally not cleared
  1677. //
  1678. // Copy all the properties in the select clause except for irrelevant ones
  1679. //
  1680. pNewExpr->bStar = pExpr->bStar;
  1681. if(!pNewExpr->bStar)
  1682. {
  1683. delete [] pNewExpr->pRequestedPropertyNames;
  1684. pNewExpr->nCurPropSize = pExpr->nCurPropSize+1;
  1685. pNewExpr->pRequestedPropertyNames =
  1686. new CPropertyName[pNewExpr->nCurPropSize];
  1687. if(pNewExpr->pRequestedPropertyNames == NULL)
  1688. {
  1689. delete pNewExpr;
  1690. return WBEM_E_OUT_OF_MEMORY;
  1691. }
  1692. //
  1693. // Add __RELPATH, as we always need that!
  1694. //
  1695. pNewExpr->pRequestedPropertyNames[0].AddElement(L"__RELPATH");
  1696. pNewExpr->nNumberOfProperties = 1;
  1697. for(int i = 0; i < pExpr->nNumberOfProperties; i++)
  1698. {
  1699. //
  1700. // Check if the property exists in the class
  1701. //
  1702. CIMTYPE ct;
  1703. hres = pClass->Get(pExpr->pRequestedPropertyNames[i].GetStringAt(0),
  1704. 0, NULL, &ct, NULL);
  1705. if(SUCCEEDED(hres))
  1706. {
  1707. //
  1708. // Add it to the list
  1709. //
  1710. pNewExpr->pRequestedPropertyNames[
  1711. pNewExpr->nNumberOfProperties++] =
  1712. pExpr->pRequestedPropertyNames[i];
  1713. }
  1714. }
  1715. }
  1716. return S_OK;
  1717. }
  1718. BOOL CQueryAnalyser::IsTokenAboutClass(QL_LEVEL_1_TOKEN& Token,
  1719. IWbemClassObject* pClass,
  1720. CWStringArray& awsOverriden)
  1721. {
  1722. //
  1723. // Check if the property being compared is in our class
  1724. // and not overriden
  1725. //
  1726. if(!IsPropertyInClass(Token.PropertyName, pClass, awsOverriden))
  1727. return FALSE;
  1728. //
  1729. // If comparing to another property, check if that one is
  1730. // likewise good
  1731. //
  1732. if(Token.m_bPropComp &&
  1733. !IsPropertyInClass(Token.PropertyName2, pClass, awsOverriden))
  1734. return FALSE;
  1735. return TRUE;
  1736. }
  1737. BOOL CQueryAnalyser::IsPropertyInClass(CPropertyName& Prop,
  1738. IWbemClassObject* pClass,
  1739. CWStringArray& awsOverriden)
  1740. {
  1741. //
  1742. // Check if the property exists in the class
  1743. //
  1744. CIMTYPE ct;
  1745. HRESULT hres = pClass->Get(Prop.GetStringAt(0), 0, NULL, &ct, NULL);
  1746. if(FAILED(hres))
  1747. return FALSE;
  1748. //
  1749. // Check if the property is overriden by any of our children
  1750. //
  1751. if(awsOverriden.FindStr(Prop.GetStringAt(0), CWStringArray::no_case) >= 0)
  1752. return FALSE;
  1753. return TRUE;
  1754. }