////////////////////////////////////////////////////////////////////// // DbQuery.cpp: implementation of the CDbQuery class. // // Created by JOEM 03-2000 // Copyright (C) 2000 Microsoft Corporation // All Rights Reserved // /////////////////////////////////////////////////////// JOEM 3-2000 // #include "stdafx.h" #include "DbQuery.h" #include "PromptDb.h" #include ////////////////////////////////////////////////////////////////////// // CEquivCost // // Construction/Destruction ////////////////////////////////////////////////////////////////////// CEquivCost::CEquivCost() { text = NULL; entry = NULL; fTagMatch = true; } CEquivCost::CEquivCost(const CEquivCost& old) { if ( text ) { text = wcsdup(old.text); } else { text = NULL; } if ( entry ) { entry = new CPromptEntry(*old.entry); } else { entry = NULL; } cost = old.cost; whereFrom = old.whereFrom; fTagMatch = old.fTagMatch; } CEquivCost::~CEquivCost() { if ( text ) { free(text); text = NULL; } if ( entry ) { entry->Release(); entry = NULL; } } ////////////////////////////////////////////////////////////////////// // CCandidate // // Construction/Destruction ////////////////////////////////////////////////////////////////////// CCandidate::CCandidate() { equivList = NULL; parent = NULL; firstPos = 0; lastPos = 0; candMax = 0; candNum = 0; iQueryNum = 0; } CCandidate::CCandidate(const CCandidate& old) { CEquivCost* equiv = NULL; firstPos = old.firstPos; lastPos = old.lastPos; candMax = old.candMax; candNum = old.candNum; iQueryNum = old.iQueryNum; parent = old.parent; if ( old.equivList && old.equivList->GetSize() ) { equivList = new CSPArray; for (USHORT i=0; iGetSize(); i++) { equiv = new CEquivCost( *(*old.equivList)[i] ); equivList->Add(equiv); } } } CCandidate::~CCandidate() { USHORT i = 0; if ( equivList ) { for ( i=0; iGetSize(); i++ ) { if ( (*equivList)[i] ) { delete (*equivList)[i]; (*equivList)[i] = NULL; } } equivList->RemoveAll(); delete equivList; } parent = NULL; } ////////////////////////////////////////////////////////////////////// // CDbQuery // // Construction/Destruction ////////////////////////////////////////////////////////////////////// CDbQuery::CDbQuery() { m_pIDb = NULL; m_pPhoneContext = NULL; m_papQueries = NULL; m_pOutputSite = NULL; m_iCurrentQuery = 0; m_fAbort = false; } CDbQuery::~CDbQuery() { USHORT i = 0; if ( m_pIDb ) { m_pIDb->Release(); m_pIDb = NULL; } // These are just pointers set in CDbQuery::Init and CDbQuery::Query (deallocated elsewhere) m_pPhoneContext = NULL; m_papQueries = NULL; // To be safe, I'll keep this list deletion here. // However, it is generally deleted when CDbQuery::Query calls CDbQuery::Reset m_apCandEnd.RemoveAll(); for ( i=0; iAddRef(); m_pPhoneContext = pPhoneContext; SPDBG_REPORT_ON_FAIL( hr ); return hr; } ////////////////////////////////////////////////////////////////////// // CDbQuery::Reset // // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CDbQuery::Reset() { SPDBG_FUNC( "CDbQuery::Reset" ); USHORT i = 0; m_iCurrentQuery = 0; m_papQueries = NULL; m_apCandEnd.RemoveAll(); for ( i=0; i* papQueries, double* pdCost, ISpTTSEngineSite* pOutputSite, bool *fAbort) { SPDBG_FUNC( "CDbQuery::Query" ); HRESULT hr = S_OK; USHORT i = 0; USHORT j = 0; USHORT unIdSize = 0; const WCHAR* pszId = NULL; WCHAR* pszText = NULL; CQuery* pQuery = NULL; SPDBG_ASSERT(papQueries); SPDBG_ASSERT(pOutputSite); m_pOutputSite = pOutputSite; m_papQueries = papQueries; m_fAbort = false; for ( i=0; SUCCEEDED(hr) && i < m_papQueries->GetSize(); i++ ) { if ( m_pOutputSite->GetActions() & SPVES_ABORT ) { m_fAbort = true; break; } if ( SUCCEEDED(hr) ) { pQuery = (*m_papQueries)[i]; m_iCurrentQuery = i; if ( !pQuery->m_fSpeak ) { continue; } } if ( SUCCEEDED(hr) ) { if ( pQuery->m_fXML ) { // If the database needs to be changed, do it now. if ( pQuery->m_unDbAction ) { switch ( pQuery->m_unDbAction ) { case DB_ADD: if ( !pQuery->m_pszDbPath ) { hr = E_INVALIDARG; } if ( SUCCEEDED(hr) ) { hr = m_pIDb->AddDb(pQuery->m_pszDbName, pQuery->m_pszDbPath, pQuery->m_pszDbIdSet, DB_LOAD); } if ( SUCCEEDED(hr) ) { free( pQuery->m_pszDbName ); pQuery->m_pszDbName = NULL; } break; case DB_ACTIVATE: if ( !pQuery->m_pszDbName ) { hr = E_INVALIDARG; } if ( SUCCEEDED(hr) ) { hr = m_pIDb->ActivateDbName(pQuery->m_pszDbName); } break; case DB_UNLOAD: hr = m_pIDb->UnloadDb(pQuery->m_pszDbName); break; default: break; } continue; } // if ( pQuery->m_unDbAction ) // ID search else if ( pQuery->m_pszId ) { hr = SearchId( pQuery->m_pszId ); continue; } else { // Any XML besides DATABASE or ID can be ignored here. if ( pQuery->m_fXML == UNKNOWN_XML ) { pQuery->m_fTTS = true; } continue; } } // if ( pQuery->m_fXML ) } // if ( SUCCEEDED(hr) ) // For Text, search in the Db first, then do SearchBackup (for TTS costs) if ( SUCCEEDED (hr) ) { if ( !pQuery->m_fTTS ) { hr = SearchText( pQuery->m_pszExpandedText, pQuery->m_paTagList ); if ( FAILED(hr) ) { pQuery->m_afEntryMatch.Add(false); if ( pQuery->m_fFragType ) { hr = RemoveLocalQueries(i); } } } // SearchBackup for TTS items, or if SearchText failed. if ( pQuery->m_fSpeak && ( pQuery->m_fTTS || FAILED(hr) ) ) { pszText = new WCHAR[pQuery->m_pTextFrag->ulTextLen + 1]; if ( pszText ) { hr = S_OK; } else { hr = E_OUTOFMEMORY; } if ( SUCCEEDED(hr) ) { wcsncpy(pszText, pQuery->m_pTextFrag->pTextStart, pQuery->m_pTextFrag->ulTextLen); pszText[pQuery->m_pTextFrag->ulTextLen] = L'\0'; hr = SearchBackup( pszText ); delete pszText; pszText = NULL; } if ( SUCCEEDED(hr) ) { pQuery->m_fTTS = true; pQuery->m_afEntryMatch.Add(true); } } } } // for ( i=0; i < m_papQueries->GetSize(); i++ ) // Backtrack, selecting the search items with min. cost if ( SUCCEEDED(hr) && !m_fAbort ) { hr = Backtrack( pdCost ); } Reset(); *fAbort = m_fAbort; SPDBG_REPORT_ON_FAIL( hr ); return hr; } ////////////////////////////////////////////////////////////////////// // CDbQuery::SearchId // // Checks the Db for specific Ids, adds them to the candidate list // for backtracking later (in CDbQuery::Query). // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CDbQuery::SearchId(const WCHAR* pszId) { SPDBG_FUNC( "CDbQuery::SearchId" ); HRESULT hr = S_OK; CCandidate* newCand = NULL; IPromptEntry* pIPE = NULL; USHORT i = 0; SPDBG_ASSERT( pszId ); hr = m_pIDb->FindEntry(pszId, &pIPE); if ( SUCCEEDED(hr) ) { newCand = new CCandidate; if ( !newCand ) { hr = E_OUTOFMEMORY; } if ( SUCCEEDED(hr) ) { newCand->firstPos = 0; newCand->lastPos = 0; newCand->candMax = 1; newCand->candNum = 0; newCand->parent = NULL; newCand->iQueryNum = m_iCurrentQuery; hr = ComputeCostsId (newCand, pIPE); } if ( SUCCEEDED(hr) ) { m_apCandidates.Add(newCand); m_apCandEnd.RemoveAll(); m_apCandEnd.Add(newCand); } if ( FAILED(hr) && newCand ) { delete newCand; newCand = NULL; } pIPE->Release(); } SPDBG_REPORT_ON_FAIL( hr ); return hr; } ////////////////////////////////////////////////////////////////////// // CDbQuery::SearchText // // Searches the Db for text. If found, adds the items (with computed // transition costs) to the candidate list for backtracking later // (in CDbQuery::Query). // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CDbQuery::SearchText(WCHAR *pszText, const CSPArray* tags) { SPDBG_FUNC( "CDbQuery::SearchText" ); HRESULT hr = S_OK; WCHAR** wordList = NULL; USHORT wordCount = 0; int i = 0; // THIS MUST BE SIGNED int j = 0; int k = 0; bool* pfSearch = NULL; CSPArray* activeCand; CSPArray* tmpCandEnd; CCandidate* newCand = NULL; hr = SplitWords (pszText, &wordList, &wordCount); if ( SUCCEEDED(hr) ) { hr = RemovePunctuation(wordList, &wordCount); } if ( wordCount <= 0 ) { return hr; } // These flags turn on the searches that start with word position i // A search is later turned on if a previous search ended at i-1. pfSearch = new bool[wordCount]; if ( !pfSearch ) { hr = E_OUTOFMEMORY; } else { pfSearch[0] = true; // always do the first search for ( i=1; i; if ( !activeCand ) { hr = E_OUTOFMEMORY; } } // Get the active candidate list from previous search, if any. if ( SUCCEEDED(hr) ) { // Any previous candidates? if ( m_apCandEnd.GetSize() == 0 ) { // No, then start a new cand list from scratch. newCand = new CCandidate; if ( !newCand ) { hr = E_OUTOFMEMORY; } if ( SUCCEEDED(hr) ) { newCand->equivList = NULL; // the list of IDs that exist for this text newCand->firstPos = 0; // the word pos where this cand starts newCand->lastPos = -1; // the last word pos for this candidate (-1 initially) newCand->candMax = wordCount; // the max number of cands for this string newCand->candNum = 0; // the number of cands for this path newCand->parent = NULL; newCand->iQueryNum = m_iCurrentQuery; // the query number where this cand goes when backtracking m_apCandidates.Add(newCand); activeCand->Add(newCand); } } else { // Yes, then get the current candEnds and put them on the activeCand list CCandidate* tmp = NULL; for ( i = m_apCandEnd.GetUpperBound(); i >= 0; i--) { tmp = m_apCandEnd[i]; if ( !tmp ) { hr = E_UNEXPECTED; } if ( SUCCEEDED(hr) ) { tmp->firstPos = 0; tmp->lastPos = -1; tmp->candMax = wordCount; tmp->candNum = 0; activeCand->Add(tmp); } } } // else } // if ( SUCCEEDED(hr) // initialize a temporary candEnd list. if ( SUCCEEDED(hr) ) { tmpCandEnd = new CSPArray; if ( !tmpCandEnd ) { hr = E_OUTOFMEMORY; } } // BEGIN THE SEARCH // For each word position (i), search to the end, which is (wordcount - i) searches. // e.g., for "A B C": // when i==0, search "A", "A B", "A B C" // when i==1, search "B", "B C" // when i==2, search "C" // For each successful search, compute the cost from the previous candEnds, and // for each ID returned by the search. // For each ID, keep only the cheapest path. Discard the rest. for ( i=0; SUCCEEDED(hr) && iGetActions() & SPVES_ABORT ) { m_fAbort = true; break; } if ( SUCCEEDED(hr) ) { hr = AssembleText( i, j, wordList, &tmpStr ); } // Then, search for it if ( SUCCEEDED(hr) ) { HRESULT hrSearch = S_OK; USHORT idCount = 0; //OutputDebugStringW ( L"Searching for: " ); //OutputDebugStringW (tmpStr); //OutputDebugStringW ( L"\n" ); hrSearch = m_pIDb->SearchDb(tmpStr, &idCount); // get a count of the id's to retrieve for this text // If the search succeeds, retrieve each ID for this text. if ( SUCCEEDED(hrSearch) ) { const WCHAR* pszId = NULL; CSPArray idList; for ( k=0; kRetrieveSearchItem( (USHORT) k, &pszId); if ( SUCCEEDED(hr) && pszId ) { idList.Add(pszId); pszId = NULL; } } if ( k == idCount ) { if ( j < wordCount-1 ) // if this is not the end, { pfSearch[j+1] = true; // activate search for remaining items } //OutputDebugStringW ( L"FOUND!\n" ); } double dMin = DBL_MAX; double dCand = 0.0; CCandidate* bestCandidate = NULL; CCandidate* current = NULL; // compute costs from each activeCand that ends where this starts for ( k=0; SUCCEEDED(hr) && kGetSize(); k++ ) { // keep going? if ( m_pOutputSite->GetActions() & SPVES_ABORT ) { m_fAbort = true; break; } if ( SUCCEEDED(hr) ) { current = (*activeCand)[k]; if ( current->lastPos != i-1 ) // can the new cand attach to this one? { continue; } } // make a new temporary candidate if ( SUCCEEDED(hr) ) { newCand = new CCandidate; if ( !newCand ) { hr = E_OUTOFMEMORY; break; } } if ( SUCCEEDED(hr) ) { newCand->equivList = NULL; newCand->firstPos = i; // starting search position newCand->lastPos = j; //+1; // last word number newCand->candMax = wordCount - j; newCand->candNum = 0; newCand->parent = current; newCand->iQueryNum = m_iCurrentQuery; } hr = ComputeCosts(current, newCand, tags, &idList, AS_ENTRY, &dCand); if ( SUCCEEDED(hr) ) { // keep the best, delete the rest. if ( dCand < dMin ) { delete bestCandidate; bestCandidate = newCand; dMin = dCand; } else { delete newCand; newCand = NULL; } } } if ( SUCCEEDED (hr) && !m_fAbort ) { if ( j == wordCount-1 ) // complete candidate { tmpCandEnd->Add(bestCandidate); } else { activeCand->Add(bestCandidate); // save it so we can search for the rest. } m_apCandidates.Add(bestCandidate); } bestCandidate = NULL; for ( k=0; kGetUpperBound(); j>=0; j-- ) { CCandidate* temp = (*activeCand)[j]; if ( temp->lastPos < i ) { activeCand->RemoveAt( j ); // remove it. } temp = NULL; } } } // for ( i=0; SUCCEEDED(hr) && iGetSize() ) { hr = E_FAIL; } } if ( SUCCEEDED(hr) && !m_fAbort ) { CCandidate* saveCand = NULL; m_apCandEnd.RemoveAll(); while ( tmpCandEnd->GetSize() ) { saveCand = (*tmpCandEnd)[tmpCandEnd->GetUpperBound()]; tmpCandEnd->RemoveAt( tmpCandEnd->GetUpperBound() ); m_apCandEnd.Add(saveCand); } } if ( SUCCEEDED(hr) && !m_fAbort ) { // now these should be empty. SPDBG_ASSERT( !tmpCandEnd->GetSize() ); SPDBG_ASSERT( !activeCand->GetSize() ); } if ( tmpCandEnd ) { delete tmpCandEnd; } if ( activeCand ) { delete activeCand; } if ( wordList ) { free (wordList); } if ( pfSearch ) { delete [] pfSearch; pfSearch = NULL; } return hr; } ////////////////////////////////////////////////////////////////////// // CDbQuery::SearchBackup // // Computes costs for a TTS item, adds it to candidate list for // backtracking (in CDbQuery::Query). // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CDbQuery::SearchBackup(const WCHAR *pszText) { SPDBG_FUNC( "CDbQuery::SearchBackup" ); HRESULT hr = S_OK; CCandidate* newCand = NULL; USHORT i = 0; newCand = new CCandidate; if ( !newCand ) { hr = E_OUTOFMEMORY; } if ( SUCCEEDED(hr) ) { newCand->firstPos = 0; newCand->lastPos = 0; newCand->candMax = 1; newCand->candNum = 0; newCand->parent = NULL; newCand->iQueryNum = m_iCurrentQuery; hr = ComputeCostsText (newCand, pszText); } if ( SUCCEEDED(hr) ) { m_apCandidates.Add(newCand); m_apCandEnd.RemoveAll(); m_apCandEnd.Add(newCand); } SPDBG_REPORT_ON_FAIL( hr ); return hr; } ////////////////////////////////////////////////////////////////////// // CDbQuery::Backtrack // // Backtracks the candidate list, keeping items that minimize costs. // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CDbQuery::Backtrack(double* pdCost) { SPDBG_FUNC( "CDbQuery::Backtrack" ); CCandidate* cur = NULL; CEquivCost* equiv = NULL; USHORT nCand = 0; USHORT nEquiv = 0; int minIdx = 0; int minIdx2 = 0; USHORT i = 0; USHORT j = 0; double minCost = 0; nCand = (USHORT) m_apCandEnd.GetSize(); if ( nCand ) { minCost = DBL_MAX; } // Look at the last item in each path, and get the Idx of the path with lowest cost for (i=0; iequivList ) { nEquiv = (USHORT) cur->equivList->GetSize(); } for (j=0; jequivList)[j]; if (equiv->cost < minCost) { minCost = equiv->cost; minIdx = i; minIdx2 = j; } } } // Go back through the path and get the items if (nCand) { cur = m_apCandEnd[minIdx]; while ( cur && cur->equivList && cur->equivList->GetSize() ) { equiv = (*cur->equivList)[minIdx2]; if ( equiv->entry ) { (*m_papQueries)[cur->iQueryNum]->m_apEntry.Add(equiv->entry); equiv->entry->AddRef(); (*m_papQueries)[cur->iQueryNum]->m_afEntryMatch.Add(equiv->fTagMatch); (*m_papQueries)[cur->iQueryNum]->m_fTTS = false; } else { (*m_papQueries)[cur->iQueryNum]->m_fTTS = true; } minIdx2 = equiv->whereFrom; cur = cur->parent; equiv = NULL; } } *pdCost = minCost; return S_OK; } ////////////////////////////////////////////////////////////////////// // CDbQuery::ComputeCosts // // Cost computation // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CDbQuery::ComputeCosts(CCandidate *parent, CCandidate *child, const CSPArray* tags, CSPArray* idList, const bool asEntry, double *dCandCost) { SPDBG_FUNC( "CDbQuery::ComputeCosts" ); HRESULT hr = S_OK; USHORT nEquiv = 0; USHORT nParentEquiv = 0; USHORT i = 0; USHORT j = 0; int minIdx = 0; const WCHAR* id = NULL; double minCost = 0.0; double cost = 0.0; CEquivCost* curCand = NULL; CEquivCost* prevCand = NULL; IPromptEntry* pIPE = NULL; CSPArray* equivList = NULL; SPDBG_ASSERT (parent); SPDBG_ASSERT (child); SPDBG_ASSERT (idList); nEquiv = (USHORT) idList->GetSize(); if ( parent->equivList ) { nParentEquiv = (USHORT) parent->equivList->GetSize(); } equivList = new CSPArray; if ( !equivList ) { hr = E_OUTOFMEMORY; } for (i=0; iFindEntry(id, &pIPE); if ( SUCCEEDED(hr) ) { hr = CopyEntry(pIPE, &curCand->entry); pIPE->Release(); } } } if ( SUCCEEDED(hr) ) { curCand->cost = 0.0; curCand->whereFrom = -1; minCost = DBL_MAX; minIdx = -1; } // This is the minimizing loop if ( SUCCEEDED(hr) ) { if (nParentEquiv) { for (j=0; jequivList)[j]; SPDBG_ASSERT (prevCand); hr = CostFunction (prevCand, curCand, tags, &cost); if ( SUCCEEDED(hr) ) { if (cost < minCost ) { minCost = cost; minIdx = j; } } } if ( SUCCEEDED(hr) && minIdx == -1 ) { hr = E_FAIL; } } else { hr = CostFunction (prevCand, curCand, tags, &minCost); } } if ( SUCCEEDED(hr) ) { curCand->cost = minCost; if ( dCandCost ) { *dCandCost = minCost; } curCand->whereFrom = minIdx; equivList->Add(curCand); } } // for if ( SUCCEEDED(hr) ) { child->equivList = equivList; } else { if ( curCand ) { delete curCand; curCand = NULL; } } SPDBG_REPORT_ON_FAIL( hr ); return hr; } ////////////////////////////////////////////////////////////////////// // CDbQuery::ComputeCostsId // // Cost computation // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CDbQuery::ComputeCostsId(CCandidate *child, IPromptEntry* pIPE) { SPDBG_FUNC( "CDbQuery::ComputeCostsId" ); HRESULT hr = S_OK; CCandidate* parent = NULL; CCandidate* minParent = NULL; CEquivCost* curCand = NULL; CEquivCost* prevCand = NULL; USHORT nParent = 0; USHORT nParentEquiv= 0; int minIdx = 0; double minCost = 0.0; double cost = 0.0; USHORT i = 0; USHORT j = 0; CSPArray* equivList; curCand = new CEquivCost; if ( !curCand ) { hr = E_OUTOFMEMORY; } hr = CopyEntry( pIPE, &curCand->entry ); if ( SUCCEEDED(hr) ) { curCand->cost = 0.0; curCand->whereFrom = -1; minParent = NULL; minCost = DBL_MAX; minIdx = -1; nParent = (USHORT) m_apCandEnd.GetSize(); } // This is the minimizing loop for (i=0; iequivList->GetSize(); if (nParentEquiv) { for ( j=0; jequivList)[j]; hr = CostFunction (prevCand, curCand, NULL, &cost); if ( SUCCEEDED(hr) ) { if (cost < minCost ) { minCost = cost; minIdx = j; minParent = parent; } } } if ( SUCCEEDED(hr) && minIdx == -1 ) { hr = E_FAIL; } } else { minCost = 0.0; } if ( SUCCEEDED(hr) ) { curCand->cost = minCost; curCand->whereFrom = minIdx; } } if ( SUCCEEDED(hr) ) { equivList = new CSPArray; if (!equivList) { hr = E_OUTOFMEMORY; } } if ( SUCCEEDED(hr) ) { equivList->Add(curCand); child->equivList = equivList; child->parent = minParent; } if ( FAILED(hr) ) { delete curCand; } SPDBG_REPORT_ON_FAIL( hr ); return hr; } ////////////////////////////////////////////////////////////////////// // CDbQuery::ComputeCostsText // // Cost computation // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CDbQuery::ComputeCostsText(CCandidate *child, const WCHAR *pszText) { SPDBG_FUNC( "CDbQuery::ComputeCostsText" ); HRESULT hr = S_OK; USHORT nParent = 0; USHORT nParentEquiv = 0; int minIdx = 0; double minCost = 0.0; double cost = 0.0; USHORT i = 0; USHORT j = 0; CEquivCost* curCand = NULL; CEquivCost* prevCand = NULL; CCandidate* parent = NULL; CCandidate* minParent= NULL; CSPArray* equivList; SPDBG_ASSERT (child); SPDBG_ASSERT (pszText); equivList = new CSPArray; if ( !equivList ) { hr = E_OUTOFMEMORY; } if ( SUCCEEDED(hr) ) { curCand = new CEquivCost; if ( !curCand ) { hr = E_OUTOFMEMORY; } } if ( SUCCEEDED(hr) ) { curCand->cost = 0.0; curCand->whereFrom = -1; curCand->text = wcsdup(pszText); if ( !curCand->text ) { hr = E_OUTOFMEMORY; } } if ( SUCCEEDED(hr) ) { minParent = NULL; minCost = DBL_MAX; minIdx = -1; nParent = (USHORT) m_apCandEnd.GetSize(); } if ( !nParent ) { hr = CostFunction (NULL, curCand, NULL, &cost); if ( SUCCEEDED(hr) ) { curCand->cost = cost; curCand->whereFrom = minIdx; } } else { // This is the minimizing loop for (i=0; iequivList->GetSize(); if (nParentEquiv) { for (j=0; jequivList)[j]; hr = CostFunction (prevCand, curCand, NULL, &cost); if ( SUCCEEDED(hr) ) { if (cost < minCost ) { minCost = cost; minIdx = j; minParent = parent; } } } if ( SUCCEEDED(hr) && minIdx == -1 ) { hr = E_FAIL; } } else { minCost = 0.0; } if ( SUCCEEDED(hr) ) { curCand->cost = minCost; curCand->whereFrom = minIdx; } } } if ( SUCCEEDED(hr) ) { equivList->Add(curCand); child->equivList = equivList; child->parent = minParent; } else { if ( curCand ) { delete curCand; } } SPDBG_REPORT_ON_FAIL( hr ); return hr; } ////////////////////////////////////////////////////////////////////// // CDbQuery::CostFunction // // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CDbQuery::CostFunction(CEquivCost *prev, CEquivCost *cur, const CSPArray* tags, double *cost) { SPDBG_FUNC( "CDbQuery::CostFunction" ); HRESULT hr = S_OK; SPDBG_ASSERT (cur); SPDBG_ASSERT (cost); if ( prev ) { *cost = prev->cost; } else { *cost = 0.0; } // Cost of using TTS if ( cur->text ) { if ( prev ) { // if we're transitioning from prompts, add the transition cost + TTS insert cost. if ( prev->entry ) { *cost += FIXED_TRANSITION_COST; // Fixed cost for a transition *cost += TTS_INSERT_COST; // * CountWords (cur->text); } } else // otherwise, just add the TTS cost { *cost += TTS_INSERT_COST; // * CountWords (cur->text); } } else // Cost of using an entry; { double tagCost = MATCHING_TAG_COST; USHORT nEntryTags = 0; if ( prev ) { *cost += FIXED_TRANSITION_COST; // Fixed cost for a transition } cur->entry->CountTags(&nEntryTags); if ( !tags ) { if ( nEntryTags ) { *cost += NON_MATCHING_TAG_COST; cur->fTagMatch = false; } } else { USHORT i = 0; CSpDynamicString curTag; USHORT nTags = (USHORT) tags->GetSize(); for (i=0; ientry->GetTag(&entryTag, j); if ( SUCCEEDED(hr) ) { if ( wcscmp(curTag, entryTag) == 0 ) { entryTag = NULL; break; } entryTag = NULL; } } if (j == nEntryTags) { tagCost = NON_MATCHING_TAG_COST; cur->fTagMatch = false; } } //--- An empty curTag should still match with an entry that has no tags else if ( wcscmp(curTag,emptyTag) != 0 ) { tagCost = NON_MATCHING_TAG_COST; cur->fTagMatch = false; } *cost += tagCost; curTag.Clear(); } // for each tag } } // else // If there is information about phonetic // context, apply it if ( SUCCEEDED(hr) ) { if ( m_pPhoneContext && prev && prev->entry && cur->entry ) { double cntxtCost; hr = m_pPhoneContext->Apply( prev->entry, cur->entry, &cntxtCost ); if ( SUCCEEDED (hr) ) { *cost += cntxtCost; } } } SPDBG_REPORT_ON_FAIL( hr ); return hr; } ////////////////////////////////////////////////////////////////////// // CDbQuery::CopyEntry // // Creates and returns a copy of the entry pointed to by pIPE. // /////////////////////////////////////////////////////// JOEM 5-2000 // HRESULT CDbQuery::CopyEntry(IPromptEntry *pIPE, CPromptEntry** inEntry) { SPDBG_FUNC( "CDbQuery::CopyEntry" ); HRESULT hr = S_OK; double entryTime = 0.0; const WCHAR* entryText = NULL; USHORT i = 0; USHORT tagCount = 0; CPromptEntry* newEntry = new CPromptEntry ( *(CPromptEntry*)pIPE ); if ( !newEntry ) { hr = E_OUTOFMEMORY; } *inEntry = newEntry; SPDBG_REPORT_ON_FAIL( hr ); return hr; } ////////////////////////////////////////////////////////////////////// // CDbQuery::RemoveLocalQueries // // When a local query (from an expansion rule) fails, remove all // associated local queries, and reinstate the main query. // /////////////////////////////////////////////////////// JOEM 5-2000 // HRESULT CDbQuery::RemoveLocalQueries(const USHORT unQueryNum) { SPDBG_FUNC( "CDbQuery::RemoveLocalQueries" ); SHORT i = 0; CQuery* pQuery = NULL; // Take care of current query first pQuery = (*m_papQueries)[unQueryNum]; // If it's a local query, cancel it and the surrounding local queries, // and restoring the original for TTS. if ( pQuery->m_fFragType == LOCAL_FRAG ) { pQuery->m_fSpeak = FALSE; // step backward, flagging previous local queries as "don't speak" for ( i = unQueryNum-1; i>=0; i-- ) { pQuery = (*m_papQueries)[i]; if ( pQuery->m_fFragType == LOCAL_FRAG ) { pQuery->m_fSpeak = false; } else { break; } } // step forward, flagging upcoming local queries as "don't speak" for ( i = unQueryNum+1; iGetSize(); i++ ) { pQuery = (*m_papQueries)[i]; if ( pQuery->m_fFragType == LOCAL_FRAG ) { pQuery->m_fSpeak = false; } else { pQuery->m_fSpeak = true; pQuery->m_fTTS = true; // this wasn't supposed to be spoken, but now it must, so match is false. pQuery->m_afEntryMatch.Add(false); break; } } } else // It's a combined frag - restore upcoming combined frags too. { pQuery->m_fTTS = true; for ( i = unQueryNum+1; iGetSize(); i++ ) { pQuery = (*m_papQueries)[i]; if ( pQuery->m_fFragType == COMBINED_FRAG ) { pQuery->m_fFragType = SAPI_FRAG; pQuery->m_fSpeak = true; pQuery->m_fTTS = true; } else { break; } } } return S_OK; }