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.

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