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.
 
 
 
 
 
 

556 lines
14 KiB

//
// lmlattice.cpp
//
// implelementation of ITfLMLattice object, IEnumTfLatticeElements object
//
#include "private.h"
#include "sapilayr.h"
#include "lmlattic.h"
//
// CLMLattice
//
//
// ctor / dtor
CLMLattice::CLMLattice(CSapiIMX *p_tip, IUnknown *pResWrap)
{
m_cpResWrap = pResWrap;
m_pTip = p_tip;
if (m_pTip)
{
m_pTip->AddRef();
}
m_cRef = 1;
}
CLMLattice::~CLMLattice()
{
if (m_pTip)
{
m_pTip->Release();
}
}
// IUnknown
HRESULT CLMLattice::QueryInterface(REFIID riid, void **ppvObj)
{
HRESULT hr;
Assert(ppvObj);
if (IsEqualIID(riid, IID_IUnknown)
|| IsEqualIID(riid, IID_ITfLMLattice))
{
*ppvObj = this;
hr = S_OK;
this->m_cRef++;
}
else
{
*ppvObj = NULL;
hr = E_NOINTERFACE;
}
return hr;
}
ULONG CLMLattice::AddRef(void)
{
this->m_cRef++;
return this->m_cRef;
}
ULONG CLMLattice::Release(void)
{
this->m_cRef--;
if (this->m_cRef > 0)
{
return this->m_cRef;
}
delete this;
return 0;
}
// ITfLMLattice
HRESULT CLMLattice::QueryType(REFGUID refguidType, BOOL *pfSupported)
{
HRESULT hr = E_INVALIDARG;
if (pfSupported)
{
*pfSupported = IsEqualGUID(refguidType, GUID_LMLATTICE_VER1_0);
if (*pfSupported)
hr = S_OK;
}
return hr;
}
HRESULT CLMLattice::EnumLatticeElements( DWORD dwFrameStart, REFGUID refguidType, IEnumTfLatticeElements **ppEnum)
{
if (!ppEnum)
return E_INVALIDARG;
*ppEnum = NULL;
if (!IsEqualGUID(refguidType, GUID_LMLATTICE_VER1_0))
return E_INVALIDARG;
HRESULT hr = E_FAIL;
// get alternates and cache the returned cotaskmem
ULONG ulcMaxAlt = m_pTip->_GetMaxAlternates();
ISpPhraseAlt **ppAlt = NULL;
CComPtr<IServiceProvider> cpServicePrv;
CComPtr<ISpRecoResult> cpRecoResult;
CRecoResultWrap *pWrap = NULL;
ULONG ulStartInWrp, ulNumInWrp;
// QI the service provider first then get to the sapi interface
//
hr = m_cpResWrap->QueryInterface(IID_IServiceProvider, (void **)&cpServicePrv);
if (SUCCEEDED(hr))
{
hr = m_cpResWrap->QueryInterface(IID_PRIV_RESULTWRAP, (void **)&pWrap);
}
if (SUCCEEDED(hr))
{
hr = cpServicePrv->QueryService(GUID_NULL, IID_ISpRecoResult, (void **)&cpRecoResult);
}
ulStartInWrp = pWrap->GetStart();
ulNumInWrp = pWrap->GetNumElements();
if ( SUCCEEDED(hr))
{
// Get the Alternates for current RecoResult.
ppAlt = (ISpPhraseAlt **)cicMemAlloc(ulcMaxAlt * sizeof(ISpPhraseAlt *));
if (ppAlt)
{
hr = cpRecoResult->GetAlternates(
ulStartInWrp,
ulNumInWrp,
ulcMaxAlt,
ppAlt, /* [out] ISpPhraseAlt **ppPhrases, */
&ulcMaxAlt /* [out] ULONG *pcPhrasesReturned */
);
}
else
hr = E_OUTOFMEMORY;
}
// OK now create an instance of enumerator
CEnumLatticeElements *pEnumLE = NULL;
if ( SUCCEEDED(hr) )
{
pEnumLE = new CEnumLatticeElements(dwFrameStart);
if (!pEnumLE)
hr = E_OUTOFMEMORY;
if (S_OK == hr)
{
for ( ULONG i=0; i<ulcMaxAlt; i++)
{
SPPHRASE *pPhrase = NULL;
ULONG ulStart, ulNum;
ULONG ulStartInPar, ulNumInParent;
ppAlt[i]->GetPhrase(&pPhrase);
ppAlt[i]->GetAltInfo(NULL, &ulStartInPar, &ulNumInParent, &ulNum);
if ( (ulStartInPar >= ulStartInWrp) && (ulStartInPar+ulNumInParent <= ulStartInWrp+ulNumInWrp) )
{
// This is a valid alternate
if( SUCCEEDED(hr) )
{
ulStart = ulStartInPar;
hr = pEnumLE->_InitFromPhrase(pPhrase, ulStart, ulNum);
}
}
if (pPhrase)
{
CoTaskMemFree(pPhrase);
}
}
}
}
if (S_OK == hr)
{
hr = pEnumLE->QueryInterface(IID_IEnumTfLatticeElements, (void **)ppEnum);
}
SafeRelease(pEnumLE);
if ( ppAlt )
{
// Release references to alternate phrases.
for (int i = 0; i < (int)ulcMaxAlt; i++)
{
if (NULL != (ppAlt)[i])
{
((ppAlt)[i])->Release();
}
}
cicMemFree(ppAlt);
}
return hr;
}
//
// CEnumLatticeElements
//
//
// ctor / dtor
CEnumLatticeElements::CEnumLatticeElements(DWORD dwFrameStart)
{
m_dwFrameStart = dwFrameStart;
m_ulCur = (ULONG)-1;
m_ulTotal = 0;
m_cRef = 1;
}
CEnumLatticeElements::~CEnumLatticeElements()
{
// clean up the lattice elements here
int ulCount;
TF_LMLATTELEMENT * pLE;
ulCount = (int) Count( );
TraceMsg(TF_GENERAL, "CEnumLatticeElements::~CEnumLatticeElements: ulCount=%d", ulCount);
if (ulCount)
{
for (int i = 0; i < ulCount; i++)
{
pLE = GetPtr(i);
if ( pLE && pLE->bstrText)
{
::SysFreeString(pLE->bstrText);
pLE->bstrText=0;
}
}
}
}
// IUnknown
HRESULT CEnumLatticeElements::QueryInterface(REFIID riid, void **ppvObj)
{
HRESULT hr;
Assert(ppvObj);
if (IsEqualIID(riid, IID_IUnknown)
|| IsEqualIID(riid, IID_IEnumTfLatticeElements))
{
*ppvObj = this;
hr = S_OK;
this->m_cRef++;
}
else
{
*ppvObj = NULL;
hr = E_NOINTERFACE;
}
return hr;
}
ULONG CEnumLatticeElements::AddRef(void)
{
this->m_cRef++;
return this->m_cRef;
}
ULONG CEnumLatticeElements::Release(void)
{
this->m_cRef--;
if (this->m_cRef > 0)
{
return this->m_cRef;
}
delete this;
return 0;
}
// ITfEnumLatticeElements
HRESULT CEnumLatticeElements::Clone(IEnumTfLatticeElements **ppEnum)
{
HRESULT hr = E_INVALIDARG;
if (ppEnum)
{
CEnumLatticeElements *pele = new CEnumLatticeElements(m_dwFrameStart);
if ( !pele )
return E_OUTOFMEMORY;
if (pele->Append(Count()))
{
for (int i = 0; i < Count(); i++)
{
*(pele->GetPtr(i)) = *GetPtr(i);
Assert((pele->GetPtr(i))->bstrText);
(pele->GetPtr(i))->bstrText = SysAllocString(GetPtr(i)->bstrText);
}
pele->m_dwFrameStart = m_dwFrameStart;
hr = pele->QueryInterface(IID_IEnumTfLatticeElements, (void **)ppEnum);
}
else
{
delete pele;
hr = E_OUTOFMEMORY;
}
}
return hr;
}
HRESULT CEnumLatticeElements::Next(ULONG ulCount, TF_LMLATTELEMENT *rgsElements, ULONG *pcFetched)
{
if (ulCount == 0
|| rgsElements == NULL
|| pcFetched == NULL
)
return E_INVALIDARG;
// find the start position
if (m_dwFrameStart == -1)
{
m_ulCur = m_dwFrameStart = 0;
}
else
{
if (m_ulCur == (ULONG)-1)
{
_Find(m_dwFrameStart, &m_ulCur);
}
}
if (m_ulCur >= m_ulTotal)
{
// no more elements but OK
*pcFetched = 0;
}
else
{
// something to return
for (ULONG ul = m_ulCur;
ul < m_ulTotal && ul - m_ulCur < ulCount;
ul++)
{
rgsElements[ul-m_ulCur] = *GetPtr(ul);
}
*pcFetched = ul - m_ulCur;
}
return S_OK;
}
HRESULT CEnumLatticeElements::Reset()
{
m_ulCur = (ULONG)-1;
return S_OK;
}
HRESULT CEnumLatticeElements::Skip(ULONG ulCount)
{
// find the start position
if (m_dwFrameStart == -1)
{
m_ulCur = m_dwFrameStart = 0;
}
else
{
if (m_ulCur == (ULONG)-1)
{
_Find(m_dwFrameStart, &m_ulCur);
}
}
m_ulCur += ulCount;
if (m_ulCur > m_ulTotal)
m_ulCur = m_ulTotal;
return E_NOTIMPL;
}
//
// internal APIs
//
HRESULT CEnumLatticeElements::_InitFromPhrase
(
SPPHRASE *pPhrase,
ULONG ulStartElem,
ULONG ulNumElem
)
{
Assert(pPhrase);
if ( pPhrase == NULL)
return E_INVALIDARG;
HRESULT hr = S_OK;
// allocate the initial slots
if (!Append(ulNumElem))
{
hr = E_OUTOFMEMORY;
}
if (S_OK == hr)
{
long lEndElem;
long indexOrgList;
long indexNewList;
lEndElem = min(pPhrase->Rule.ulCountOfElements, ulStartElem + ulNumElem);
lEndElem --; // Real position ( offset from 0 ) for the last element
indexNewList = Count( ) - 1;
indexOrgList = indexNewList - ulNumElem;
m_ulTotal += ulNumElem;
TraceMsg(TF_GENERAL, "_InitFromPhrase: m_ulTotal=%d", m_ulTotal);
// FutureConsider: ITN has to be considered here!
for (long i=lEndElem; i>=(long)ulStartElem; i--)
{
TF_LMLATTELEMENT * pLE;
// Compare all the elements in the Org list from End to start
// with this new element's dwFrameStart,
// If dwFrameStart of the element in Org list is larger than(or equal to)
// this element's dwFrameStart, just move the org element
// to the current available position in the new list.
// until we find an element in the org list whose dwFrameStart is less than
// this element's dwFrameStart. we need to move this element to the
// new current available item in the new list.
// Current available position in the new list is from End to Start.
while ( (indexOrgList >=0) && (indexNewList >=0) && (S_OK == hr) )
{
pLE = GetPtr(indexOrgList);
if (pLE)
{
if ( pLE->dwFrameStart >= pPhrase->pElements[i].ulAudioTimeOffset )
{
// Move this Org element to a new postion in new List.
TF_LMLATTELEMENT * pNewLE;
pNewLE = GetPtr(indexNewList);
if ( pNewLE)
{
pNewLE->dwFrameStart = pLE->dwFrameStart;
pNewLE->dwFrameLen = pLE->dwFrameLen;
pNewLE->dwFlags = pLE->dwFlags;
pNewLE->iCost = pLE->iCost;
pNewLE->bstrText = pLE->bstrText;
pLE->dwFrameStart = 0;
pLE->dwFrameLen = 0;
pLE->dwFlags = 0;
pLE->iCost = 0;
pLE->bstrText = 0;
}
// update the index position in both org and new list
indexNewList --;
indexOrgList --;
}
else
{
// current element from this phrase should be moved to the new list
break;
}
}
else
{
TraceMsg(TF_GENERAL, "CEnumLatticeElements::_InitFromPhrase: pLE is NULL");
hr = E_FAIL;
break;
}
} //while
if ( (S_OK == hr) && (indexNewList >=0) )
{
pLE = GetPtr(indexNewList);
if (pLE)
{
pLE->dwFrameStart = pPhrase->pElements[i].ulAudioTimeOffset;
pLE->dwFrameLen = pPhrase->pElements[i].ulAudioSizeTime;
pLE->dwFlags = 0; // for now
pLE->iCost = pPhrase->pElements[i].ActualConfidence;
pLE->bstrText = SysAllocString(pPhrase->pElements[i].pszDisplayText);
TraceMsg(TF_GENERAL, "i=%d, dwFramStart=%d bstrText=%S", i, pLE->dwFrameStart, pLE->bstrText);
indexNewList--;
}
}
} // for
} // if
return hr;
}
//
// _Find()
//
// slightly modified version of array find
//
ULONG CEnumLatticeElements::_Find(DWORD dwFrame, ULONG *pul)
{
int iMatch = -1;
int iMid = -1;
int iMin = 0;
int iMax = _cElems;
while(iMin < iMax)
{
iMid = (iMin + iMax) / 2;
DWORD dwCur = GetPtr(iMid)->dwFrameStart;
if (dwFrame < dwCur)
{
iMax = iMid;
}
else if (dwFrame > dwCur)
{
iMin = iMid + 1;
}
else
{
iMatch = iMid;
break;
}
}
if (pul)
{
if ((iMatch == -1) && (iMid >= 0))
{
if (dwFrame < GetPtr(iMid)->dwFrameStart)
iMid--;
}
*pul = iMid;
}
return iMatch;
}