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.

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