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.
507 lines
13 KiB
507 lines
13 KiB
#include <pch.hxx>
|
|
#include <shlwapi.h>
|
|
#include "xpcomm.h"
|
|
#include "propbckt.h"
|
|
|
|
void FreePropVariant(LPPROPVARIANT pProp);
|
|
HRESULT DupPropVariant(LPPROPVARIANT pPropDst, LPCPROPVARIANT pPropSrc, BOOL fFree);
|
|
HRESULT InsertPropNode(LPCSTR pszProp, int iProp, PROPNODE **ppNode, int *pcNode, int *pcNodeBuf);
|
|
|
|
MSOEACCTAPI CreatePropertyBucket(IPropertyBucket **ppPropBckt)
|
|
{
|
|
CPropertyBucket *pBckt;
|
|
|
|
Assert(ppPropBckt != NULL);
|
|
|
|
pBckt = new CPropertyBucket;
|
|
|
|
*ppPropBckt = (IPropertyBucket *)pBckt;
|
|
|
|
return(pBckt == NULL ? E_OUTOFMEMORY : S_OK);
|
|
}
|
|
|
|
CPropertyBucket::CPropertyBucket(void)
|
|
{
|
|
m_cRef = 1;
|
|
InitializeCriticalSection(&m_cs);
|
|
|
|
m_pNodeId = NULL;
|
|
m_cNodeId = 0;
|
|
m_cNodeIdBuf = 0;
|
|
|
|
m_pNodeSz = NULL;
|
|
m_cNodeSz = 0;
|
|
m_cNodeSzBuf = 0;
|
|
|
|
m_pProp = 0;
|
|
m_cProp = 0;
|
|
m_cPropBuf = 0;
|
|
}
|
|
|
|
CPropertyBucket::~CPropertyBucket(void)
|
|
{
|
|
int i;
|
|
PROPNODE *pNode;
|
|
LPPROPVARIANT pProp;
|
|
|
|
DeleteCriticalSection(&m_cs);
|
|
|
|
if (m_pNodeId != NULL)
|
|
MemFree(m_pNodeId);
|
|
|
|
if (m_pNodeSz != NULL)
|
|
{
|
|
for (i = 0, pNode = m_pNodeSz; i < m_cNodeSz; i++, pNode++)
|
|
{
|
|
Assert(pNode->psz != NULL);
|
|
MemFree(pNode->psz);
|
|
}
|
|
|
|
MemFree(m_pNodeSz);
|
|
}
|
|
|
|
if (m_pProp != NULL)
|
|
{
|
|
for (i = 0, pProp = m_pProp; i < m_cProp; i++, pProp++)
|
|
FreePropVariant(pProp);
|
|
|
|
MemFree(m_pProp);
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CPropertyBucket::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
if (ppv == NULL)
|
|
return(E_INVALIDARG);
|
|
|
|
if (IID_IUnknown == riid)
|
|
{
|
|
*ppv = (IUnknown *)this;
|
|
}
|
|
else if (IID_IPropertyBucket == riid)
|
|
{
|
|
*ppv = (IPropertyBucket *)this;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return(E_NOINTERFACE);
|
|
}
|
|
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
return(S_OK);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CPropertyBucket::AddRef(void)
|
|
{
|
|
return((ULONG)InterlockedIncrement(&m_cRef));
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG) CPropertyBucket::Release(void)
|
|
{
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return((ULONG)cRef);
|
|
}
|
|
|
|
LPPROPVARIANT CPropertyBucket::GetPropVariant(LPCSTR pszProp)
|
|
{
|
|
BOOL fSz;
|
|
PROPID id;
|
|
PROPNODE *pNode, *pNodeT;
|
|
int x, left, right, d, cNode;
|
|
|
|
Assert(pszProp != NULL);
|
|
|
|
fSz = !IsPropId(pszProp);
|
|
if (fSz)
|
|
{
|
|
pNode = m_pNodeSz;
|
|
cNode = m_cNodeSz;
|
|
}
|
|
else
|
|
{
|
|
id = SzToPropId(pszProp);
|
|
|
|
pNode = m_pNodeId;
|
|
cNode = m_cNodeId;
|
|
}
|
|
|
|
if (pNode != NULL)
|
|
{
|
|
Assert(cNode > 0);
|
|
|
|
left = 0;
|
|
right = cNode - 1;
|
|
do
|
|
{
|
|
x = (left + right) / 2;
|
|
Assert(x >= 0);
|
|
Assert(x < cNode);
|
|
|
|
pNodeT = &pNode[x];
|
|
|
|
d = fSz ? lstrcmp(pszProp, pNodeT->psz) : (id - pNodeT->id);
|
|
|
|
if (d == 0)
|
|
{
|
|
Assert(pNodeT->iProp < m_cProp);
|
|
return(&m_pProp[pNodeT->iProp]);
|
|
}
|
|
else if (d < 0)
|
|
{
|
|
right = x - 1;
|
|
}
|
|
else
|
|
{
|
|
left = x + 1;
|
|
}
|
|
}
|
|
while (right >= left);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
// TODO: move to msoert
|
|
void FreePropVariant(LPPROPVARIANT pProp)
|
|
{
|
|
Assert(pProp != NULL);
|
|
|
|
switch (pProp->vt)
|
|
{
|
|
// Since pProp is a union, this MemFree will work for all
|
|
case VT_LPSTR:
|
|
case VT_LPWSTR:
|
|
case VT_CLSID:
|
|
case VT_CF:
|
|
if (pProp->pszVal != NULL)
|
|
MemFree(pProp->pszVal);
|
|
break;
|
|
|
|
case VT_BSTR:
|
|
if (pProp->bstrVal != NULL)
|
|
SysFreeString(pProp->bstrVal);
|
|
break;
|
|
|
|
case VT_BLOB:
|
|
if (pProp->blob.pBlobData != NULL)
|
|
MemFree(pProp->blob.pBlobData);
|
|
break;
|
|
|
|
case VT_STREAM:
|
|
if (pProp->pStream != NULL)
|
|
pProp->pStream->Release();
|
|
break;
|
|
|
|
case VT_STORAGE:
|
|
if (pProp->pStorage != NULL)
|
|
pProp->pStorage->Release();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// TODO: move to msoert
|
|
HRESULT DupPropVariant(LPPROPVARIANT pPropDst, LPCPROPVARIANT pPropSrc, BOOL fFree)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPSTR psz = NULL;
|
|
LPWSTR pwsz = NULL;
|
|
LPBYTE pb;
|
|
|
|
hr = S_OK;
|
|
|
|
switch (pPropSrc->vt)
|
|
{
|
|
case VT_LPSTR:
|
|
if (pPropSrc->pszVal != NULL)
|
|
{
|
|
IF_NULLEXIT(psz = PszDupA(pPropSrc->pszVal));
|
|
if (fFree)
|
|
FreePropVariant(pPropDst);
|
|
pPropDst->pszVal = psz;
|
|
}
|
|
else
|
|
{
|
|
if (fFree)
|
|
FreePropVariant(pPropDst);
|
|
pPropDst->pszVal = NULL;
|
|
}
|
|
break;
|
|
|
|
case VT_LPWSTR:
|
|
if (pPropSrc->pwszVal != NULL)
|
|
{
|
|
IF_NULLEXIT(pwsz = PszDupW(pPropSrc->pwszVal));
|
|
if (fFree)
|
|
FreePropVariant(pPropDst);
|
|
pPropDst->pwszVal = pwsz;
|
|
}
|
|
else
|
|
{
|
|
if (fFree)
|
|
FreePropVariant(pPropDst);
|
|
pPropDst->pwszVal = NULL;
|
|
}
|
|
break;
|
|
|
|
case VT_BLOB:
|
|
if (pPropSrc->blob.pBlobData != NULL)
|
|
{
|
|
Assert(pPropSrc->blob.cbSize > 0);
|
|
IF_NULLEXIT(MemAlloc((void **)&pb, pPropSrc->blob.cbSize));
|
|
if (fFree)
|
|
FreePropVariant(pPropDst);
|
|
|
|
CopyMemory(pb, pPropSrc->blob.pBlobData, pPropSrc->blob.cbSize);
|
|
pPropDst->blob.pBlobData = pb;
|
|
pPropDst->blob.cbSize = pPropSrc->blob.cbSize;
|
|
}
|
|
else
|
|
{
|
|
if (fFree)
|
|
FreePropVariant(pPropDst);
|
|
|
|
Assert(pPropSrc->blob.cbSize == 0);
|
|
pPropDst->blob.cbSize = 0;
|
|
pPropDst->blob.pBlobData = NULL;
|
|
}
|
|
break;
|
|
|
|
case VT_UI1:
|
|
pPropDst->bVal = pPropSrc->bVal;
|
|
break;
|
|
|
|
case VT_I2:
|
|
case VT_UI2:
|
|
case VT_BOOL:
|
|
Assert(sizeof(pPropDst->uiVal) >= sizeof(pPropDst->boolVal));
|
|
pPropDst->uiVal = pPropSrc->uiVal;
|
|
break;
|
|
|
|
case VT_I4:
|
|
case VT_UI4:
|
|
case VT_ERROR:
|
|
case VT_R4:
|
|
Assert(sizeof(pPropDst->ulVal) >= sizeof(pPropDst->scode));
|
|
Assert(sizeof(pPropDst->ulVal) >= sizeof(pPropDst->fltVal));
|
|
pPropDst->ulVal = pPropSrc->ulVal;
|
|
break;
|
|
|
|
case VT_I8:
|
|
case VT_UI8:
|
|
case VT_R8:
|
|
case VT_CY:
|
|
case VT_DATE:
|
|
case VT_FILETIME:
|
|
Assert(sizeof(pPropDst->uhVal) >= sizeof(pPropDst->dblVal));
|
|
Assert(sizeof(pPropDst->uhVal) >= sizeof(pPropDst->cyVal));
|
|
Assert(sizeof(pPropDst->uhVal) >= sizeof(pPropDst->date));
|
|
Assert(sizeof(pPropDst->uhVal) >= sizeof(pPropDst->filetime));
|
|
pPropDst->uhVal = pPropSrc->uhVal;
|
|
break;
|
|
|
|
default:
|
|
AssertSz(FALSE, "nyi");
|
|
IF_FAILEXIT(hr = E_FAIL);
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
if (SUCCEEDED(hr))
|
|
pPropDst->vt = pPropSrc->vt;
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT ComparePropVariant(LPPROPVARIANT pProp1, LPCPROPVARIANT pProp2)
|
|
{
|
|
HRESULT hr;
|
|
BYTE *pb1, *pb2;
|
|
ULONG i;
|
|
|
|
hr = S_OK;
|
|
|
|
if (pProp1->vt == pProp2->vt)
|
|
{
|
|
switch (pProp1->vt)
|
|
{
|
|
case VT_LPSTR:
|
|
if (0 == lstrcmp(pProp1->pszVal, pProp2->pszVal))
|
|
hr = S_NO_CHANGE;
|
|
break;
|
|
|
|
case VT_LPWSTR:
|
|
if (0 == StrCmpW(pProp1->pwszVal, pProp2->pwszVal))
|
|
hr = S_NO_CHANGE;
|
|
break;
|
|
|
|
case VT_BLOB:
|
|
if (pProp1->blob.cbSize == pProp2->blob.cbSize)
|
|
{
|
|
pb1 = pProp1->blob.pBlobData;
|
|
pb2 = pProp2->blob.pBlobData;
|
|
if (pb1 == NULL)
|
|
{
|
|
Assert(pb2 == NULL);
|
|
hr = S_NO_CHANGE;
|
|
}
|
|
else
|
|
{
|
|
Assert(pb2 != NULL);
|
|
for (i = 0; i < pProp1->blob.cbSize; i++)
|
|
{
|
|
if (*pb1 != *pb2)
|
|
break;
|
|
pb1++;
|
|
pb2++;
|
|
}
|
|
if (i == pProp1->blob.cbSize)
|
|
hr = S_NO_CHANGE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case VT_UI4:
|
|
if (pProp1->ulVal == pProp2->ulVal)
|
|
hr = S_NO_CHANGE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(hr);
|
|
}
|
|
|
|
STDMETHODIMP CPropertyBucket::GetProperty(LPCSTR pszProp, LPPROPVARIANT pVar, DWORD dwReserved)
|
|
{
|
|
HRESULT hr;
|
|
LPPROPVARIANT pProp;
|
|
|
|
if (pszProp == NULL ||
|
|
pVar == NULL ||
|
|
dwReserved != 0)
|
|
return(E_INVALIDARG);
|
|
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
pProp = GetPropVariant(pszProp);
|
|
if (pProp != NULL)
|
|
hr = DupPropVariant(pVar, pProp, FALSE);
|
|
else
|
|
hr = E_PROP_NOT_FOUND;
|
|
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
#define CALLOCPROP 32
|
|
#define CALLOCNODE 16
|
|
|
|
STDMETHODIMP CPropertyBucket::SetProperty(LPCSTR pszProp, LPCPROPVARIANT pVar, DWORD dwReserved)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LPPROPVARIANT pProp;
|
|
UINT cAlloc;
|
|
PROPNODE *pNode;
|
|
|
|
if (pszProp == NULL || pVar == NULL || dwReserved != 0)
|
|
return TraceResult(E_INVALIDARG);
|
|
|
|
EnterCriticalSection(&m_cs);
|
|
|
|
pProp = GetPropVariant(pszProp);
|
|
if (pProp != NULL)
|
|
{
|
|
if (pProp->vt != pVar->vt)
|
|
{
|
|
hr = E_INVALID_PROP_TYPE;
|
|
}
|
|
else
|
|
{
|
|
hr = ComparePropVariant(pProp, pVar);
|
|
if (hr != S_NO_CHANGE)
|
|
IF_FAILEXIT(hr = DupPropVariant(pProp, pVar, TRUE));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_cProp == m_cPropBuf)
|
|
{
|
|
cAlloc = m_cPropBuf + CALLOCPROP;
|
|
IF_NULLEXIT(MemRealloc((void **)&m_pProp, sizeof(PROPVARIANT) * cAlloc));
|
|
|
|
m_cPropBuf = cAlloc;
|
|
ZeroMemory(&m_pProp[m_cProp], sizeof(PROPVARIANT) * CALLOCPROP);
|
|
}
|
|
|
|
pProp = &m_pProp[m_cProp];
|
|
IF_FAILEXIT(hr = DupPropVariant(pProp, pVar, FALSE));
|
|
|
|
if (IsPropId(pszProp))
|
|
hr = InsertPropNode(pszProp, m_cProp, &m_pNodeId, &m_cNodeId, &m_cNodeIdBuf);
|
|
else
|
|
hr = InsertPropNode(pszProp, m_cProp, &m_pNodeSz, &m_cNodeSz, &m_cNodeSzBuf);
|
|
|
|
m_cProp++;
|
|
}
|
|
|
|
exit:
|
|
LeaveCriticalSection(&m_cs);
|
|
|
|
return(hr);
|
|
}
|
|
|
|
HRESULT InsertPropNode(LPCSTR pszProp, int iProp, PROPNODE **ppNode, int *pcNode, int *pcNodeBuf)
|
|
{
|
|
int iNode, cAlloc, d;
|
|
BOOL fSz;
|
|
LPSTR psz;
|
|
PROPNODE *pNodeT;
|
|
HRESULT hr = S_OK;
|
|
|
|
if (*pcNode == *pcNodeBuf)
|
|
{
|
|
cAlloc = *pcNodeBuf + CALLOCNODE;
|
|
IF_NULLEXIT(MemRealloc((void **)ppNode, sizeof(PROPNODE) * cAlloc));
|
|
|
|
*pcNodeBuf = cAlloc;
|
|
ZeroMemory(&(*ppNode)[*pcNode], sizeof(PROPNODE) * CALLOCNODE);
|
|
}
|
|
|
|
if (fSz = !IsPropId(pszProp))
|
|
{
|
|
IF_NULLEXIT(psz = StringDup(pszProp));
|
|
}
|
|
else
|
|
{
|
|
psz = (LPSTR)pszProp;
|
|
}
|
|
|
|
pNodeT = *ppNode;
|
|
for (iNode = 0; iNode < *pcNode; iNode++)
|
|
{
|
|
d = fSz ? lstrcmp(pszProp, pNodeT->psz) : (PtrToUlong(pszProp) - pNodeT->id);
|
|
Assert(d != 0);
|
|
|
|
if (d < 0)
|
|
break;
|
|
|
|
pNodeT++;
|
|
}
|
|
|
|
cAlloc = *pcNode - iNode;
|
|
if (cAlloc > 0)
|
|
MoveMemory(pNodeT + 1, pNodeT, cAlloc * sizeof(PROPNODE));
|
|
pNodeT->psz = psz;
|
|
pNodeT->iProp = iProp;
|
|
(*pcNode)++;
|
|
|
|
exit:
|
|
return hr;
|
|
}
|