windows-nt/Source/XPSP1/NT/admin/wmi/wbem/winmgmt/wbemcomn/txttempl.cpp
2020-09-26 16:20:57 +08:00

682 lines
21 KiB
C++

/*++
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"
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, '%');
}
WCHAR *wszName = new WCHAR[pwcEnd - pwc + 1];
if (!wszName)
return NULL;
wcsncpy(wszName, pwc, pwcEnd - pwc);
wszName[pwcEnd-pwc] = 0;
// Look for the optional formatting string.
if ((pszFormat = wcschr(wszName, '(')) != 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(!_wcsicmp(wszName, L"__TEXT"))
{
BSTR strText = NULL;
pObj->GetObjectText(0, &strText);
if(strText != NULL)
{
wsText += strText;
SysFreeString( strText );
}
else
wsText += L"<error>";
}
else if(IsEmbeddedObjectProperty(wszName))
{
// We have embedded object(s)
// ==========================
BSTR bstr = HandleEmbeddedObjectProperties(wszName, pObj);
if (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);
SysFreeString(bstr);
}
}
}
else
{
VARIANT v;
VariantInit(&v);
CIMTYPE ct;
HRESULT hres = pObj->Get(wszName, 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();
}
if(strText != NULL)
wsText += strText;
else
wsText += L"<error>";
SysFreeString(strText);
}
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);
HRESULT hr=SafeArrayGetLBound(v.parray,1,&lLower);
hr = SafeArrayGetUBound(v.parray, 1, &lUpper);
wsText += L"{";
for(ix[0] = lLower; ix[0] <= lUpper; ix[0]++)
{
IUnknown HUGEP *pUnk;
hr = 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();
}
if(strText != NULL)
wsText += strText;
else
wsText += L"<error>";
SysFreeString(strText);
if(ix[0] < lUpper)
{
wsText += L", ";
}
}
wsText += L"}";
}
else
{
CVar Var;
Var.SetVariant(&v);
BSTR str = Var.GetText(0, ct, pszFormat);
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);
SysFreeString(str);
}
}
}
}
VariantClear(&v);
}
delete [] wszName;
// 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 (!wszName)
return SysAllocString(L"<failed>");
wcsncpy(wszName, pwc, pwcEnd - pwc);
wszName[pwcEnd-pwc] = 0;
VARIANT v;
VariantInit(&v);
HRESULT hres = pObj->Get(wszName, 0, &v, NULL, NULL);
delete [] wszName;
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];
wcscpy(wszProperty, (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)
{
wsText += bstr;
SysFreeString(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);
HRESULT hr = SafeArrayGetLBound(v.parray, 1, &lLower);
hr = SafeArrayGetUBound(v.parray, 1, &lUpper);
wsText += L"{";
for(ix[0] = lLower; ix[0] <= lUpper; ix[0]++){
IUnknown HUGEP *pUnk;
hr = SafeArrayGetElement(v.parray, &(ix[0]), &pUnk);
BSTR bstr = GetPropertyFromIUnknown(wszProperty, pUnk);
if (bstr)
{
wsText += bstr;
SysFreeString(bstr);
}
if(ix[0] < lUpper)
{
wsText += L", ";
}
}
wsText += L"}";
}
else
{
// We have something else, which we shouldn't
// ==========================================
wsText += L"<error>";
}
VariantClear(&v);
BSTR str = SysAllocString(wsText);
// we don't want to do this here, it could go recursive & remove too many backwhacks!
// str = ReturnEscapedReturns(str);
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))
{
// 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 vProp;
VariantInit(&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();
}
if(strText != NULL)
wsText += strText;
else
wsText += L"<error>";
SysFreeString(strText);
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 = SysAllocString(str);
SysFreeString(str);
}
if ( V_VT(&vProp) & VT_ARRAY )
{
bstrRetVal = ProcessArray(vProp, bstrRetVal);
}
}
VariantClear( &vProp );
}
pEmbedded->Release();
pEmbedded = NULL;
}
return bstrRetVal;
}