// // 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 cpServicePrv; CComPtr 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; iGetPhrase(&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; }