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.
 
 
 
 
 
 

619 lines
16 KiB

//
// attr.cpp
//
#include "private.h"
#include "attr.h"
#include "ic.h"
#include "saa.h"
#include "erfa.h"
#include "epval.h"
#include "immxutil.h"
#include "range.h"
//+---------------------------------------------------------------------------
//
// CalcAppPropertyTrackerAnchors
//
// NB: an empty range will result in a single anchor at the range pos.
//----------------------------------------------------------------------------
CSharedAnchorArray *CalcAppPropertyTrackerAnchors(ITextStoreAnchor *ptsi, ITfRange *rangeSuper, ULONG cGUIDs, const GUID *prgGUIDs)
{
CSharedAnchorArray *prgAnchors;
CRange *rangeScan;
IAnchor *paPrevTrans;
IAnchor **ppa;
BOOL fRet;
BOOL fFound;
LONG lFoundOffset;
HRESULT hr;
if ((rangeScan = GetCRange_NA(rangeSuper)) == NULL)
return NULL;
if ((prgAnchors = new CSharedAnchorArray) == NULL)
return NULL;
fRet = FALSE;
if (rangeScan->_GetStart()->Clone(&paPrevTrans) != S_OK)
{
paPrevTrans = NULL;
goto Exit;
}
// now scan down the length of the range, building up a list
while (TRUE)
{
// we've just found the end point of this run
if (!prgAnchors->Append(1))
goto Exit;
ppa = prgAnchors->GetPtr(prgAnchors->Count()-1);
if (paPrevTrans->Clone(ppa) != S_OK)
goto Exit;
if (cGUIDs == 0) // no transition for zero GUIDs, just do the end anchor Clone outside the loop
break;
hr = ptsi->FindNextAttrTransition(paPrevTrans, rangeScan->_GetEnd(), cGUIDs, prgGUIDs, TS_ATTR_FIND_UPDATESTART, &fFound, &lFoundOffset);
if (hr != S_OK)
goto Exit;
// no more property spans?
if (!fFound)
break;
// stop when we hit the end of the range
if (IsEqualAnchor(paPrevTrans, rangeScan->_GetEnd()))
break;
}
if (!IsEqualAnchor(rangeScan->_GetStart(), rangeScan->_GetEnd()))
{
// add a final anchor at the end of the range
if (!prgAnchors->Append(1))
goto Exit;
ppa = prgAnchors->GetPtr(prgAnchors->Count()-1);
if (rangeScan->_GetEnd()->Clone(ppa) != S_OK)
goto Exit;
}
// shrink the array down to size, it won't be modified again
prgAnchors->CompactSize();
fRet = TRUE;
Exit:
if (!fRet)
{
prgAnchors->_Release();
prgAnchors = NULL;
}
else
{
Assert(prgAnchors != NULL);
}
SafeRelease(paPrevTrans);
return prgAnchors;
}
//+---------------------------------------------------------------------------
//
// GetDefaultValue
//
//----------------------------------------------------------------------------
HRESULT GetDefaultValue(ITextStoreAnchor *ptsi, REFGUID guidType, VARIANT *pvarValue)
{
TS_ATTRVAL av;
ULONG cFetched;
HRESULT hr;
Assert(pvarValue != NULL);
// VT_EMPTY for unsupported attrib/error
QuickVariantInit(pvarValue);
hr = ptsi->RequestSupportedAttrs(TS_ATTR_FIND_WANT_VALUE, 1, &guidType);
if (hr != S_OK)
{
return (hr == E_NOTIMPL) ? E_NOTIMPL : E_FAIL;
}
if (ptsi->RetrieveRequestedAttrs(1, &av, &cFetched) == S_OK &&
cFetched == 1)
{
Assert(IsEqualGUID(av.idAttr, guidType));
*pvarValue = av.varValue; // caller owns it now
}
else
{
// the aimm layer will sometimes stop supporting an attribute
// it has two sink callback points, the one for reconversion doesn't
// handle attributes.
// we'll just return VT_EMPTY
Assert(pvarValue->vt == VT_EMPTY);
}
return S_OK;
}
//+---------------------------------------------------------------------------
//
// FillAppValueArray
//
//----------------------------------------------------------------------------
HRESULT FillAppValueArray(ITextStoreAnchor *ptsi, CRange *range, TF_PROPERTYVAL *rgPropVal, ULONG cGUIDs, const GUID *prgGUIDs)
{
ULONG i;
ULONG j;
ULONG iNext;
ULONG cMissing;
TS_ATTRVAL *prgVals;
ULONG cFetched;
HRESULT hr;
if (cGUIDs == 0)
return S_OK;
if ((prgVals = (TS_ATTRVAL *)cicMemAlloc(cGUIDs*sizeof(TS_ATTRVAL))) == NULL)
return E_OUTOFMEMORY;
hr = ptsi->RequestAttrsAtPosition(range->_GetStart(), cGUIDs, prgGUIDs, 0);
if (hr != S_OK)
goto Exit;
hr = ptsi->RetrieveRequestedAttrs(cGUIDs, prgVals, &cFetched);
if (hr != S_OK)
goto Exit;
// copy over the values in prgVals
for (i=0; i<cFetched; i++)
{
rgPropVal[i].guidId = prgVals[i].idAttr;
rgPropVal[i].varValue = prgVals[i].varValue; // we take ownership, no VariantCopy
}
// figure out what was missing
cMissing = cGUIDs - cFetched;
if (cMissing == 0)
goto Exit;
iNext = cFetched; // index of first missing guid
// perf: this is O(n^2), we could do a sort or something...
for (i=0; i<cGUIDs; i++)
{
for (j=0; j<cFetched; j++)
{
if (IsEqualGUID(prgVals[j].idAttr, prgGUIDs[i]))
break;
}
if (j < cFetched)
continue;
// found a missing GUID, need to get the default value
hr = GetDefaultValue(ptsi, prgGUIDs[i], &rgPropVal[iNext].varValue);
if (hr != S_OK)
{
Assert(0); // why did we fail?
QuickVariantInit(&rgPropVal[iNext].varValue);
}
rgPropVal[iNext].guidId = prgGUIDs[i];
if (--cMissing == 0) // anything left to look for?
break;
iNext++;
}
Exit:
cicMemFree(prgVals);
return hr;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// CEnumAppPropRanges
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
class CEnumAppPropRanges : public CEnumRangesFromAnchorsBase
{
public:
CEnumAppPropRanges()
{
Dbg_MemSetThisNameIDCounter(TEXT("CEnumAppPropRanges"), PERF_ENUMAPPPROP_COUNTER);
}
BOOL _Init(CInputContext *pic, ITfRange *rangeSuper, REFGUID rguid);
private:
DBG_ID_DECLARE;
};
DBG_ID_INSTANCE(CEnumAppPropRanges);
//+---------------------------------------------------------------------------
//
// _Init
//
// Scan the superset range and build up a list of covered ranges.
//
//----------------------------------------------------------------------------
BOOL CEnumAppPropRanges::_Init(CInputContext *pic, ITfRange *rangeSuper, REFGUID rguid)
{
Assert(_iCur == 0);
Assert(_pic == NULL);
Assert(_prgAnchors == NULL);
_prgAnchors = CalcAppPropertyTrackerAnchors(pic->_GetTSI(), rangeSuper, 1, &rguid);
if (_prgAnchors == NULL)
return FALSE;
_pic = pic;
_pic->AddRef();
return TRUE;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// CAppProperty
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
class CAppProperty : public ITfReadOnlyProperty,
public CComObjectRootImmx
{
public:
CAppProperty(CInputContext *pic, REFGUID guid);
~CAppProperty();
BEGIN_COM_MAP_IMMX(CAppProperty)
COM_INTERFACE_ENTRY(ITfReadOnlyProperty)
END_COM_MAP_IMMX()
IMMX_OBJECT_IUNKNOWN_FOR_ATL()
// ITfReadOnlyProperty
STDMETHODIMP GetType(GUID *pguid);
STDMETHODIMP EnumRanges(TfEditCookie ec, IEnumTfRanges **ppEnum, ITfRange *pTargetRange);
STDMETHODIMP GetValue(TfEditCookie ec, ITfRange *pRange, VARIANT *pvarValue);
STDMETHODIMP GetContext(ITfContext **ppContext);
private:
BOOL _IsValidEditCookie(TfEditCookie ec, DWORD dwFlags)
{
return _pic->_IsValidEditCookie(ec, dwFlags);
}
CInputContext *_pic;
GUID _guid;
DBG_ID_DECLARE;
};
DBG_ID_INSTANCE(CAppProperty);
//+---------------------------------------------------------------------------
//
// ctor
//
//----------------------------------------------------------------------------
CAppProperty::CAppProperty(CInputContext *pic, REFGUID guid)
{
Dbg_MemSetThisNameIDCounter(TEXT("CAppProperty"), PERF_APPPROP_COUNTER);
_pic = pic;
_pic->AddRef();
_guid = guid;
}
//+---------------------------------------------------------------------------
//
// dtor
//
//----------------------------------------------------------------------------
CAppProperty::~CAppProperty()
{
_pic->Release();
}
//+---------------------------------------------------------------------------
//
// GetType
//
//----------------------------------------------------------------------------
STDAPI CAppProperty::GetType(GUID *pguid)
{
if (pguid == NULL)
return E_INVALIDARG;
*pguid = _guid;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// EnumRanges
//
//----------------------------------------------------------------------------
STDAPI CAppProperty::EnumRanges(TfEditCookie ec, IEnumTfRanges **ppEnum, ITfRange *pTargetRange)
{
CEnumAppPropRanges *pEnum;
if (ppEnum == NULL)
return E_INVALIDARG;
*ppEnum = NULL;
if (!_IsValidEditCookie(ec, TF_ES_READ))
{
Assert(0);
return TF_E_NOLOCK;
}
// nb: unlike ITfProperty, ITfReadOnlyProperty does not accept pTargetRange == NULL!
if (pTargetRange == NULL)
return E_INVALIDARG;
// make sure ic, range are in the same context
if (!VerifySameContext(_pic, pTargetRange))
return E_INVALIDARG;
pEnum = new CEnumAppPropRanges;
if (pEnum == NULL)
return E_OUTOFMEMORY;
if (!pEnum->_Init(_pic, pTargetRange, _guid))
{
pEnum->Release();
return E_FAIL;
}
*ppEnum = pEnum;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// GetValue
//
//----------------------------------------------------------------------------
STDAPI CAppProperty::GetValue(TfEditCookie ec, ITfRange *pRange, VARIANT *pvarValue)
{
TS_ATTRVAL av;
HRESULT hr;
CRange *range;
ULONG cFetched;
ITextStoreAnchor *ptsi;
if (pvarValue == NULL)
return E_INVALIDARG;
QuickVariantInit(pvarValue);
if (!_IsValidEditCookie(ec, TF_ES_READ))
{
Assert(0);
return TF_E_NOLOCK;
}
if (pRange == NULL)
return E_INVALIDARG; // supporting "whole doc" behavior too expensive!
if ((range = GetCRange_NA(pRange)) == NULL)
return E_INVALIDARG;
if (!VerifySameContext(_pic, range))
return E_INVALIDARG;
ptsi = _pic->_GetTSI();
// we always return the value at the start anchor
hr = ptsi->RequestAttrsAtPosition(range->_GetStart(), 1, &_guid, 0);
if (hr != S_OK)
return E_FAIL;
QuickVariantInit(&av.varValue);
// just return the single VARIANT value directly
if (ptsi->RetrieveRequestedAttrs(1, &av, &cFetched) != S_OK)
return E_FAIL;
if (cFetched == 0)
{
// default value
return GetDefaultValue(_pic->_GetTSI(), _guid, pvarValue);
}
*pvarValue = av.varValue; // caller takes ownership
return S_OK;
}
//+---------------------------------------------------------------------------
//
// GetContext
//
//----------------------------------------------------------------------------
STDAPI CAppProperty::GetContext(ITfContext **ppContext)
{
if (ppContext == NULL)
return E_INVALIDARG;
*ppContext = _pic;
(*ppContext)->AddRef();
return S_OK;
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//
// CInputContext
//
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//+---------------------------------------------------------------------------
//
// GetAppProperty
//
//----------------------------------------------------------------------------
STDAPI CInputContext::GetAppProperty(REFGUID guidProp, ITfReadOnlyProperty **ppProp)
{
CAppProperty *prop;
TS_ATTRVAL av;
ULONG cFetched;
BOOL fUnsupported;
HRESULT hr;
if (ppProp == NULL)
return E_INVALIDARG;
*ppProp = NULL;
if (!_IsConnected())
return TF_E_DISCONNECTED;
//
// if we have a mapping property, it will be returned.
//
APPPROPMAP *pMap = FindMapAppProperty(guidProp);
if (pMap)
{
CProperty *pProp;
if (SUCCEEDED(_GetProperty(pMap->guidProp, &pProp)))
{
*ppProp = (ITfReadOnlyProperty *)pProp;
return S_OK;
}
}
// does the app support this property?
fUnsupported = TRUE;
if ((hr = _ptsi->RequestSupportedAttrs(0, 1, &guidProp)) != S_OK)
{
return (hr == E_NOTIMPL) ? E_NOTIMPL : E_FAIL;
}
QuickVariantInit(&av.varValue);
if (_ptsi->RetrieveRequestedAttrs(1, &av, &cFetched) == S_OK &&
cFetched == 1)
{
if (IsEqualGUID(av.idAttr, guidProp)) // paranoia
{
fUnsupported = FALSE;
}
else
{
Assert(0); // bad out param!
}
}
if (fUnsupported)
{
return S_FALSE;
}
if ((prop = new CAppProperty(this, guidProp)) == NULL)
return E_OUTOFMEMORY;
*ppProp = prop;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// MapAppProperty
//
//----------------------------------------------------------------------------
STDAPI CInputContext::MapAppProperty(REFGUID guidAppProp, REFGUID guidProp)
{
APPPROPMAP *pMap;
//
// overwrite the mapping guidProp.
//
if (pMap = FindMapAppProperty(guidAppProp))
{
pMap->guidProp = guidProp;
return S_OK;
}
pMap = _rgAppPropMap.Append(1);
if (!pMap)
return E_OUTOFMEMORY;
pMap->guidAppProp = guidAppProp;
pMap->guidProp = guidProp;
return S_OK;
}
//+---------------------------------------------------------------------------
//
// FindMapProp
//
//----------------------------------------------------------------------------
CInputContext::APPPROPMAP *CInputContext::FindMapAppProperty(REFGUID guidAppProp)
{
int i;
for (i = 0; i < _rgAppPropMap.Count(); i++)
{
APPPROPMAP *pMap = _rgAppPropMap.GetPtr(i);
if (IsEqualGUID(pMap->guidAppProp, guidAppProp))
return pMap;
}
return NULL;
}
//+---------------------------------------------------------------------------
//
// GetMappedAppProperty
//
//----------------------------------------------------------------------------
HRESULT CInputContext::GetMappedAppProperty(REFGUID guidProp, CProperty **ppProp)
{
if (!_IsConnected())
return TF_E_DISCONNECTED;
//
// if we have a mapping property, it will be returned.
//
APPPROPMAP *pMap = FindMapAppProperty(guidProp);
if (pMap)
{
if (SUCCEEDED(_GetProperty(pMap->guidProp, ppProp)))
{
return S_OK;
}
}
return E_FAIL;
}