|
|
/*++
Copyright (C) 1996-2001 Microsoft Corporation
Module Name:
Abstract:
History:
--*/
#include "precomp.h"
#include "txttempl.h"
#include <stdio.h>
#include <assert.h>
#include "var.h"
#include <arrtempl.h>
CTextTemplate::CTextTemplate(LPCWSTR wszTemplate) : m_wsTemplate(wszTemplate) { } CTextTemplate::~CTextTemplate() { }
void CTextTemplate::SetTemplate(LPCWSTR wszTemplate) { m_wsTemplate = wszTemplate; }
// replace escape sequences with proper characters
// currently enabled for:
// \t; \n; \r;
// anything else is translated literally, minus the backwhack
// returned string may or may not be same string as passed in
// if not, then arg string is deleted & a new one returned.
// -=> Thou Hast Been Forewarned!
BSTR CTextTemplate::ReturnEscapedReturns(BSTR str) { BSTR newStr = str; // if we find a backwhack
if (NULL != wcschr(str, L'\\')) { if (newStr = SysAllocString(str)) { WCHAR *pSource, *pDest; ZeroMemory(newStr, (wcslen(str)+1) *2);
pDest = newStr; pSource = str;
do { if (*pSource == L'\\') { pSource++; switch (*pSource) { case L'n' : case L'N' : *pDest = L'\n'; break; case L't' : case L'T' : *pDest = L'\t'; break; case L'r' : case L'R' : *pDest = L'\r'; break; default: *pDest = *pSource; } } else *pDest = *pSource;
pDest++; } while (*++pSource);
*pDest = '\0'; SysFreeString(str); } else // graceful degradation: return untranslated string if we're out of memory
// user sees ugly escape sequence but is better than failing altogether.
newStr = str; }
return newStr; };
// v is an array (caller's supposed to check)
// str is a string representing that array
// this fcn checks for single element arrays
// and if so, magically transforms
// "{element}" to "element"
// BSTR returned may or may not be the same as the one passed in.
BSTR CTextTemplate::ProcessArray(const VARIANT& v, BSTR str) { if (SafeArrayGetDim(v.parray) == 1) { long lBound =0, uBound =0; SafeArrayGetLBound(v.parray, 1, &lBound); SafeArrayGetUBound(v.parray, 1, &uBound);
UINT nStrLen = wcslen(str);
assert( nStrLen >= 2 );
// check if there's one element
if (uBound == lBound) { // single dimensioned array, with a single element.
// nuke the curlies by copying everything but.
UINT lastChar = nStrLen - 2;
for (UINT i = 1; i <= lastChar; i++) str[i-1] = str[i]; str[lastChar] = L'\0'; } else { //
// convert the curlies to parentheses. note that this
// only works for single dimensional arrays.
//
str[0] = '('; str[nStrLen-1] = ')'; } } return str; }
// concatentates property onto string
// does so without quotes around the property, instead of:
// str "prop"
// you get:
// str prop
// we do *not* check for escapes in this function: we blindly strip off the leading & trailing quote
void CTextTemplate::ConcatWithoutQuotes(WString& str, BSTR& property) { // dump the quotes
if ((property[0] == L'\"') && (property[wcslen(property) -1] == L'\"')) { // hop past the first one
WCHAR* p = property; p++; str += p;
// null out the last one
p = (wchar_t*)str; p[wcslen(p) -1] = L'\0'; } else str += property;
}
BSTR CTextTemplate::Apply(IWbemClassObject* pObj) { WString wsText; WCHAR* pwc = (WCHAR*)m_wsTemplate; while(*pwc) { if(*pwc != L'%') { wsText += *pwc; } else { pwc++;
if(*pwc == L'%') { // Double %
// ========
wsText += L'%'; } else { // It's a property --- find the end
// ================================
WCHAR *pwcEnd = wcschr(pwc, L'%'); if(pwcEnd == NULL) { // No end --- fail
// ===============
wsText += L"<error>"; break; } else { // Look for the optional formatting string.
WCHAR *pszFormat = wcschr(pwc, '(');
// If we found a paren before what we thought was
// the end, look for the end of the formatting string.
// Once we find it, look again for the real end. We do
// this in case the % we found was actually part of the
// formatting string.
if (pszFormat && pszFormat < pwcEnd) { pszFormat = wcschr(pszFormat + 1, ')'); if (pszFormat) pwcEnd = wcschr(pszFormat + 1, '%'); }
wmilib::auto_buffer<WCHAR> wszName(new WCHAR[pwcEnd - pwc + 1]); if (NULL == wszName.get()) return NULL;
wcsncpy(wszName.get(), pwc, pwcEnd - pwc); wszName[pwcEnd-pwc] = 0;
// Look for the optional formatting string.
if ((pszFormat = wcschr(wszName.get(), '(')) != NULL) { WCHAR *pszEndFormat;
*pszFormat = 0; pszFormat++;
pszEndFormat = wcschr(pszFormat, ')');
if (pszEndFormat) *pszEndFormat = 0; else // In case of a bad format string.
pszFormat = NULL; }
// Get it
// ======
if(!wbem_wcsicmp(wszName.get(), L"__TEXT")) { BSTR strText = NULL;
pObj->GetObjectText(0, &strText); if(strText != NULL) { CSysFreeMe fm(strText); wsText += strText; } else wsText += L"<error>"; } else if(IsEmbeddedObjectProperty(wszName.get())) { // We have embedded object(s)
// ==========================
BSTR bstr = HandleEmbeddedObjectProperties(wszName.get(), pObj);
if (bstr) { CSysFreeMeRef fmref(bstr); // we want to do this here, rather than in the HandleEmbeddedObjectProperties
// because that call can go recursive, thereby removing too many backwhacks!
bstr = ReturnEscapedReturns(bstr); if (bstr) { ConcatWithoutQuotes(wsText, bstr); } } } else { _variant_t v; CIMTYPE ct; HRESULT hres = pObj->Get(wszName.get(), 0, &v, &ct, NULL); // Append its value
// ================
if (WBEM_E_NOT_FOUND == hres) wsText += L"<unknown>"; else if(FAILED(hres)) wsText += L"<failed>"; else if (V_VT(&v) == VT_NULL) { wsText += L"<null>"; } else if (V_VT(&v) == VT_UNKNOWN) { BSTR strText = NULL; IWbemClassObject* pEmbeddedObj; if (SUCCEEDED(V_UNKNOWN(&v)->QueryInterface(IID_IWbemClassObject, (void**)&pEmbeddedObj))) { pEmbeddedObj->GetObjectText(0, &strText); pEmbeddedObj->Release(); } CSysFreeMe fm(strText);
if(strText != NULL) wsText += strText; else wsText += L"<error>"; } else if ( V_VT(&v) == (VT_UNKNOWN | VT_ARRAY) ) { // We have an array of objects
// ==============================================
long ix[2] = {0,0}; long lLower, lUpper;
int iDim = SafeArrayGetDim(v.parray); SafeArrayGetLBound(v.parray,1,&lLower); SafeArrayGetUBound(v.parray, 1, &lUpper);
wsText += L"{";
for(ix[0] = lLower; ix[0] <= lUpper; ix[0]++) { IUnknown HUGEP *pUnk; // this array access does not copy anything, hence success assumed
SafeArrayGetElement( v.parray, &(ix[0]), &pUnk);
BSTR strText = NULL; IWbemClassObject* pEmbeddedObj; if (SUCCEEDED(pUnk->QueryInterface( IID_IWbemClassObject, (void**)&pEmbeddedObj))) { pEmbeddedObj->GetObjectText(0, &strText); pEmbeddedObj->Release(); } CSysFreeMe fm(strText);
if(strText != NULL) wsText += strText; else wsText += L"<error>";
if(ix[0] < lUpper) { wsText += L", "; } }
wsText += L"}"; } else { CVar Var; Var.SetVariant(&v); BSTR str = Var.GetText(0, ct, pszFormat);
CSysFreeMeRef fmRef(str);
if (str == NULL) { wsText += L"<error>"; } else { if (V_VT(&v) & VT_ARRAY) str = ProcessArray(v, str);
if (str) { str = ReturnEscapedReturns(str);
if (str) { ConcatWithoutQuotes(wsText, str); } } } } } // Move the pointer
pwc = pwcEnd; } } }
pwc++; }
BSTR str = SysAllocString(wsText); return str; }
BSTR CTextTemplate::HandleEmbeddedObjectProperties(WCHAR* wszTemplate, IWbemClassObject* pObj) { WString wsText;
// Get the embedded object/array
// =============================
WCHAR* pwc = wszTemplate; WCHAR* pwcEnd = wcschr(wszTemplate, L'.');
if(!pwcEnd) { BSTR bstr = SysAllocString(L"<error>"); return bstr; }
WCHAR* wszName = new WCHAR[pwcEnd - pwc + 1]; if (NULL == wszName) return SysAllocString(L"<failed>"); CVectorDeleteMe<WCHAR> dm(wszName);
wcsncpy(wszName, pwc, pwcEnd - pwc); wszName[pwcEnd-pwc] = 0;
_variant_t v; HRESULT hres = pObj->Get(wszName, 0, &v, NULL, NULL);
if (WBEM_E_NOT_FOUND == hres) return SysAllocString(L"<unknown>"); else if(FAILED(hres)) return SysAllocString(L"<failed>"); else if (V_VT(&v) == VT_NULL) return SysAllocString(L"<null>");
pwc = wcschr(wszTemplate, L'.'); WCHAR wszProperty[1024]; StringCchCopyW(wszProperty, 1024, (pwc + 1));
if(V_VT(&v) == VT_UNKNOWN) { // We have a single object, so process it
// =======================================
BSTR bstr = GetPropertyFromIUnknown(wszProperty, V_UNKNOWN(&v));
if (bstr) { CSysFreeMe fm(bstr); wsText += bstr; } } else if((V_VT(&v) & VT_ARRAY) && (V_VT(&v) & VT_UNKNOWN)) { // We have an array of objects, so process the elements
// ====================================================
long ix[2] = {0,0}; long lLower, lUpper;
int iDim = SafeArrayGetDim(v.parray);
SafeArrayGetLBound(v.parray, 1, &lLower); SafeArrayGetUBound(v.parray, 1, &lUpper);
wsText += L"{";
for(ix[0] = lLower; ix[0] <= lUpper; ix[0]++){
IUnknown HUGEP *pUnk; // no copy performed when accessing the n-th element, hence no failure
SafeArrayGetElement(v.parray, &(ix[0]), &pUnk);
BSTR bstr = GetPropertyFromIUnknown(wszProperty, pUnk); if (bstr) { CSysFreeMe fm(bstr); wsText += bstr; }
if(ix[0] < lUpper) { wsText += L", "; } }
wsText += L"}"; } else { // We have something else, which we shouldn't
// ==========================================
wsText += L"<error>"; }
BSTR str = SysAllocString(wsText); return str; }
BOOL CTextTemplate::IsEmbeddedObjectProperty(WCHAR * wszProperty) { WCHAR* pwcStart = wcschr(wszProperty, L'[');
if(pwcStart) { return TRUE; }
pwcStart = wcschr(wszProperty, L'.');
if(pwcStart) { return TRUE; }
return FALSE; }
BSTR CTextTemplate::GetPropertyFromIUnknown(WCHAR *wszProperty, IUnknown *pUnk) { BSTR bstrRetVal = NULL; IWbemClassObject *pEmbedded = NULL;
// Get an IWbemClassObject pointer
// ===============================
HRESULT hres = pUnk->QueryInterface( IID_IWbemClassObject, (void **)&pEmbedded );
if(SUCCEEDED(hres)) { CReleaseMe rm(pEmbedded); // For each object get the desired property
if(IsEmbeddedObjectProperty(wszProperty)) { // We have more embedded object(s)
// ===============================
BSTR bstr = HandleEmbeddedObjectProperties( wszProperty, pEmbedded ); if (bstr) { bstrRetVal = SysAllocString(bstr); SysFreeString(bstr); } } else { _variant_t vProp; CIMTYPE ct; HRESULT hRes = pEmbedded->Get( wszProperty, 0, &vProp, &ct, NULL );
if (WBEM_E_NOT_FOUND == hRes) { bstrRetVal = SysAllocString(L"<unknown>"); } else if(FAILED(hRes)) { bstrRetVal = SysAllocString(L"<failed>"); } else if (V_VT(&vProp) == VT_NULL) { bstrRetVal = SysAllocString(L"<null>"); } else { BSTR str = NULL; if ( V_VT(&vProp) == ( VT_UNKNOWN | VT_ARRAY ) ) { WString wsText;
// We have an array of objects
// ==============================================
long ix[2] = {0,0}; long lLower, lUpper; int iDim = SafeArrayGetDim(vProp.parray); HRESULT hr=SafeArrayGetLBound(vProp.parray,1,&lLower); hr = SafeArrayGetUBound(vProp.parray, 1, &lUpper); wsText += L"{";
for(ix[0] = lLower; ix[0] <= lUpper; ix[0]++) { IUnknown *pUnkHere = NULL; hr = SafeArrayGetElement( vProp.parray, &(ix[0]), &pUnkHere ); BSTR strText = NULL; IWbemClassObject* pEmbeddedObj = NULL; if (SUCCEEDED(pUnkHere->QueryInterface( IID_IWbemClassObject, (void**)&pEmbeddedObj))) { pEmbeddedObj->GetObjectText(0, &strText); pEmbeddedObj->Release(); } CSysFreeMe sfm(strText); if(strText != NULL) wsText += strText; else wsText += L"<error>";
if(ix[0] < lUpper) { wsText += L", "; } }
wsText += L"}";
str = SysAllocString( wsText ); } else if ( V_VT(&vProp) != VT_UNKNOWN ) { CVar Var; Var.SetVariant(&vProp); str = Var.GetText( 0, ct ); } else { IWbemClassObject* pEmbedded2; hres = V_UNKNOWN(&vProp)->QueryInterface( IID_IWbemClassObject, (void**)&pEmbedded2 ); if ( SUCCEEDED(hres) ) { pEmbedded2->GetObjectText( 0, &str ); pEmbedded2->Release(); } } if( str == NULL ) { bstrRetVal = SysAllocString(L"<error>"); } else { bstrRetVal = str; }
if ( V_VT(&vProp) & VT_ARRAY ) { bstrRetVal = ProcessArray(vProp, bstrRetVal); } } }
}
return bstrRetVal; }
|