498 lines
13 KiB
C++
498 lines
13 KiB
C++
/*---------------------------------------------------------------------------
|
|
File: VarData.cpp
|
|
|
|
Comments: CVarData represents one level in the VarSet. It has a variant
|
|
value, and a map containing one or more subvalues.
|
|
|
|
(c) Copyright 1995-1998, Mission Critical Software, Inc., All Rights Reserved
|
|
Proprietary and confidential to Mission Critical Software, Inc.
|
|
|
|
REVISION LOG ENTRY
|
|
Revision By: Christy Boles
|
|
Revised on 11/19/98 17:24:56
|
|
|
|
---------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
#include "VarData.h"
|
|
#include "VarMap.h"
|
|
#include "DotStr.hpp"
|
|
|
|
#ifdef STRIPPED_VARSET
|
|
#include "Varset.h"
|
|
#include "NoMcs.h"
|
|
#else
|
|
#include <VarSet.h>
|
|
#include "McString.h"
|
|
#include "McLog.h"
|
|
using namespace McString;
|
|
#endif
|
|
#include "VSet.h"
|
|
#include <comdef.h>
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
|
|
int
|
|
CVarData::SetData(
|
|
CString key, // in - key value
|
|
VARIANT * var, // in - data value
|
|
BOOL bCoerce, // in - flag, whether to coerce to a persistable value
|
|
HRESULT * pResult // out- optional return code
|
|
)
|
|
{
|
|
int nCreated = 0;
|
|
_variant_t newVal(var);
|
|
HRESULT hr = S_OK;
|
|
|
|
if ( key.IsEmpty() )
|
|
{
|
|
m_cs.Lock();
|
|
// set my data value
|
|
if ( ! bCoerce )
|
|
{
|
|
m_var.Copy(&newVal);
|
|
}
|
|
else
|
|
{
|
|
// need to coerce the value to an appropriate type
|
|
|
|
if ( var->vt == VT_DISPATCH || var->vt == VT_UNKNOWN )
|
|
{
|
|
// if it's an IUnknown, see if it supports IDispatch
|
|
IDispatchPtr pDisp;
|
|
|
|
pDisp = newVal;
|
|
|
|
if ( pDisp != NULL )
|
|
{
|
|
// the object supports IDispatch
|
|
// try to get the default property
|
|
_variant_t defPropVar;
|
|
DISPPARAMS dispParamsNoArgs = {NULL, NULL, 0, 0};
|
|
|
|
hr = pDisp->Invoke(0,
|
|
IID_NULL,
|
|
LOCALE_USER_DEFAULT,
|
|
DISPATCH_PROPERTYGET,
|
|
&dispParamsNoArgs,
|
|
&defPropVar,
|
|
NULL,
|
|
NULL);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
// we got the default property
|
|
newVal = defPropVar;
|
|
}
|
|
else
|
|
{
|
|
MC_LOG("VarSet::put - unable to retrieve default property for IDispatch object. Put operation failed, hr=" << hr << "returning E_INVALIDARG");
|
|
hr = E_INVALIDARG;
|
|
}
|
|
}
|
|
}
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if ( newVal.vt & VT_BYREF )
|
|
{
|
|
if ( newVal.vt == (VT_VARIANT | VT_BYREF) )
|
|
{
|
|
m_var.Copy(newVal.pvarVal);
|
|
}
|
|
else
|
|
{
|
|
hr = ::VariantChangeType(&newVal,&newVal,0,newVal.vt & ~VT_BYREF);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
m_var.Copy(&newVal);
|
|
}
|
|
else
|
|
{
|
|
MC_LOG("VarSet::put - failed to dereference variant of type " << newVal.vt << ". Put operation failed, hr=" <<hr);
|
|
hr = E_INVALIDARG;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_var.Copy(&newVal);
|
|
}
|
|
}
|
|
}
|
|
m_cs.Unlock();
|
|
}
|
|
else
|
|
{
|
|
// set the value for a child
|
|
|
|
CDottedString s(key);
|
|
CString seg;
|
|
CVarData * pObj;
|
|
CVarData * pChild;
|
|
|
|
s.GetSegment(0,seg);
|
|
|
|
m_cs.Lock();
|
|
if ( ! m_children )
|
|
{
|
|
// create the child map if it does not exist
|
|
m_children = new CMapStringToVar(IsCaseSensitive(),IsIndexed(), AllowRehashing() );
|
|
if (!m_children)
|
|
{
|
|
m_cs.Unlock();
|
|
return nCreated;
|
|
}
|
|
}
|
|
// look for the first segment of the entry in the child map
|
|
if ( ! m_children->Lookup(seg,pObj) )
|
|
{
|
|
// add it if it doesn't exist
|
|
pChild = new CVarData;
|
|
if (!pChild)
|
|
{
|
|
m_cs.Unlock();
|
|
return nCreated;
|
|
}
|
|
pChild->SetCaseSensitive(IsCaseSensitive());
|
|
pChild->SetAllowRehashing(AllowRehashing());
|
|
pChild->SetIndexed(IsIndexed());
|
|
m_children->SetAt(seg,pChild);
|
|
nCreated++; // we added a new node
|
|
}
|
|
else
|
|
{
|
|
pChild = (CVarData*)pObj;
|
|
}
|
|
// strip off the first segment from the property name, and call SetData
|
|
// recursively on the child item
|
|
nCreated += pChild->SetData(key.Right(key.GetLength() - seg.GetLength()-1),var,bCoerce,&hr);
|
|
m_cs.Unlock();
|
|
}
|
|
if ( pResult )
|
|
{
|
|
(*pResult) = hr;
|
|
}
|
|
return nCreated;
|
|
}
|
|
|
|
void
|
|
CVarData::RemoveAll()
|
|
{
|
|
// remove all children from the map
|
|
m_cs.Lock();
|
|
if ( m_children && ! m_children->IsEmpty() )
|
|
{
|
|
// Enumerate the MAP and delete each object
|
|
POSITION pos;
|
|
CString key;
|
|
CVarData * pObj;
|
|
|
|
pos = m_children->GetStartPosition();
|
|
|
|
while ( pos )
|
|
{
|
|
m_children->GetNextAssoc(pos,key,pObj);
|
|
if ( pObj )
|
|
{
|
|
delete pObj;
|
|
}
|
|
}
|
|
m_children->RemoveAll();
|
|
}
|
|
if ( m_children )
|
|
{
|
|
delete m_children;
|
|
m_children = NULL;
|
|
}
|
|
m_cs.Unlock();
|
|
}
|
|
|
|
BOOL // ret- TRUE if key exists in the map
|
|
CVarData::Lookup(
|
|
LPCTSTR key, // in - key to search for
|
|
CVarData *& rValue // out- value
|
|
)
|
|
{
|
|
if ( m_children )
|
|
{
|
|
return m_children->Lookup(key,rValue);
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOL // ret- TRUE if there are sub-items for this node
|
|
CVarData::HasChildren()
|
|
{
|
|
return m_children && !m_children->IsEmpty();
|
|
}
|
|
|
|
void
|
|
CVarData::SetAt(
|
|
LPCTSTR key, // in - key
|
|
CVarData * newValue // in - new value
|
|
)
|
|
{
|
|
if ( ! m_children )
|
|
{
|
|
// create map to hold children if it doesn't already exist
|
|
m_children = new CMapStringToVar(IsCaseSensitive(),IsIndexed(),AllowRehashing());
|
|
if (!m_children)
|
|
return;
|
|
}
|
|
m_children->SetAt(key,newValue);
|
|
}
|
|
|
|
void
|
|
CVarData::SetIndexed(
|
|
BOOL nVal
|
|
)
|
|
{
|
|
if ( m_children )
|
|
{
|
|
m_children->SetIndexed(nVal);
|
|
}
|
|
if ( nVal )
|
|
{
|
|
m_options |= CVARDATA_INDEXED;
|
|
}
|
|
else
|
|
{
|
|
m_options &= ~CVARDATA_INDEXED;
|
|
}
|
|
}
|
|
|
|
void
|
|
CVarData::SetCaseSensitive(
|
|
BOOL nVal // in - whether to make lookups case-sensitive
|
|
)
|
|
{
|
|
if ( m_children )
|
|
{
|
|
m_children->SetCaseSensitive(nVal);
|
|
}
|
|
if ( nVal )
|
|
{
|
|
m_options |= CVARDATA_CASE_SENSITIVE;
|
|
}
|
|
else
|
|
{
|
|
m_options &= ~CVARDATA_CASE_SENSITIVE;
|
|
}
|
|
}
|
|
|
|
void
|
|
CVarData::SetAllowRehashing(
|
|
BOOL nVal // in - whether to allow the table to be rehashed for better performance
|
|
)
|
|
{
|
|
if ( m_children )
|
|
{
|
|
m_children->SetAllowRehash(nVal);
|
|
}
|
|
if ( nVal )
|
|
{
|
|
m_options |= CVARDATA_ALLOWREHASH;
|
|
}
|
|
else
|
|
{
|
|
m_options &= ~CVARDATA_ALLOWREHASH;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
HRESULT
|
|
CVarData::WriteToStream(
|
|
LPSTREAM pS // in - stream to write data to
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL hasChildren = (m_children != NULL);
|
|
|
|
// save the variant
|
|
hr = m_var.WriteToStream(pS);
|
|
|
|
if (SUCCEEDED(hr) )
|
|
{
|
|
// save children, if any
|
|
ULONG result;
|
|
hr = pS->Write(&hasChildren,(sizeof hasChildren),&result);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if ( m_children )
|
|
{
|
|
hr = m_children->WriteToStream(pS);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
HRESULT
|
|
CVarData::ReadFromStream(
|
|
LPSTREAM pS // in - stream to read data from
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BOOL hasChildren;
|
|
ULONG result;
|
|
|
|
// read the variant
|
|
hr = m_var.ReadFromStream(pS);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = pS->Read(&hasChildren,(sizeof hasChildren),&result);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
if ( hasChildren )
|
|
{
|
|
// create the child array
|
|
m_children = new CMapStringToVar(IsCaseSensitive(),IsIndexed(),AllowRehashing());
|
|
if (!m_children)
|
|
return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
|
|
hr = m_children->ReadFromStream(pS);
|
|
}
|
|
}
|
|
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
DWORD // ret- Length, in bytes to write the data to a stream
|
|
CVarData::CalculateStreamedLength()
|
|
{
|
|
HRESULT hr =S_OK;
|
|
DWORD len = sizeof (VARTYPE);
|
|
|
|
// Calculate size needed for root data value
|
|
|
|
int cbWrite = 0;
|
|
switch (m_var.vt)
|
|
{
|
|
case VT_UNKNOWN:
|
|
case VT_DISPATCH:
|
|
{
|
|
CComQIPtr<IPersistStream> spStream = m_var.punkVal;
|
|
if( spStream )
|
|
{
|
|
len += sizeof(CLSID);
|
|
ULARGE_INTEGER uiSize = { 0 };
|
|
hr = spStream->GetSizeMax(&uiSize);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
len += uiSize.LowPart;
|
|
}
|
|
}
|
|
break;
|
|
case VT_UI1:
|
|
case VT_I1:
|
|
cbWrite = sizeof(BYTE);
|
|
break;
|
|
case VT_I2:
|
|
case VT_UI2:
|
|
case VT_BOOL:
|
|
cbWrite = sizeof(short);
|
|
break;
|
|
case VT_I4:
|
|
case VT_UI4:
|
|
case VT_R4:
|
|
case VT_INT:
|
|
case VT_UINT:
|
|
case VT_ERROR:
|
|
cbWrite = sizeof(long);
|
|
break;
|
|
case VT_R8:
|
|
case VT_CY:
|
|
case VT_DATE:
|
|
cbWrite = sizeof(double);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
CComBSTR bstrWrite;
|
|
CComVariant varBSTR;
|
|
|
|
if (m_var.vt != VT_BSTR)
|
|
{
|
|
hr = VariantChangeType(&varBSTR, &m_var, VARIANT_NOVALUEPROP, VT_BSTR);
|
|
if (FAILED(hr))
|
|
return hr;
|
|
bstrWrite = varBSTR.bstrVal;
|
|
}
|
|
else
|
|
{
|
|
bstrWrite = m_var.bstrVal;
|
|
}
|
|
len += 4 + (static_cast<BSTR>(bstrWrite) ? SysStringByteLen(bstrWrite) : 0) + 2;
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
len += cbWrite;
|
|
}
|
|
|
|
// Add sizes of children
|
|
len += (sizeof BOOL); // has children?
|
|
if ( m_children )
|
|
{
|
|
len += m_children->CalculateStreamedLength();
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
long // ret- number of data items
|
|
CVarData::CountItems()
|
|
{
|
|
long count = 1;
|
|
|
|
if ( m_children )
|
|
{
|
|
count += m_children->CountItems();
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
void
|
|
CVarData::McLogInternalDiagnostics(
|
|
CString keyname // in - Key name for this subtree, so the complete name can be displayed
|
|
)
|
|
{
|
|
CString value;
|
|
|
|
switch ( m_var.vt )
|
|
{
|
|
case VT_EMPTY:
|
|
value = _T("<Empty>");
|
|
break;
|
|
case VT_NULL:
|
|
value = _T("<Null>");
|
|
break;
|
|
case VT_I2:
|
|
case VT_I4:
|
|
value.Format(_T("%ld"),m_var.iVal);
|
|
break;
|
|
case VT_BSTR:
|
|
value = m_var.bstrVal;
|
|
break;
|
|
default:
|
|
value.Format(_T("variant type=0x%lx"),m_var.vt);
|
|
break;
|
|
}
|
|
MC_LOG(String(keyname) << "-->"<< String(value) << (m_children ? " (Has Children)" : " (No Children)") << " Options = " << makeStr(m_options) << " CaseSensitive=" << ( IsCaseSensitive()?"TRUE":"FALSE") << " Indexed=" << (IsIndexed()?"TRUE":"FALSE") );
|
|
|
|
if ( m_children )
|
|
{
|
|
m_children->McLogInternalDiagnostics(keyname);
|
|
}
|
|
} |