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.

681 lines
21 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. #include "precomp.h"
  8. #include "txttempl.h"
  9. #include <stdio.h>
  10. #include <assert.h>
  11. #include "var.h"
  12. CTextTemplate::CTextTemplate(LPCWSTR wszTemplate) : m_wsTemplate(wszTemplate)
  13. {
  14. }
  15. CTextTemplate::~CTextTemplate()
  16. {
  17. }
  18. void CTextTemplate::SetTemplate(LPCWSTR wszTemplate)
  19. {
  20. m_wsTemplate = wszTemplate;
  21. }
  22. // replace escape sequences with proper characters
  23. // currently enabled for:
  24. // \t; \n; \r;
  25. // anything else is translated literally, minus the backwhack
  26. // returned string may or may not be same string as passed in
  27. // if not, then arg string is deleted & a new one returned.
  28. // -=> Thou Hast Been Forewarned!
  29. BSTR CTextTemplate::ReturnEscapedReturns(BSTR str)
  30. {
  31. BSTR newStr = str;
  32. // if we find a backwhack
  33. if (NULL != wcschr(str, L'\\'))
  34. {
  35. if (newStr = SysAllocString(str))
  36. {
  37. WCHAR *pSource, *pDest;
  38. ZeroMemory(newStr, (wcslen(str)+1) *2);
  39. pDest = newStr;
  40. pSource = str;
  41. do
  42. {
  43. if (*pSource == L'\\')
  44. {
  45. pSource++;
  46. switch (*pSource)
  47. {
  48. case L'n' :
  49. case L'N' :
  50. *pDest = L'\n';
  51. break;
  52. case L't' :
  53. case L'T' :
  54. *pDest = L'\t';
  55. break;
  56. case L'r' :
  57. case L'R' :
  58. *pDest = L'\r';
  59. break;
  60. default:
  61. *pDest = *pSource;
  62. }
  63. }
  64. else
  65. *pDest = *pSource;
  66. pDest++;
  67. }
  68. while (*++pSource);
  69. *pDest = '\0';
  70. SysFreeString(str);
  71. }
  72. else
  73. // graceful degradation: return untranslated string if we're out of memory
  74. // user sees ugly escape sequence but is better than failing altogether.
  75. newStr = str;
  76. }
  77. return newStr;
  78. };
  79. // v is an array (caller's supposed to check)
  80. // str is a string representing that array
  81. // this fcn checks for single element arrays
  82. // and if so, magically transforms
  83. // "{element}" to "element"
  84. // BSTR returned may or may not be the same as the one passed in.
  85. BSTR CTextTemplate::ProcessArray(const VARIANT& v, BSTR str)
  86. {
  87. if (SafeArrayGetDim(v.parray) == 1)
  88. {
  89. long lBound =0, uBound =0;
  90. SafeArrayGetLBound(v.parray, 1, &lBound);
  91. SafeArrayGetUBound(v.parray, 1, &uBound);
  92. UINT nStrLen = wcslen(str);
  93. assert( nStrLen >= 2 );
  94. // check if there's one element
  95. if (uBound == lBound)
  96. {
  97. // single dimensioned array, with a single element.
  98. // nuke the curlies by copying everything but.
  99. UINT lastChar = nStrLen - 2;
  100. for (UINT i = 1; i <= lastChar; i++)
  101. str[i-1] = str[i];
  102. str[lastChar] = L'\0';
  103. }
  104. else
  105. {
  106. //
  107. // convert the curlies to parentheses. note that this
  108. // only works for single dimensional arrays.
  109. //
  110. str[0] = '(';
  111. str[nStrLen-1] = ')';
  112. }
  113. }
  114. return str;
  115. }
  116. // concatentates property onto string
  117. // does so without quotes around the property, instead of:
  118. // str "prop"
  119. // you get:
  120. // str prop
  121. // we do *not* check for escapes in this function: we blindly strip off the leading & trailing quote
  122. void CTextTemplate::ConcatWithoutQuotes(WString& str, BSTR& property)
  123. {
  124. // dump the quotes
  125. if ((property[0] == L'\"') && (property[wcslen(property) -1] == L'\"'))
  126. {
  127. // hop past the first one
  128. WCHAR* p = property;
  129. p++;
  130. str += p;
  131. // null out the last one
  132. p = (wchar_t*)str;
  133. p[wcslen(p) -1] = L'\0';
  134. }
  135. else
  136. str += property;
  137. }
  138. BSTR CTextTemplate::Apply(IWbemClassObject* pObj)
  139. {
  140. WString wsText;
  141. WCHAR* pwc = (WCHAR*)m_wsTemplate;
  142. while(*pwc)
  143. {
  144. if(*pwc != L'%')
  145. {
  146. wsText += *pwc;
  147. }
  148. else
  149. {
  150. pwc++;
  151. if(*pwc == L'%')
  152. {
  153. // Double %
  154. // ========
  155. wsText += L'%';
  156. }
  157. else
  158. {
  159. // It's a property --- find the end
  160. // ================================
  161. WCHAR *pwcEnd = wcschr(pwc, L'%');
  162. if(pwcEnd == NULL)
  163. {
  164. // No end --- fail
  165. // ===============
  166. wsText += L"<error>";
  167. break;
  168. }
  169. else
  170. {
  171. // Look for the optional formatting string.
  172. WCHAR *pszFormat = wcschr(pwc, '(');
  173. // If we found a paren before what we thought was
  174. // the end, look for the end of the formatting string.
  175. // Once we find it, look again for the real end. We do
  176. // this in case the % we found was actually part of the
  177. // formatting string.
  178. if (pszFormat && pszFormat < pwcEnd)
  179. {
  180. pszFormat = wcschr(pszFormat + 1, ')');
  181. if (pszFormat)
  182. pwcEnd = wcschr(pszFormat + 1, '%');
  183. }
  184. WCHAR *wszName = new WCHAR[pwcEnd - pwc + 1];
  185. if (!wszName)
  186. return NULL;
  187. wcsncpy(wszName, pwc, pwcEnd - pwc);
  188. wszName[pwcEnd-pwc] = 0;
  189. // Look for the optional formatting string.
  190. if ((pszFormat = wcschr(wszName, '(')) != NULL)
  191. {
  192. WCHAR *pszEndFormat;
  193. *pszFormat = 0;
  194. pszFormat++;
  195. pszEndFormat = wcschr(pszFormat, ')');
  196. if (pszEndFormat)
  197. *pszEndFormat = 0;
  198. else
  199. // In case of a bad format string.
  200. pszFormat = NULL;
  201. }
  202. // Get it
  203. // ======
  204. if(!_wcsicmp(wszName, L"__TEXT"))
  205. {
  206. BSTR strText = NULL;
  207. pObj->GetObjectText(0, &strText);
  208. if(strText != NULL)
  209. {
  210. wsText += strText;
  211. SysFreeString( strText );
  212. }
  213. else
  214. wsText += L"<error>";
  215. }
  216. else if(IsEmbeddedObjectProperty(wszName))
  217. {
  218. // We have embedded object(s)
  219. // ==========================
  220. BSTR bstr = HandleEmbeddedObjectProperties(wszName, pObj);
  221. if (bstr)
  222. {
  223. // we want to do this here, rather than in the HandleEmbeddedObjectProperties
  224. // because that call can go recursive, thereby removing too many backwhacks!
  225. bstr = ReturnEscapedReturns(bstr);
  226. if (bstr)
  227. {
  228. ConcatWithoutQuotes(wsText, bstr);
  229. SysFreeString(bstr);
  230. }
  231. }
  232. }
  233. else
  234. {
  235. VARIANT v;
  236. VariantInit(&v);
  237. CIMTYPE ct;
  238. HRESULT hres = pObj->Get(wszName, 0, &v, &ct, NULL);
  239. // Append its value
  240. // ================
  241. if (WBEM_E_NOT_FOUND == hres)
  242. wsText += L"<unknown>";
  243. else if(FAILED(hres))
  244. wsText += L"<failed>";
  245. else if (V_VT(&v) == VT_NULL)
  246. {
  247. wsText += L"<null>";
  248. }
  249. else if (V_VT(&v) == VT_UNKNOWN)
  250. {
  251. BSTR strText = NULL;
  252. IWbemClassObject* pEmbeddedObj;
  253. if (SUCCEEDED(V_UNKNOWN(&v)->QueryInterface(IID_IWbemClassObject, (void**)&pEmbeddedObj)))
  254. {
  255. pEmbeddedObj->GetObjectText(0, &strText);
  256. pEmbeddedObj->Release();
  257. }
  258. if(strText != NULL)
  259. wsText += strText;
  260. else
  261. wsText += L"<error>";
  262. SysFreeString(strText);
  263. }
  264. else if ( V_VT(&v) == (VT_UNKNOWN | VT_ARRAY) )
  265. {
  266. // We have an array of objects
  267. // ==============================================
  268. long ix[2] = {0,0};
  269. long lLower, lUpper;
  270. int iDim = SafeArrayGetDim(v.parray);
  271. HRESULT hr=SafeArrayGetLBound(v.parray,1,&lLower);
  272. hr = SafeArrayGetUBound(v.parray, 1, &lUpper);
  273. wsText += L"{";
  274. for(ix[0] = lLower; ix[0] <= lUpper; ix[0]++)
  275. {
  276. IUnknown HUGEP *pUnk;
  277. hr = SafeArrayGetElement( v.parray,
  278. &(ix[0]),
  279. &pUnk);
  280. BSTR strText = NULL;
  281. IWbemClassObject* pEmbeddedObj;
  282. if (SUCCEEDED(pUnk->QueryInterface(
  283. IID_IWbemClassObject,
  284. (void**)&pEmbeddedObj)))
  285. {
  286. pEmbeddedObj->GetObjectText(0, &strText);
  287. pEmbeddedObj->Release();
  288. }
  289. if(strText != NULL)
  290. wsText += strText;
  291. else
  292. wsText += L"<error>";
  293. SysFreeString(strText);
  294. if(ix[0] < lUpper)
  295. {
  296. wsText += L", ";
  297. }
  298. }
  299. wsText += L"}";
  300. }
  301. else
  302. {
  303. CVar Var;
  304. Var.SetVariant(&v);
  305. BSTR str = Var.GetText(0, ct, pszFormat);
  306. if (str == NULL)
  307. {
  308. wsText += L"<error>";
  309. }
  310. else
  311. {
  312. if (V_VT(&v) & VT_ARRAY)
  313. str = ProcessArray(v, str);
  314. if (str)
  315. {
  316. str = ReturnEscapedReturns(str);
  317. if (str)
  318. {
  319. ConcatWithoutQuotes(wsText, str);
  320. SysFreeString(str);
  321. }
  322. }
  323. }
  324. }
  325. VariantClear(&v);
  326. }
  327. delete [] wszName;
  328. // Move the pointer
  329. // ================
  330. pwc = pwcEnd;
  331. }
  332. }
  333. }
  334. pwc++;
  335. }
  336. BSTR str = SysAllocString(wsText);
  337. return str;
  338. }
  339. BSTR CTextTemplate::HandleEmbeddedObjectProperties(WCHAR* wszTemplate, IWbemClassObject* pObj)
  340. {
  341. WString wsText;
  342. // Get the embedded object/array
  343. // =============================
  344. WCHAR* pwc = wszTemplate;
  345. WCHAR* pwcEnd = wcschr(wszTemplate, L'.');
  346. if(!pwcEnd)
  347. {
  348. BSTR bstr = SysAllocString(L"<error>");
  349. return bstr;
  350. }
  351. WCHAR* wszName = new WCHAR[pwcEnd - pwc + 1];
  352. if (!wszName)
  353. return SysAllocString(L"<failed>");
  354. wcsncpy(wszName, pwc, pwcEnd - pwc);
  355. wszName[pwcEnd-pwc] = 0;
  356. VARIANT v;
  357. VariantInit(&v);
  358. HRESULT hres = pObj->Get(wszName, 0, &v, NULL, NULL);
  359. delete [] wszName;
  360. if (WBEM_E_NOT_FOUND == hres)
  361. return SysAllocString(L"<unknown>");
  362. else if(FAILED(hres))
  363. return SysAllocString(L"<failed>");
  364. else if (V_VT(&v) == VT_NULL)
  365. return SysAllocString(L"<null>");
  366. pwc = wcschr(wszTemplate, L'.');
  367. WCHAR wszProperty[1024];
  368. wcscpy(wszProperty, (pwc + 1));
  369. if(V_VT(&v) == VT_UNKNOWN)
  370. {
  371. // We have a single object, so process it
  372. // =======================================
  373. BSTR bstr = GetPropertyFromIUnknown(wszProperty, V_UNKNOWN(&v));
  374. if (bstr)
  375. {
  376. wsText += bstr;
  377. SysFreeString(bstr);
  378. }
  379. }
  380. else if((V_VT(&v) & VT_ARRAY) && (V_VT(&v) & VT_UNKNOWN))
  381. {
  382. // We have an array of objects, so process the elements
  383. // ====================================================
  384. long ix[2] = {0,0};
  385. long lLower, lUpper;
  386. int iDim = SafeArrayGetDim(v.parray);
  387. HRESULT hr = SafeArrayGetLBound(v.parray, 1, &lLower);
  388. hr = SafeArrayGetUBound(v.parray, 1, &lUpper);
  389. wsText += L"{";
  390. for(ix[0] = lLower; ix[0] <= lUpper; ix[0]++){
  391. IUnknown HUGEP *pUnk;
  392. hr = SafeArrayGetElement(v.parray, &(ix[0]), &pUnk);
  393. BSTR bstr = GetPropertyFromIUnknown(wszProperty, pUnk);
  394. if (bstr)
  395. {
  396. wsText += bstr;
  397. SysFreeString(bstr);
  398. }
  399. if(ix[0] < lUpper)
  400. {
  401. wsText += L", ";
  402. }
  403. }
  404. wsText += L"}";
  405. }
  406. else
  407. {
  408. // We have something else, which we shouldn't
  409. // ==========================================
  410. wsText += L"<error>";
  411. }
  412. VariantClear(&v);
  413. BSTR str = SysAllocString(wsText);
  414. // we don't want to do this here, it could go recursive & remove too many backwhacks!
  415. // str = ReturnEscapedReturns(str);
  416. return str;
  417. }
  418. BOOL CTextTemplate::IsEmbeddedObjectProperty(WCHAR * wszProperty)
  419. {
  420. WCHAR* pwcStart = wcschr(wszProperty, L'[');
  421. if(pwcStart)
  422. {
  423. return TRUE;
  424. }
  425. pwcStart = wcschr(wszProperty, L'.');
  426. if(pwcStart)
  427. {
  428. return TRUE;
  429. }
  430. return FALSE;
  431. }
  432. BSTR CTextTemplate::GetPropertyFromIUnknown(WCHAR *wszProperty, IUnknown *pUnk)
  433. {
  434. BSTR bstrRetVal = NULL;
  435. IWbemClassObject *pEmbedded = NULL;
  436. // Get an IWbemClassObject pointer
  437. // ===============================
  438. HRESULT hres = pUnk->QueryInterface( IID_IWbemClassObject,
  439. (void **)&pEmbedded );
  440. if(SUCCEEDED(hres))
  441. {
  442. // For each object get the desired property
  443. // ========================================
  444. if(IsEmbeddedObjectProperty(wszProperty))
  445. {
  446. // We have more embedded object(s)
  447. // ===============================
  448. BSTR bstr = HandleEmbeddedObjectProperties( wszProperty,
  449. pEmbedded );
  450. if (bstr)
  451. {
  452. bstrRetVal = SysAllocString(bstr);
  453. SysFreeString(bstr);
  454. }
  455. }
  456. else
  457. {
  458. VARIANT vProp;
  459. VariantInit(&vProp);
  460. CIMTYPE ct;
  461. HRESULT hRes = pEmbedded->Get( wszProperty, 0, &vProp,
  462. &ct, NULL );
  463. if (WBEM_E_NOT_FOUND == hRes)
  464. {
  465. bstrRetVal = SysAllocString(L"<unknown>");
  466. }
  467. else if(FAILED(hRes))
  468. {
  469. bstrRetVal = SysAllocString(L"<failed>");
  470. }
  471. else if (V_VT(&vProp) == VT_NULL)
  472. {
  473. bstrRetVal = SysAllocString(L"<null>");
  474. }
  475. else
  476. {
  477. BSTR str = NULL;
  478. if ( V_VT(&vProp) == ( VT_UNKNOWN | VT_ARRAY ) )
  479. {
  480. WString wsText;
  481. // We have an array of objects
  482. // ==============================================
  483. long ix[2] = {0,0};
  484. long lLower, lUpper;
  485. int iDim = SafeArrayGetDim(vProp.parray);
  486. HRESULT hr=SafeArrayGetLBound(vProp.parray,1,&lLower);
  487. hr = SafeArrayGetUBound(vProp.parray, 1, &lUpper);
  488. wsText += L"{";
  489. for(ix[0] = lLower; ix[0] <= lUpper; ix[0]++)
  490. {
  491. IUnknown *pUnkHere = NULL;
  492. hr = SafeArrayGetElement( vProp.parray,
  493. &(ix[0]),
  494. &pUnkHere );
  495. BSTR strText = NULL;
  496. IWbemClassObject* pEmbeddedObj = NULL;
  497. if (SUCCEEDED(pUnkHere->QueryInterface(
  498. IID_IWbemClassObject,
  499. (void**)&pEmbeddedObj)))
  500. {
  501. pEmbeddedObj->GetObjectText(0, &strText);
  502. pEmbeddedObj->Release();
  503. }
  504. if(strText != NULL)
  505. wsText += strText;
  506. else
  507. wsText += L"<error>";
  508. SysFreeString(strText);
  509. if(ix[0] < lUpper)
  510. {
  511. wsText += L", ";
  512. }
  513. }
  514. wsText += L"}";
  515. str = SysAllocString( wsText );
  516. }
  517. else if ( V_VT(&vProp) != VT_UNKNOWN )
  518. {
  519. CVar Var;
  520. Var.SetVariant(&vProp);
  521. str = Var.GetText( 0, ct );
  522. }
  523. else
  524. {
  525. IWbemClassObject* pEmbedded2;
  526. hres = V_UNKNOWN(&vProp)->QueryInterface(
  527. IID_IWbemClassObject,
  528. (void**)&pEmbedded2 );
  529. if ( SUCCEEDED(hres) )
  530. {
  531. pEmbedded2->GetObjectText( 0, &str );
  532. pEmbedded2->Release();
  533. }
  534. }
  535. if( str == NULL )
  536. {
  537. bstrRetVal = SysAllocString(L"<error>");
  538. }
  539. else
  540. {
  541. bstrRetVal = SysAllocString(str);
  542. SysFreeString(str);
  543. }
  544. if ( V_VT(&vProp) & VT_ARRAY )
  545. {
  546. bstrRetVal = ProcessArray(vProp, bstrRetVal);
  547. }
  548. }
  549. VariantClear( &vProp );
  550. }
  551. pEmbedded->Release();
  552. pEmbedded = NULL;
  553. }
  554. return bstrRetVal;
  555. }