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.

1546 lines
39 KiB

  1. /*++
  2. Copyright Microsoft Corporation. All rights reserved.
  3. Module Name:
  4. OBJPATH.CPP
  5. Abstract:
  6. Object path parser.
  7. History:
  8. --*/
  9. #include "precomp.h"
  10. #include <genlex.h>
  11. #include <opathlex.h>
  12. #include <objpath.h>
  13. inline LPWSTR Macro_CloneLPWSTR(LPCWSTR x)
  14. {
  15. if (0 == x) return 0;
  16. size_t cchTmp = wcslen(x) + 1;
  17. LPWSTR szTemp = new wchar_t[cchTmp];
  18. if (szTemp) memcpy(szTemp,x,cchTmp*sizeof(WCHAR));
  19. return szTemp;
  20. }
  21. bool inline CloneFailed(LPCWSTR p1, LPCWSTR p2)
  22. {
  23. if (0 == p1 && 0 == p2 ) return false;
  24. if (p1 && p2) return false;
  25. return true;
  26. }
  27. ParsedObjectPath::ParsedObjectPath()
  28. {
  29. m_pServer = 0; // NULL if no server
  30. m_dwNumNamespaces = 0; // 0 if no namespaces
  31. m_dwAllocNamespaces = 2;
  32. m_paNamespaces = new LPWSTR[m_dwAllocNamespaces];
  33. if(m_paNamespaces)
  34. for (unsigned i = 0; i < m_dwAllocNamespaces; i++)
  35. m_paNamespaces[i] = 0;
  36. m_pClass = 0; // Class name
  37. m_dwNumKeys = 0; // 0 if no keys (just a class name)
  38. m_bSingletonObj = FALSE;
  39. m_dwAllocKeys = 2;
  40. m_paKeys = new KeyRef *[m_dwAllocKeys];
  41. if (m_paKeys)
  42. for (unsigned i = 0; i < m_dwAllocKeys; i++)
  43. m_paKeys[i] = NULL;
  44. }
  45. ParsedObjectPath::~ParsedObjectPath()
  46. {
  47. if (m_pServer)
  48. delete m_pServer;
  49. if (m_paNamespaces)
  50. {
  51. for (DWORD dwIx = 0; dwIx < m_dwNumNamespaces; dwIx++)
  52. if (m_paNamespaces[dwIx])
  53. delete m_paNamespaces[dwIx];
  54. delete m_paNamespaces;
  55. }
  56. if (m_pClass)
  57. delete m_pClass;
  58. if (m_paKeys)
  59. {
  60. for (DWORD dwIx = 0; dwIx < m_dwNumKeys; dwIx++)
  61. if (m_paKeys[dwIx])
  62. delete m_paKeys[dwIx];
  63. delete m_paKeys;
  64. }
  65. }
  66. BOOL ParsedObjectPath::SetClassName(LPCWSTR wszClassName)
  67. {
  68. if (m_pClass)
  69. delete [] m_pClass;
  70. if(wszClassName == NULL)
  71. {
  72. m_pClass = NULL;
  73. }
  74. else
  75. {
  76. m_pClass = Macro_CloneLPWSTR(wszClassName);
  77. if (CloneFailed(m_pClass,wszClassName))
  78. return FALSE;
  79. }
  80. return TRUE;
  81. }
  82. BOOL ParsedObjectPath::IsClass()
  83. {
  84. if(!IsObject())
  85. return FALSE;
  86. return (m_dwNumKeys == 0 && !m_bSingletonObj);
  87. }
  88. BOOL ParsedObjectPath::IsInstance()
  89. {
  90. return IsObject() && !IsClass();
  91. }
  92. BOOL ParsedObjectPath::IsObject()
  93. {
  94. if(m_pClass == NULL)
  95. return FALSE;
  96. if(m_pServer)
  97. {
  98. return (m_dwNumNamespaces > 0);
  99. }
  100. else
  101. {
  102. return (m_dwNumNamespaces == 0);
  103. }
  104. }
  105. BOOL ParsedObjectPath::AddNamespace(LPCWSTR wszNamespace)
  106. {
  107. if(m_dwNumNamespaces == m_dwAllocNamespaces)
  108. {
  109. DWORD dwNewAllocNamespaces = m_dwAllocNamespaces * 2;
  110. LPWSTR* paNewNamespaces = new LPWSTR[dwNewAllocNamespaces];
  111. if(paNewNamespaces == NULL) return FALSE;
  112. memcpy(paNewNamespaces, m_paNamespaces,
  113. sizeof(LPWSTR) * m_dwAllocNamespaces);
  114. delete [] m_paNamespaces;
  115. m_paNamespaces = paNewNamespaces;
  116. m_dwAllocNamespaces = dwNewAllocNamespaces;
  117. }
  118. LPWSTR p = Macro_CloneLPWSTR(wszNamespace);
  119. if (p)
  120. {
  121. m_paNamespaces[m_dwNumNamespaces++] = p;
  122. return TRUE;
  123. }
  124. else
  125. {
  126. return FALSE;
  127. }
  128. }
  129. BOOL ParsedObjectPath::AddKeyRefEx(LPCWSTR wszKeyName, const VARIANT* pvValue )
  130. {
  131. BOOL bStatus = TRUE ;
  132. BOOL bFound = FALSE ;
  133. BOOL bUnNamed = FALSE ;
  134. for ( ULONG dwIndex = 0 ; dwIndex < m_dwNumKeys ; dwIndex ++ )
  135. {
  136. if ( ( m_paKeys [ dwIndex ]->m_pName ) && wszKeyName )
  137. {
  138. if ( wbem_wcsicmp ( m_paKeys [ dwIndex ]->m_pName , wszKeyName )
  139. == 0 )
  140. {
  141. bFound = TRUE ;
  142. break ;
  143. }
  144. }
  145. else
  146. {
  147. if ( ( ( m_paKeys [ dwIndex ]->m_pName ) == 0 ) )
  148. {
  149. bUnNamed = TRUE ;
  150. if ( ( wszKeyName == 0 ) )
  151. {
  152. bFound = TRUE ;
  153. break ;
  154. }
  155. }
  156. }
  157. }
  158. if ( ! wszKeyName )
  159. {
  160. /* Remove all existing keys */
  161. for ( ULONG dwDeleteIndex = 0 ; dwDeleteIndex < m_dwNumKeys ;
  162. dwDeleteIndex ++ )
  163. {
  164. delete ( m_paKeys [ dwDeleteIndex ]->m_pName ) ;
  165. m_paKeys [ dwDeleteIndex ]->m_pName = NULL ;
  166. VariantClear ( & ( m_paKeys [ dwDeleteIndex ]->m_vValue ) ) ;
  167. }
  168. if (S_OK == VariantCopy ( & ( m_paKeys [ 0 ]->m_vValue ) , ( VARIANT * ) pvValue ))
  169. {
  170. m_dwNumKeys = 1 ;
  171. }
  172. else
  173. {
  174. bStatus = FALSE;
  175. }
  176. }
  177. else
  178. {
  179. if ( bFound )
  180. {
  181. /*
  182. * If key already exists then just replace the value
  183. */
  184. if ( wszKeyName )
  185. {
  186. size_t cchTmp = wcslen ( wszKeyName ) + 1;
  187. m_paKeys[dwIndex]->m_pName = new wchar_t [cchTmp];
  188. if (m_paKeys[dwIndex]->m_pName)
  189. {
  190. StringCchCopyW(m_paKeys[dwIndex]->m_pName,cchTmp,wszKeyName);
  191. }
  192. else
  193. {
  194. bStatus = FALSE;
  195. goto error;
  196. }
  197. }
  198. VariantClear ( & ( m_paKeys [ dwIndex ]->m_vValue ) ) ;
  199. if (S_OK != VariantCopy ( & ( m_paKeys [ dwIndex ]->m_vValue ) ,
  200. ( VARIANT * ) pvValue ))
  201. {
  202. bStatus = FALSE;
  203. }
  204. }
  205. else
  206. {
  207. if ( bUnNamed )
  208. {
  209. /* Add an un named key */
  210. for ( ULONG dwDeleteIndex = 0 ; dwDeleteIndex < m_dwNumKeys ;
  211. dwDeleteIndex ++ )
  212. {
  213. delete ( m_paKeys [ dwDeleteIndex ]->m_pName ) ;
  214. m_paKeys [ dwDeleteIndex ]->m_pName = NULL ;
  215. VariantClear (& ( m_paKeys [ dwDeleteIndex ]->m_vValue ) );
  216. }
  217. size_t cchTmp = wcslen ( wszKeyName ) + 1;
  218. m_paKeys[0]->m_pName = new wchar_t[cchTmp];
  219. if (m_paKeys[0]->m_pName)
  220. {
  221. StringCchCopyW(m_paKeys [0]->m_pName,cchTmp, wszKeyName ) ;
  222. if (S_OK == VariantCopy ( & ( m_paKeys [ 0 ]->m_vValue ) ,
  223. ( VARIANT * ) pvValue ))
  224. {
  225. m_dwNumKeys = 1;
  226. }
  227. else
  228. {
  229. bStatus = FALSE;
  230. }
  231. }
  232. else
  233. {
  234. bStatus = FALSE;
  235. }
  236. }
  237. else
  238. {
  239. /* Add a Named Key */
  240. bStatus = AddKeyRef(wszKeyName, pvValue);
  241. }
  242. }
  243. }
  244. error:
  245. return bStatus;
  246. }
  247. void ParsedObjectPath::ClearKeys ()
  248. {
  249. for ( ULONG dwDeleteIndex = 0 ; dwDeleteIndex < m_dwNumKeys ;
  250. dwDeleteIndex ++ )
  251. {
  252. delete m_paKeys [ dwDeleteIndex ] ;
  253. m_paKeys [ dwDeleteIndex ] = NULL ;
  254. }
  255. delete [] m_paKeys ;
  256. m_paKeys = NULL ;
  257. m_dwNumKeys = 0; // 0 if no keys (just a class name)
  258. m_paKeys = new KeyRef *[2];
  259. if (m_paKeys)
  260. m_dwAllocKeys = 2;
  261. }
  262. BOOL ParsedObjectPath::AddKeyRef(LPCWSTR wszKeyName, const VARIANT* pvValue)
  263. {
  264. if(m_dwNumKeys == m_dwAllocKeys)
  265. {
  266. DWORD dwNewAllocKeys = m_dwAllocKeys * 2;
  267. KeyRef** paNewKeys = new KeyRef*[dwNewAllocKeys];
  268. if (!paNewKeys)
  269. return FALSE;
  270. memcpy(paNewKeys, m_paKeys, sizeof(KeyRef*) * m_dwAllocKeys);
  271. delete [] m_paKeys;
  272. m_paKeys = paNewKeys;
  273. m_dwAllocKeys = dwNewAllocKeys;
  274. }
  275. if(m_paKeys == NULL)
  276. return FALSE;
  277. m_paKeys[m_dwNumKeys] = new KeyRef(wszKeyName, pvValue);
  278. if (!m_paKeys[m_dwNumKeys] || !m_paKeys[m_dwNumKeys]->IsValid())
  279. return FALSE;
  280. m_dwNumKeys++;
  281. return TRUE;
  282. }
  283. BOOL ParsedObjectPath::AddKeyRef(KeyRef* pAcquireRef)
  284. {
  285. if(m_dwNumKeys == m_dwAllocKeys)
  286. {
  287. DWORD dwNewAllocKeys = m_dwAllocKeys * 2;
  288. KeyRef** paNewKeys = new KeyRef*[dwNewAllocKeys];
  289. if(paNewKeys == NULL)return FALSE;
  290. memcpy(paNewKeys, m_paKeys, sizeof(KeyRef*) * m_dwAllocKeys);
  291. delete [] m_paKeys;
  292. m_paKeys = paNewKeys;
  293. m_dwAllocKeys = dwNewAllocKeys;
  294. }
  295. m_paKeys[m_dwNumKeys] = pAcquireRef;
  296. m_dwNumKeys++;
  297. return TRUE;
  298. }
  299. KeyRef::KeyRef()
  300. {
  301. m_pName = 0;
  302. VariantInit(&m_vValue);
  303. m_hRes = S_OK;
  304. }
  305. KeyRef::KeyRef(LPCWSTR wszKeyName, const VARIANT* pvValue)
  306. {
  307. m_pName = Macro_CloneLPWSTR(wszKeyName);
  308. VariantInit(&m_vValue);
  309. m_hRes = VariantCopy(&m_vValue, (VARIANT*)pvValue);
  310. }
  311. KeyRef::~KeyRef()
  312. {
  313. delete m_pName;
  314. VariantClear(&m_vValue);
  315. }
  316. int WINAPI CObjectPathParser::Unparse(
  317. ParsedObjectPath* pInput,
  318. DELETE_ME LPWSTR* pwszPath)
  319. {
  320. if(pInput->m_pClass == NULL)
  321. {
  322. return CObjectPathParser::InvalidParameter;
  323. }
  324. // Allocate enough space
  325. // =====================
  326. int nSpace = wcslen(pInput->m_pClass);
  327. nSpace += 10;
  328. DWORD dwIx;
  329. for (dwIx = 0; dwIx < pInput->m_dwNumKeys; dwIx++)
  330. {
  331. KeyRef* pKey = pInput->m_paKeys[dwIx];
  332. if(pKey->m_pName)
  333. nSpace += wcslen(pKey->m_pName);
  334. if(V_VT(&pKey->m_vValue) == VT_BSTR)
  335. {
  336. nSpace += wcslen(V_BSTR(&pKey->m_vValue))*2 + 10;
  337. }
  338. else if( V_VT(&pKey->m_vValue) == VT_I4
  339. || V_VT(&pKey->m_vValue) == VT_UI4 )
  340. {
  341. nSpace += 30;
  342. }
  343. else if ( V_VT(&pKey->m_vValue) == VT_I2
  344. || V_VT(&pKey->m_vValue) == VT_UI2 )
  345. {
  346. nSpace += 15;
  347. }
  348. else if ( V_VT(&pKey->m_vValue) == VT_I1
  349. || V_VT(&pKey->m_vValue) == VT_UI1 )
  350. {
  351. nSpace += 8;
  352. }
  353. }
  354. if(pInput->m_bSingletonObj)
  355. nSpace +=2;
  356. WCHAR wszTemp[30];
  357. LPWSTR wszPath = new WCHAR[nSpace];
  358. if (!wszPath)
  359. return OutOfMemory;
  360. StringCchCopyW(wszPath,nSpace, pInput->m_pClass);
  361. for (dwIx = 0; dwIx < pInput->m_dwNumKeys; dwIx++)
  362. {
  363. KeyRef* pKey = pInput->m_paKeys[dwIx];
  364. // We dont want to put a '.' if there isnt a key name,
  365. // for example, Myclass="value"
  366. if(dwIx == 0)
  367. {
  368. if((pKey->m_pName && (0 < wcslen(pKey->m_pName))) || pInput->m_dwNumKeys > 1)
  369. StringCchCatW(wszPath,nSpace, L".");
  370. }
  371. else
  372. {
  373. StringCchCatW(wszPath,nSpace, L",");
  374. }
  375. if(pKey->m_pName)
  376. StringCchCatW(wszPath,nSpace, pKey->m_pName);
  377. StringCchCatW(wszPath,nSpace, L"=");
  378. if(V_VT(&pKey->m_vValue) == VT_BSTR)
  379. {
  380. StringCchCatW(wszPath,nSpace, L"\"");
  381. WCHAR* pwc = V_BSTR(&pKey->m_vValue);
  382. WCHAR str[2];
  383. str[1] = 0;
  384. while(*pwc)
  385. {
  386. if(*pwc == '\\' || *pwc == '"')
  387. {
  388. StringCchCatW(wszPath,nSpace, L"\\");
  389. }
  390. str[0] = *pwc;
  391. StringCchCatW(wszPath,nSpace, str);
  392. pwc++;
  393. }
  394. StringCchCatW(wszPath,nSpace, L"\"");
  395. }
  396. else if( V_VT(&pKey->m_vValue) == VT_I4 )
  397. {
  398. StringCchPrintfW(wszTemp,LENGTH_OF(wszTemp), L"%d", V_I4(&pKey->m_vValue));
  399. StringCchCatW(wszPath,nSpace, wszTemp);
  400. }
  401. else if( V_VT(&pKey->m_vValue) == VT_UI4 )
  402. {
  403. StringCchPrintfW(wszTemp,LENGTH_OF(wszTemp), L"%u", V_UI4(&pKey->m_vValue));
  404. StringCchCatW(wszPath,nSpace, wszTemp);
  405. }
  406. else if( V_VT(&pKey->m_vValue) == VT_I2 )
  407. {
  408. StringCchPrintfW(wszTemp,LENGTH_OF(wszTemp), L"%hd", V_I2(&pKey->m_vValue));
  409. StringCchCatW(wszPath,nSpace, wszTemp);
  410. }
  411. else if( V_VT(&pKey->m_vValue) == VT_UI2 )
  412. {
  413. StringCchPrintfW(wszTemp,LENGTH_OF(wszTemp), L"%hu", V_UI2(&pKey->m_vValue));
  414. StringCchCatW(wszPath,nSpace, wszTemp);
  415. }
  416. else if( V_VT(&pKey->m_vValue) == VT_I1 )
  417. {
  418. StringCchPrintfW(wszTemp,LENGTH_OF(wszTemp), L"%d", V_I1(&pKey->m_vValue));
  419. StringCchCatW(wszPath,nSpace, wszTemp);
  420. }
  421. else if( V_VT(&pKey->m_vValue) == VT_UI1 )
  422. {
  423. StringCchPrintfW(wszTemp,LENGTH_OF(wszTemp), L"%u", V_UI1(&pKey->m_vValue));
  424. StringCchCatW(wszPath,nSpace, wszTemp);
  425. }
  426. }
  427. // Take care of the singleton case. This is a path of the form
  428. // MyClass=@ and represents a single instance of a class with no
  429. // keys.
  430. if(pInput->m_bSingletonObj && pInput->m_dwNumKeys == 0)
  431. StringCchCatW(wszPath,nSpace, L"=@");
  432. *pwszPath = wszPath;
  433. return NoError;
  434. }
  435. LPWSTR WINAPI CObjectPathParser::GetRelativePath(LPWSTR wszFullPath)
  436. {
  437. LPWSTR wsz = wcschr(wszFullPath, L':');
  438. if(wsz)
  439. return wsz + 1;
  440. else
  441. return NULL;
  442. }
  443. void CObjectPathParser::Zero()
  444. {
  445. m_nCurrentToken = 0;
  446. m_pLexer = 0;
  447. m_pInitialIdent = 0;
  448. m_pOutput = 0;
  449. m_pTmpKeyRef = 0;
  450. }
  451. CObjectPathParser::CObjectPathParser(ObjectParserFlags eFlags)
  452. : m_eFlags(eFlags)
  453. {
  454. Zero();
  455. }
  456. void CObjectPathParser::Empty()
  457. {
  458. delete m_pLexer;
  459. delete m_pInitialIdent;
  460. delete m_pTmpKeyRef;
  461. // m_pOutput is intentionally left alone,
  462. // since all code paths delete this already on error, or
  463. // else the user acquired the pointer.
  464. }
  465. CObjectPathParser::~CObjectPathParser()
  466. {
  467. Empty();
  468. }
  469. int CObjectPathParser::Parse(
  470. LPCWSTR pRawPath,
  471. ParsedObjectPath **pOutput
  472. )
  473. {
  474. if (pOutput == 0 || pRawPath == 0 || wcslen(pRawPath) == 0)
  475. return CObjectPathParser::InvalidParameter;
  476. // Check for leading / trailing ws.
  477. // ================================
  478. if (iswspace(pRawPath[wcslen(pRawPath)-1]) || iswspace(pRawPath[0]))
  479. return InvalidParameter;
  480. // These are required for multiple calls to Parse().
  481. // ==================================================
  482. Empty();
  483. Zero();
  484. // Set default return to NULL initially until we have some output.
  485. // ===============================================================
  486. *pOutput = 0;
  487. m_pOutput = new ParsedObjectPath;
  488. if (!m_pOutput)
  489. return OutOfMemory;
  490. if (!m_pOutput->IsValid())
  491. {
  492. delete m_pOutput;
  493. m_pOutput = NULL;
  494. return OutOfMemory;
  495. }
  496. // Parse the server name (if there is one) manually
  497. // ================================================
  498. if ( (pRawPath[0] == '\\' && pRawPath[1] == '\\') ||
  499. (pRawPath[0] == '/' && pRawPath[1] == '/'))
  500. {
  501. const WCHAR* pwcStart = pRawPath + 2;
  502. // Find the next backslash --- it's the end of the server name
  503. // ===========================================================
  504. const WCHAR* pwcEnd = pwcStart;
  505. while (*pwcEnd != L'\0' && *pwcEnd != L'\\' && *pwcEnd != L'/')
  506. {
  507. pwcEnd++;
  508. }
  509. if (*pwcEnd == L'\0')
  510. {
  511. // If we have already exhausted the object path string,
  512. // a lone server name was all there was.
  513. // ====================================================
  514. if (m_eFlags != e_ParserAcceptAll)
  515. {
  516. delete m_pOutput;
  517. return SyntaxError;
  518. }
  519. else // A lone server name is legal.
  520. {
  521. size_t cchTmp = wcslen(pwcStart)+1;
  522. m_pOutput->m_pServer = new WCHAR[cchTmp];
  523. if (!m_pOutput->m_pServer)
  524. {
  525. delete m_pOutput;
  526. return OutOfMemory;
  527. }
  528. StringCchCopyW(m_pOutput->m_pServer,cchTmp, pwcStart);
  529. *pOutput = m_pOutput;
  530. m_pOutput = 0;
  531. return NoError;
  532. }
  533. }
  534. if (pwcEnd == pwcStart)
  535. {
  536. // No name at all.
  537. // ===============
  538. delete m_pOutput;
  539. return SyntaxError;
  540. }
  541. m_pOutput->m_pServer = new WCHAR[pwcEnd-pwcStart+1];
  542. if (!m_pOutput->m_pServer)
  543. {
  544. delete m_pOutput;
  545. return OutOfMemory;
  546. }
  547. wcsncpy(m_pOutput->m_pServer, pwcStart, pwcEnd-pwcStart);
  548. m_pOutput->m_pServer[pwcEnd-pwcStart] = 0;
  549. pRawPath = pwcEnd;
  550. }
  551. // Point the lexer at the source.
  552. // ==============================
  553. CTextLexSource src(pRawPath);
  554. m_pLexer = new CGenLexer(OPath_LexTable, &src);
  555. if (!m_pLexer)
  556. {
  557. delete m_pOutput;
  558. return OutOfMemory;
  559. }
  560. // Go.
  561. // ===
  562. int nRes = begin_parse();
  563. if (nRes)
  564. {
  565. delete m_pOutput;
  566. return nRes;
  567. }
  568. if (m_nCurrentToken != OPATH_TOK_EOF)
  569. {
  570. delete m_pOutput;
  571. return SyntaxError;
  572. }
  573. if (m_pOutput->m_dwNumNamespaces > 0 && m_pOutput->m_pServer == NULL)
  574. {
  575. if (m_eFlags != e_ParserAcceptRelativeNamespace && m_eFlags != e_ParserAcceptAll)
  576. {
  577. delete m_pOutput;
  578. return SyntaxError;
  579. }
  580. else
  581. {
  582. // Local namespace --- set server to "."
  583. // =====================================
  584. m_pOutput->m_pServer = new WCHAR[2];
  585. if (!m_pOutput->m_pServer)
  586. {
  587. delete m_pOutput;
  588. return OutOfMemory;
  589. }
  590. StringCchCopyW(m_pOutput->m_pServer,2, L".");
  591. }
  592. }
  593. // Sort the key refs lexically. If there is only
  594. // one key, there is nothing to sort anyway.
  595. // =============================================
  596. if (m_pOutput->m_dwNumKeys > 1)
  597. {
  598. BOOL bChanges = TRUE;
  599. while (bChanges)
  600. {
  601. bChanges = FALSE;
  602. for (DWORD dwIx = 0; dwIx < m_pOutput->m_dwNumKeys - 1; dwIx++)
  603. {
  604. if (wbem_wcsicmp(m_pOutput->m_paKeys[dwIx]->m_pName,
  605. m_pOutput->m_paKeys[dwIx+1]->m_pName) > 0)
  606. {
  607. KeyRef *pTmp = m_pOutput->m_paKeys[dwIx];
  608. m_pOutput->m_paKeys[dwIx] = m_pOutput->m_paKeys[dwIx + 1];
  609. m_pOutput->m_paKeys[dwIx + 1] = pTmp;
  610. bChanges = TRUE;
  611. }
  612. }
  613. }
  614. }
  615. // Add in key refs.
  616. // ================
  617. *pOutput = m_pOutput;
  618. m_pOutput = 0;
  619. return NoError;
  620. }
  621. BOOL CObjectPathParser::NextToken()
  622. {
  623. m_nCurrentToken = m_pLexer->NextToken();
  624. if (m_nCurrentToken == OPATH_TOK_ERROR)
  625. return FALSE;
  626. return TRUE;
  627. }
  628. void CObjectPathParser::Free(ParsedObjectPath *pOutput)
  629. {
  630. delete pOutput;
  631. }
  632. void CObjectPathParser::Free( LPWSTR wszUnparsedPath )
  633. {
  634. delete wszUnparsedPath;
  635. }
  636. //
  637. // <Parse> ::= BACKSLASH <ns_or_server>;
  638. // <Parse> ::= IDENT <ns_or_class>;
  639. // <Parse> ::= COLON <objref>;
  640. //
  641. int CObjectPathParser::begin_parse()
  642. {
  643. if (!NextToken())
  644. return SyntaxError;
  645. if (m_nCurrentToken == OPATH_TOK_BACKSLASH)
  646. {
  647. if (!NextToken())
  648. return SyntaxError;
  649. return ns_or_server();
  650. }
  651. else if (m_nCurrentToken == OPATH_TOK_IDENT)
  652. {
  653. m_pInitialIdent = Macro_CloneLPWSTR(m_pLexer->GetTokenText());
  654. if (CloneFailed(m_pInitialIdent,m_pLexer->GetTokenText()))
  655. return OutOfMemory;
  656. if (!NextToken())
  657. return SyntaxError;
  658. // Copy the token and put it in a temporary holding place
  659. // until we figure out whether it is a namespace or a class name.
  660. // ==============================================================
  661. return ns_or_class();
  662. }
  663. else if (m_nCurrentToken == OPATH_TOK_COLON)
  664. {
  665. if (!NextToken())
  666. return SyntaxError;
  667. return objref();
  668. }
  669. // If here, we had a bad starter token.
  670. // ====================================
  671. return SyntaxError;
  672. }
  673. //
  674. // <ns_or_server> ::= BACKSLASH <dot_or_ident> BACKSLASH <ns_list> <optional_objref>;
  675. // <ns_or_server> ::= <ns_list> <optional_objref>;
  676. //
  677. // <dot_or_ident> is embedded.
  678. //
  679. int CObjectPathParser::ns_or_server()
  680. {
  681. if (m_nCurrentToken == OPATH_TOK_BACKSLASH)
  682. {
  683. // Actually, server names have been take care of, so this is a failure
  684. // ===================================================================
  685. return SyntaxError;
  686. }
  687. else if (m_nCurrentToken == OPATH_TOK_IDENT)
  688. {
  689. int nRes = ns_list();
  690. if (nRes)
  691. return nRes;
  692. return optional_objref();
  693. }
  694. else
  695. if (m_nCurrentToken == OPATH_TOK_EOF)
  696. return NoError;
  697. return SyntaxError;
  698. }
  699. //
  700. // <optional_objref> ::= COLON <objref>;
  701. // <optional_objref> ::= <>;
  702. //
  703. int CObjectPathParser::optional_objref()
  704. {
  705. if (m_nCurrentToken == OPATH_TOK_EOF)
  706. return NoError;
  707. if (m_nCurrentToken != OPATH_TOK_COLON)
  708. return SyntaxError;
  709. if (!NextToken())
  710. return SyntaxError;
  711. return objref();
  712. }
  713. //
  714. // <ns_or_class> ::= COLON <ident_becomes_ns> <objref>;
  715. // <ns_or_class> ::= BACKSLASH <ident_becomes_ns> <ns_list> COLON <objref>;
  716. // <ns_or_class> ::= BACKSLASH <ident_becomes_ns> <ns_list>;
  717. //
  718. int CObjectPathParser::ns_or_class()
  719. {
  720. if (m_nCurrentToken == OPATH_TOK_COLON)
  721. {
  722. ident_becomes_ns();
  723. if (!NextToken())
  724. return SyntaxError;
  725. return objref();
  726. }
  727. else if (m_nCurrentToken == OPATH_TOK_BACKSLASH)
  728. {
  729. ident_becomes_ns();
  730. if (!NextToken())
  731. return SyntaxError;
  732. int nRes = ns_list();
  733. if (nRes)
  734. return nRes;
  735. if (m_nCurrentToken == OPATH_TOK_EOF) // ns only
  736. return NoError;
  737. if (m_nCurrentToken != OPATH_TOK_COLON)
  738. return SyntaxError;
  739. if (!NextToken())
  740. return SyntaxError;
  741. return objref();
  742. }
  743. // Else
  744. // ====
  745. ident_becomes_class();
  746. return objref_rest();
  747. }
  748. //
  749. // <objref> ::= IDENT <objref_rest>; // IDENT is classname
  750. //
  751. int CObjectPathParser::objref()
  752. {
  753. if (m_nCurrentToken != OPATH_TOK_IDENT)
  754. return SyntaxError;
  755. m_pOutput->m_pClass = Macro_CloneLPWSTR(m_pLexer->GetTokenText());
  756. if (CloneFailed(m_pOutput->m_pClass,m_pLexer->GetTokenText()))
  757. return OutOfMemory;
  758. if (!NextToken())
  759. return SyntaxError;
  760. return objref_rest();
  761. }
  762. //
  763. // <ns_list> ::= IDENT <ns_list_rest>;
  764. //
  765. int CObjectPathParser::ns_list()
  766. {
  767. if (m_nCurrentToken == OPATH_TOK_IDENT)
  768. {
  769. m_pOutput->AddNamespace(m_pLexer->GetTokenText());
  770. if (!NextToken())
  771. return SyntaxError;
  772. return ns_list_rest();
  773. }
  774. return SyntaxError;
  775. }
  776. //
  777. // <ident_becomes_ns> ::= <>; // <initial_ident> becomes a namespace
  778. //
  779. int CObjectPathParser::ident_becomes_ns()
  780. {
  781. m_pOutput->AddNamespace(m_pInitialIdent);
  782. delete m_pInitialIdent;
  783. m_pInitialIdent = 0;
  784. return NoError;
  785. }
  786. //
  787. // <ident_becomes_class> ::= <>; // <initial_ident> becomes the class
  788. //
  789. int CObjectPathParser::ident_becomes_class()
  790. {
  791. m_pOutput->m_pClass = Macro_CloneLPWSTR(m_pInitialIdent);
  792. if (CloneFailed(m_pOutput->m_pClass,m_pInitialIdent))
  793. return OutOfMemory;
  794. delete m_pInitialIdent;
  795. m_pInitialIdent = 0;
  796. return NoError;
  797. }
  798. //
  799. // <objref_rest> ::= EQUALS <key_const>;
  800. // <objref_rest> ::= EQUALS *;
  801. // <objref_rest> ::= DOT <keyref_list>;
  802. // <objref_rest> ::= <>;
  803. //
  804. int CObjectPathParser::objref_rest()
  805. {
  806. if (m_nCurrentToken == OPATH_TOK_EQ)
  807. {
  808. if (!NextToken())
  809. return SyntaxError;
  810. // Take care of the singleton case. This is a path of the form
  811. // MyClass=@ and represents a singleton instance of a class with no
  812. // keys.
  813. if(m_nCurrentToken == OPATH_TOK_SINGLETON_SYM)
  814. {
  815. if(NextToken() && m_nCurrentToken != OPATH_TOK_EOF)
  816. return SyntaxError;
  817. m_pOutput->m_bSingletonObj = TRUE;
  818. return NoError;
  819. }
  820. m_pTmpKeyRef = new KeyRef; // no IsValid here
  821. if (!m_pTmpKeyRef)
  822. return OutOfMemory;
  823. int nRes = key_const();
  824. if (nRes)
  825. {
  826. delete m_pTmpKeyRef;
  827. m_pTmpKeyRef = 0;
  828. return nRes;
  829. }
  830. if (!m_pOutput->AddKeyRef(m_pTmpKeyRef))
  831. {
  832. delete m_pTmpKeyRef;
  833. m_pTmpKeyRef = 0;
  834. return OutOfMemory;
  835. }
  836. m_pTmpKeyRef = 0;
  837. }
  838. else if (m_nCurrentToken == OPATH_TOK_DOT)
  839. {
  840. if (!NextToken())
  841. return SyntaxError;
  842. return keyref_list();
  843. }
  844. return NoError;
  845. }
  846. //
  847. // <ns_list_rest> ::= BACKSLASH <ns_list>;
  848. // <ns_list_rest> ::= <>;
  849. //
  850. int CObjectPathParser::ns_list_rest()
  851. {
  852. if (m_nCurrentToken == OPATH_TOK_BACKSLASH)
  853. {
  854. if (!NextToken())
  855. return SyntaxError;
  856. return ns_list();
  857. }
  858. return NoError;
  859. }
  860. //
  861. // <key_const> ::= STRING_CONST;
  862. // <key_const> ::= INTEGRAL_CONST;
  863. // <key_const> ::= REAL_CONST;
  864. // <key_const> ::= IDENT; // Where IDENT is "OBJECT" for singleton classes
  865. //
  866. int CObjectPathParser::key_const()
  867. {
  868. // If here, we have a key constant.
  869. // We may or may not have the property name
  870. // associated with it.
  871. // ========================================
  872. if (m_nCurrentToken == OPATH_TOK_QSTRING)
  873. {
  874. BSTR bStr = SysAllocString(m_pLexer->GetTokenText());
  875. if (bStr)
  876. {
  877. V_VT(&m_pTmpKeyRef->m_vValue) = VT_BSTR;
  878. V_BSTR(&m_pTmpKeyRef->m_vValue) = bStr;
  879. }
  880. else
  881. return OutOfMemory;
  882. }
  883. else if (m_nCurrentToken == OPATH_TOK_INT)
  884. {
  885. V_VT(&m_pTmpKeyRef->m_vValue) = VT_I4;
  886. char buf[32];
  887. if(m_pLexer->GetTokenText() == NULL || wcslen(m_pLexer->GetTokenText()) > 31)
  888. return SyntaxError;
  889. StringCchPrintfA(buf,LENGTH_OF(buf), "%S", m_pLexer->GetTokenText());
  890. V_I4(&m_pTmpKeyRef->m_vValue) = atol(buf);
  891. }
  892. else if (m_nCurrentToken == OPATH_TOK_HEXINT)
  893. {
  894. V_VT(&m_pTmpKeyRef->m_vValue) = VT_I4;
  895. char buf[32];
  896. if(m_pLexer->GetTokenText() == NULL || wcslen(m_pLexer->GetTokenText()) > 31)
  897. return SyntaxError;
  898. StringCchPrintfA(buf,LENGTH_OF(buf), "%S", m_pLexer->GetTokenText());
  899. long l;
  900. sscanf(buf, "%x", &l);
  901. V_I4(&m_pTmpKeyRef->m_vValue) = l;
  902. }
  903. else if (m_nCurrentToken == OPATH_TOK_IDENT)
  904. {
  905. if (wbem_wcsicmp(m_pLexer->GetTokenText(), L"TRUE") == 0)
  906. {
  907. V_VT(&m_pTmpKeyRef->m_vValue) = VT_I4;
  908. V_I4(&m_pTmpKeyRef->m_vValue) = 1;
  909. }
  910. else if (wbem_wcsicmp(m_pLexer->GetTokenText(), L"FALSE") == 0)
  911. {
  912. V_VT(&m_pTmpKeyRef->m_vValue) = VT_I4;
  913. V_I4(&m_pTmpKeyRef->m_vValue) = 0;
  914. }
  915. else
  916. return SyntaxError;
  917. }
  918. else return SyntaxError;
  919. if (!NextToken())
  920. return SyntaxError;
  921. return NoError;
  922. }
  923. //
  924. // <keyref_list> ::= <keyref> <keyref_term>;
  925. //
  926. int CObjectPathParser::keyref_list()
  927. {
  928. int nRes = keyref();
  929. if (nRes)
  930. return nRes;
  931. return keyref_term();
  932. }
  933. //
  934. // <keyref> ::= <propname> EQUALS <key_const>;
  935. //
  936. int CObjectPathParser::keyref()
  937. {
  938. m_pTmpKeyRef = new KeyRef; // no IsValid here
  939. if (!m_pTmpKeyRef)
  940. return OutOfMemory;
  941. int nRes = propname();
  942. if (nRes)
  943. {
  944. delete m_pTmpKeyRef;
  945. m_pTmpKeyRef = 0;
  946. return nRes;
  947. }
  948. if (m_nCurrentToken != OPATH_TOK_EQ)
  949. {
  950. delete m_pTmpKeyRef;
  951. m_pTmpKeyRef = 0;
  952. return SyntaxError;
  953. }
  954. if (!NextToken())
  955. {
  956. delete m_pTmpKeyRef;
  957. m_pTmpKeyRef = 0;
  958. return SyntaxError;
  959. }
  960. nRes = key_const();
  961. if (nRes)
  962. {
  963. delete m_pTmpKeyRef;
  964. m_pTmpKeyRef = 0;
  965. return nRes;
  966. }
  967. if (!m_pOutput->AddKeyRef(m_pTmpKeyRef))
  968. {
  969. delete m_pTmpKeyRef;
  970. m_pTmpKeyRef = 0;
  971. return OutOfMemory;
  972. }
  973. m_pTmpKeyRef = 0;
  974. return NoError;
  975. }
  976. //
  977. // <keyref_term> ::= COMMA <keyref_list>; // Used for compound keys
  978. // <keyref_term> ::= <>;
  979. //
  980. int CObjectPathParser::keyref_term()
  981. {
  982. if (m_nCurrentToken == OPATH_TOK_COMMA)
  983. {
  984. if (!NextToken())
  985. return SyntaxError;
  986. return keyref_list();
  987. }
  988. return NoError;
  989. }
  990. //
  991. // <propname> ::= IDENT;
  992. //
  993. int CObjectPathParser::propname()
  994. {
  995. if (m_nCurrentToken != OPATH_TOK_IDENT)
  996. return SyntaxError;
  997. m_pTmpKeyRef->m_pName = Macro_CloneLPWSTR(m_pLexer->GetTokenText());
  998. if (CloneFailed(m_pTmpKeyRef->m_pName,m_pLexer->GetTokenText()))
  999. return OutOfMemory;
  1000. if (!NextToken())
  1001. {
  1002. delete m_pTmpKeyRef;
  1003. m_pTmpKeyRef = 0;
  1004. return SyntaxError;
  1005. }
  1006. return NoError;
  1007. }
  1008. //***************************************************************************
  1009. //
  1010. // ParsedObjectPath::GetKeyString
  1011. //
  1012. // Returns the db-engine compatible key string for the object.
  1013. // The format will likely change after the Alpha PDK Release.
  1014. //
  1015. // Return value:
  1016. // NULL on error or for pure classes. Otherwise returns a pointer to
  1017. // a newly allocated string which must be deallocated with operator
  1018. // delete.
  1019. //
  1020. //***************************************************************************
  1021. LPWSTR ParsedObjectPath::GetKeyString()
  1022. {
  1023. if (m_dwNumKeys == 0 && !m_bSingletonObj)
  1024. {
  1025. if (m_pClass == 0 || wcslen(m_pClass) == 0)
  1026. return 0;
  1027. size_t cchTmp = wcslen(m_pClass) + 1;
  1028. LPWSTR pTmp = new wchar_t[cchTmp];
  1029. if (pTmp) StringCchCopyW(pTmp,cchTmp, m_pClass);
  1030. return pTmp;
  1031. }
  1032. // Allocate enough space
  1033. // =====================
  1034. int nSpace = 10;
  1035. DWORD dwIx;
  1036. for (dwIx = 0; dwIx < m_dwNumKeys; dwIx++)
  1037. {
  1038. KeyRef* pKey = m_paKeys[dwIx];
  1039. nSpace += 2; // for the |
  1040. if(V_VT(&pKey->m_vValue) == VT_BSTR)
  1041. {
  1042. nSpace += wcslen(V_BSTR(&pKey->m_vValue))*2 + 10;
  1043. }
  1044. else if(V_VT(&pKey->m_vValue) == VT_I4)
  1045. {
  1046. nSpace += 30;
  1047. }
  1048. }
  1049. if(m_bSingletonObj)
  1050. nSpace +=20;
  1051. LPWSTR pRetVal = new wchar_t[nSpace];
  1052. wchar_t Tmp[32];
  1053. long nVal;
  1054. if (!pRetVal)
  1055. return NULL;
  1056. *pRetVal = 0;
  1057. BOOL bFirst = TRUE;
  1058. // The key are already sorted lexically.
  1059. // =====================================
  1060. WCHAR wszSeparator[2];
  1061. wszSeparator[0] = 0xFFFF;
  1062. wszSeparator[1] = 0;
  1063. for (DWORD i = 0; i < m_dwNumKeys; i++)
  1064. {
  1065. if (!bFirst)
  1066. StringCchCatW(pRetVal,nSpace, wszSeparator);
  1067. bFirst = FALSE;
  1068. KeyRef *pKeyRef = m_paKeys[i];
  1069. VARIANT *pv = &pKeyRef->m_vValue;
  1070. int nType = V_VT(pv);
  1071. switch (nType)
  1072. {
  1073. case VT_LPWSTR:
  1074. case VT_BSTR:
  1075. StringCchCatW(pRetVal,nSpace, V_BSTR(pv));
  1076. break;
  1077. case VT_I4:
  1078. nVal = V_I4(pv);
  1079. StringCchPrintfW(Tmp,LENGTH_OF(Tmp), L"%d", nVal);
  1080. StringCchCatW(pRetVal,nSpace, Tmp);
  1081. break;
  1082. case VT_I2:
  1083. nVal = V_I2(pv);
  1084. StringCchPrintfW(Tmp,LENGTH_OF(Tmp), L"%d", nVal);
  1085. StringCchCatW(pRetVal,nSpace, Tmp);
  1086. break;
  1087. case VT_UI1:
  1088. nVal = V_UI1(pv);
  1089. StringCchPrintfW(Tmp,LENGTH_OF(Tmp), L"%d", nVal);
  1090. StringCchCatW(pRetVal,nSpace, Tmp);
  1091. break;
  1092. case VT_BOOL:
  1093. nVal = V_BOOL(pv);
  1094. StringCchPrintfW(Tmp,LENGTH_OF(Tmp), L"%d", (nVal?1:0));
  1095. StringCchCatW(pRetVal,nSpace, Tmp);
  1096. break;
  1097. default:
  1098. StringCchCatW(pRetVal,nSpace, L"NULL");
  1099. }
  1100. }
  1101. if (wcslen(pRetVal) == 0)
  1102. {
  1103. if(m_bSingletonObj)
  1104. {
  1105. StringCchCopyW(pRetVal,nSpace, L"@");
  1106. }
  1107. }
  1108. return pRetVal; // This may not be NULL
  1109. }
  1110. LPWSTR ParsedObjectPath::GetNamespacePart()
  1111. {
  1112. if (m_dwNumNamespaces == 0)
  1113. return NULL;
  1114. // Compute necessary space
  1115. // =======================
  1116. int nSpace = 0;
  1117. for(DWORD i = 0; i < m_dwNumNamespaces; i++)
  1118. nSpace += 1 + wcslen(m_paNamespaces[i]);
  1119. nSpace--;
  1120. // Allocate buffer
  1121. // ===============
  1122. LPWSTR wszOut = new wchar_t[nSpace + 1];
  1123. if (!wszOut)
  1124. return NULL;
  1125. *wszOut = 0;
  1126. // Output
  1127. // ======
  1128. for(i = 0; i < m_dwNumNamespaces; i++)
  1129. {
  1130. if(i != 0) StringCchCatW(wszOut,nSpace + 1, L"\\");
  1131. StringCchCatW(wszOut,nSpace + 1, m_paNamespaces[i]);
  1132. }
  1133. return wszOut;
  1134. }
  1135. LPWSTR ParsedObjectPath::GetParentNamespacePart()
  1136. {
  1137. if(m_dwNumNamespaces < 2)
  1138. return NULL;
  1139. // Compute necessary space
  1140. // =======================
  1141. int nSpace = 0;
  1142. for(DWORD i = 0; i < m_dwNumNamespaces - 1; i++)
  1143. nSpace += 1 + wcslen(m_paNamespaces[i]);
  1144. nSpace--;
  1145. // Allocate buffer
  1146. // ===============
  1147. LPWSTR wszOut = new wchar_t[nSpace + 1];
  1148. if(wszOut == NULL)return NULL;
  1149. *wszOut = 0;
  1150. // Output
  1151. // ======
  1152. for(i = 0; i < m_dwNumNamespaces - 1; i++)
  1153. {
  1154. if(i != 0) StringCchCatW(wszOut,nSpace + 1, L"\\");
  1155. StringCchCatW(wszOut,nSpace + 1, m_paNamespaces[i]);
  1156. }
  1157. return wszOut;
  1158. }
  1159. BOOL ParsedObjectPath::IsRelative(LPCWSTR wszMachine, LPCWSTR wszNamespace)
  1160. {
  1161. if(!IsLocal(wszMachine))
  1162. return FALSE;
  1163. if(m_dwNumNamespaces == 0)
  1164. return TRUE;
  1165. size_t cchTmp = wcslen(wszNamespace) + 1;
  1166. LPWSTR wszCopy = new wchar_t[cchTmp];
  1167. if(wszCopy == NULL)return FALSE;
  1168. StringCchCopyW(wszCopy,cchTmp, wszNamespace);
  1169. LPWSTR wszLeft = wszCopy;
  1170. BOOL bFailed = FALSE;
  1171. for(DWORD i = 0; i < m_dwNumNamespaces; i++)
  1172. {
  1173. unsigned int nLen = wcslen(m_paNamespaces[i]);
  1174. if(nLen > wcslen(wszLeft))
  1175. {
  1176. bFailed = TRUE;
  1177. break;
  1178. }
  1179. if(i == m_dwNumNamespaces - 1 && wszLeft[nLen] != 0)
  1180. {
  1181. bFailed = TRUE;
  1182. break;
  1183. }
  1184. if(i != m_dwNumNamespaces - 1 && wszLeft[nLen] != L'\\')
  1185. {
  1186. bFailed = TRUE;
  1187. break;
  1188. }
  1189. wszLeft[nLen] = 0;
  1190. if(wbem_wcsicmp(wszLeft, m_paNamespaces[i]))
  1191. {
  1192. bFailed = TRUE;
  1193. break;
  1194. }
  1195. wszLeft += nLen+1;
  1196. }
  1197. delete [] wszCopy;
  1198. return !bFailed;
  1199. }
  1200. BOOL ParsedObjectPath::IsLocal(LPCWSTR wszMachine)
  1201. {
  1202. return (m_pServer == NULL || !wbem_wcsicmp(m_pServer, L".") ||
  1203. !wbem_wcsicmp(m_pServer, wszMachine));
  1204. }
  1205. ////////////////////////////////////////////////////////
  1206. //
  1207. // Test object path parser by parsing all objects
  1208. // in the input file (one object path per line).
  1209. //
  1210. ////////////////////////////////////////////////////////
  1211. #ifdef TEST
  1212. void xmain(int argc, char **argv)
  1213. {
  1214. printf("Object Path Test\n");
  1215. if (argc < 2 || strchr(argv[1], '?') != NULL)
  1216. {
  1217. printf("Usage: objpath input-file\n");
  1218. return;
  1219. }
  1220. int nLine = 1;
  1221. char buf[2048];
  1222. FILE *f = fopen(argv[1], "rt");
  1223. if (f == NULL)
  1224. {
  1225. printf("Usage: objpath input-file\nError: cannot open file %s!\n", argv[1]);
  1226. return;
  1227. }
  1228. while (fgets(buf, 2048, f) != NULL)
  1229. {
  1230. // Get rid of newline and trailing spaces.
  1231. // =======================================
  1232. char* ptr = strchr(buf, '\n');
  1233. if (ptr != NULL)
  1234. {
  1235. *ptr = ' ';
  1236. while (ptr >= buf && *ptr == ' ')
  1237. {
  1238. *ptr = '\0';
  1239. ptr--;
  1240. }
  1241. }
  1242. // Get rid of leading spaces.
  1243. // ==========================
  1244. ptr = buf;
  1245. while (*ptr == ' ')
  1246. {
  1247. ptr++;
  1248. }
  1249. // Convert to wide char and parse. Ignore blank lines.
  1250. // ====================================================
  1251. if (*ptr != '\0')
  1252. {
  1253. wchar_t buf2[2048];
  1254. MultiByteToWideChar(CP_ACP, 0, ptr, -1, buf2, 2048);
  1255. printf("----Object path----\n");
  1256. printf("%S\n", buf2);
  1257. ParsedObjectPath* pOutput = 0;
  1258. CObjectPathParser p(e_ParserAcceptAll);
  1259. int nStatus = p.Parse(buf2, &pOutput);
  1260. if (nStatus != 0)
  1261. {
  1262. printf("ERROR: return code is %d\n", nStatus);
  1263. continue;
  1264. }
  1265. printf("No errors.\n");
  1266. printf("------Output------\n");
  1267. LPWSTR pKey = pOutput->GetKeyString();
  1268. printf("Key String = <%S>\n", pKey);
  1269. delete pKey;
  1270. printf("Server = %S\n", pOutput->m_pServer);
  1271. printf("Namespace Part = %S\n", pOutput->GetNamespacePart());
  1272. printf("Parent Part = %S\n", pOutput->GetParentNamespacePart());
  1273. for (DWORD dwIx = 0; dwIx < pOutput->m_dwNumNamespaces; dwIx++)
  1274. {
  1275. printf("Namespace = <%S>\n", pOutput->m_paNamespaces[dwIx]);
  1276. }
  1277. printf("Class = <%S>\n", pOutput->m_pClass);
  1278. // If here, the key ref is complete.
  1279. // =================================
  1280. for (dwIx = 0; dwIx < pOutput->m_dwNumKeys; dwIx++)
  1281. {
  1282. KeyRef *pTmp = pOutput->m_paKeys[dwIx];
  1283. printf("*** KeyRef contents:\n");
  1284. printf(" Name = %S Value=", pTmp->m_pName);
  1285. switch (V_VT(&pTmp->m_vValue))
  1286. {
  1287. case VT_I4: printf("%d", V_I4(&pTmp->m_vValue)); break;
  1288. case VT_R8: printf("%f", V_R8(&pTmp->m_vValue)); break;
  1289. case VT_BSTR: printf("<%S>", V_BSTR(&pTmp->m_vValue)); break;
  1290. default:
  1291. printf("BAD KEY REF\n");
  1292. }
  1293. printf("\n");
  1294. }
  1295. p.Free(pOutput);
  1296. }
  1297. }
  1298. }
  1299. void main(int argc, char **argv)
  1300. {
  1301. xmain(argc, argv);
  1302. }
  1303. #endif