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.

1530 lines
44 KiB

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