////////////////////////////////////////////////////////////////////// // PhoneContext.cpp: implementation of the CPhoneContext class and // subclasses. // // Created by JOEM 03-2000 // Copyright (C) 2000 Microsoft Corporation // All Rights Reserved // /////////////////////////////////////////////////////// JOEM 3-2000 // #include "stdafx.h" #include "PhoneContext.h" #include ////////////////////////////////////////////////////////////////////// // CPhoneContext // Construction/Destruction /////////////////////////////////////////////////////// JOEM 3-2000 // CPhoneContext::CPhoneContext() { m_ulNRules = 0; m_ppContextRules = NULL; } CPhoneContext::~CPhoneContext() { ULONG i = 0; ULONG j = 0; ULONG k = 0; for (i=0; im_pszRuleName = wcsdup(pszText)) == NULL) { hr = E_OUTOFMEMORY; } else { hr = RegularizeText(newRule->m_pszRuleName, KEEP_PUNCTUATION); } } if ( SUCCEEDED(hr) ) { m_ppContextRules[m_ulNRules] = newRule; m_ulNRules++; } if ( FAILED(hr) ) { if ( newRule ) { if ( newRule->m_pszRuleName ) { free (newRule->m_pszRuleName); newRule->m_pszRuleName = NULL; } free (newRule); newRule = NULL; } } return hr; } ////////////////////////////////////////////////////////////////////// // CPhoneContext::ParsePhoneClass // // Reads, parses, creates a phone class. Adds phones to class. // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CPhoneContext::ParsePhoneClass(const Macro *pMacros, const USHORT unMacros, CContextRule* pRule, WCHAR **ppszOrig) { HRESULT hr = S_OK; WCHAR* ptr = NULL; WCHAR* end = NULL; int i; SPDBG_ASSERT (ppszOrig && *ppszOrig); ptr = *ppszOrig; WSkipWhiteSpace (ptr); end = ptr; WSkipNonWhiteSpace (end); *end++ = L'\0'; if ( SUCCEEDED(hr) ) { hr = CreatePhoneClass (&pRule->m_pvPhoneClasses, &pRule->m_unNPhoneClasses, ptr); } if ( SUCCEEDED(hr) ) { ptr = end; WSkipWhiteSpace (ptr); if (*ptr != L'{') { return 0; } ptr ++; WSkipWhiteSpace (ptr); } if ( SUCCEEDED(hr) ) { while ( SUCCEEDED(hr) && *ptr!= L'}' ) { if (*ptr == L'\0') { hr = E_FAIL; } if ( SUCCEEDED(hr) ) { end = ptr; WSkipNonWhiteSpace (end); *end++ = L'\0'; hr = AddPhoneToClass (pRule->m_pvPhoneClasses[pRule->m_unNPhoneClasses-1], ptr); } if ( SUCCEEDED(hr) ) { ptr = end; WSkipWhiteSpace (ptr); } } } if ( SUCCEEDED(hr) ) { ptr++; WSkipWhiteSpace(ptr); if (*ptr == L'%') { // It is a macro ptr++; for (i=0; im_pvPhoneClasses[pRule->m_unNPhoneClasses-1]->m_dWeight = pMacros[i].value; break; } } if (i == unMacros) { hr = E_FAIL; } } else { // Get the value directly pRule->m_pvPhoneClasses[pRule->m_unNPhoneClasses-1]->m_dWeight = wcstod(ptr, NULL); } } if ( SUCCEEDED(hr) ) { WSkipNonWhiteSpace(ptr); WSkipWhiteSpace(ptr); *ppszOrig = ptr; } return hr; } ////////////////////////////////////////////////////////////////////// // CPhoneContext // // CreatePhoneClass // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CPhoneContext::CreatePhoneClass(CPhoneClass*** pppClasses, USHORT* punClasses, const WCHAR *psz) { HRESULT hr = S_OK; CPhoneClass* phClass = NULL; SPDBG_ASSERT (pppClasses); SPDBG_ASSERT (punClasses); SPDBG_ASSERT (psz); if ( SUCCEEDED(hr) ) { if ((phClass = (CPhoneClass*) calloc (1, sizeof(*phClass))) == NULL) { hr = E_OUTOFMEMORY; } } if ( SUCCEEDED(hr) ) { if ((phClass->m_pszPhoneClassName = wcsdup(psz)) == NULL) { hr = E_OUTOFMEMORY; } else { hr = RegularizeText(phClass->m_pszPhoneClassName, KEEP_PUNCTUATION); } } if ( SUCCEEDED(hr) ) { if (*pppClasses) { *pppClasses = (CPhoneClass**) realloc (*pppClasses, (*punClasses +1) * sizeof(**pppClasses)); } else { *pppClasses = (CPhoneClass**) malloc (sizeof(**pppClasses)); } if (*pppClasses == NULL) { hr = E_OUTOFMEMORY; } } if ( SUCCEEDED(hr) ) { (*pppClasses)[*punClasses] = phClass; (*punClasses)++; } if ( FAILED(hr) ) { DeletePhoneClass (phClass); } return hr; } ////////////////////////////////////////////////////////////////////// // CPhoneContext // // AddPhoneToClass // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CPhoneContext::AddPhoneToClass(CPhoneClass* phClass, WCHAR *phone) { HRESULT hr = S_OK; SPDBG_ASSERT(phClass); if (phClass->m_pppszPhones) { phClass->m_pppszPhones = (WCHAR**) realloc (phClass->m_pppszPhones, (phClass->m_unNPhones +1) * sizeof (*phClass->m_pppszPhones)); } else { phClass->m_pppszPhones = (WCHAR**) malloc (sizeof (*phClass->m_pppszPhones)); } if (phClass->m_pppszPhones == NULL) { hr = E_OUTOFMEMORY; } if ( SUCCEEDED(hr) ) { if ( (phClass->m_pppszPhones[phClass->m_unNPhones] = wcsdup(phone)) == NULL ) { hr = E_OUTOFMEMORY; } else { hr = RegularizeText(phClass->m_pppszPhones[phClass->m_unNPhones], KEEP_PUNCTUATION); } } if ( SUCCEEDED(hr) ) { phClass->m_unNPhones++; } return hr; } ////////////////////////////////////////////////////////////////////// // CPhoneContext // // SearchPhoneTag // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CPhoneContext::SearchPhoneTag(IPromptEntry *pIPE, const WCHAR **result, CONTEXT_PHONE_TAG phoneTag) { HRESULT hr = S_OK; WCHAR* ptr = NULL; USHORT nTags = 0; const WCHAR* tag = L""; int i = 0; SPDBG_ASSERT (result); switch ( phoneTag.iPhoneTag ) { case START_TAG: hr = pIPE->GetStartPhone( result ); break; case END_TAG: hr = pIPE->GetEndPhone( result ); break; case RIGHT_TAG: hr = pIPE->GetRightContext( result ); break; case LEFT_TAG: hr = pIPE->GetLeftContext( result ); break; default: *result = NULL; break; } return hr; } ////////////////////////////////////////////////////////////////////// // CPhoneContext // // ApplyPhoneticRule // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CPhoneContext::ApplyPhoneticRule(const WCHAR *pszPhone, const WCHAR *pszContext, double *cost) { HRESULT hr = S_OK; CContextRule* rule = NULL; bool fDone = false; WCHAR* phnNextRule = NULL; WCHAR* cntxtNextRule = NULL; SPDBG_ASSERT (cost); if ( SUCCEEDED(hr) ) { hr = FindContextRule (L"MAIN", &rule); } if ( SUCCEEDED(hr) ) { // cost initialized to no match at all hr = GetWeight (rule, L"NONE", cost); } if ( !pszPhone || !pszContext ) { fDone = true; } if ( SUCCEEDED(hr) && !fDone ) { // First try if they are the same if (wcscmp (pszPhone, pszContext) == 0) { hr = GetWeight (rule, L"ALL", cost); fDone = true; } } if ( SUCCEEDED(hr) && !fDone ) { // Now iterate over the rules do { if ( SUCCEEDED(hr) && !fDone ) { hr = ApplyRule (rule, pszPhone, &phnNextRule); } if ( SUCCEEDED(hr) && !fDone ) { hr = ApplyRule (rule, pszContext, &cntxtNextRule); } if ( SUCCEEDED(hr) && !fDone && phnNextRule && cntxtNextRule ) { // if the two phones are both in the same next rule, continue. Otherwise, done. if ( phnNextRule && cntxtNextRule && wcscmp(phnNextRule, cntxtNextRule) ) { fDone = true; } } if ( SUCCEEDED(hr) && !fDone && phnNextRule && cntxtNextRule ) { // They are the same, get the cost for the next iteration hr = GetWeight (rule, phnNextRule, cost); } if ( SUCCEEDED(hr) && !fDone && phnNextRule && cntxtNextRule ) { // And the next rule to apply hr = FindContextRule (phnNextRule, &rule); if ( FAILED(hr) ) { fDone = true; hr = S_OK; } } } while ( !fDone && rule && phnNextRule && cntxtNextRule); } return hr; } ////////////////////////////////////////////////////////////////////// // CPhoneContext // // FindContextRule // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CPhoneContext::FindContextRule(const WCHAR *pszName, CContextRule** ppRule) { HRESULT hr = E_FAIL; USHORT i = 0; SPDBG_ASSERT(pszName); for (i=0; i< m_ulNRules; i++) { if ( wcscmp (m_ppContextRules[i]->m_pszRuleName, pszName) == 0 ) { *ppRule = m_ppContextRules[i]; hr = S_OK; break; } } return hr; } ////////////////////////////////////////////////////////////////////// // CPhoneContext // // ApplyRule // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CPhoneContext::ApplyRule(const CContextRule *pRule, const WCHAR *pszPhone, WCHAR** ppszNextRule) { HRESULT hr = S_FALSE; USHORT i = 0; USHORT j = 0; SPDBG_ASSERT (pRule); SPDBG_ASSERT (pszPhone); *ppszNextRule = NULL; for ( i=0; i < pRule->m_unNPhoneClasses; i++ ) { for ( j=0; j < pRule->m_pvPhoneClasses[i]->m_unNPhones; j++ ) { if ( wcscmp( pszPhone, pRule->m_pvPhoneClasses[i]->m_pppszPhones[j] ) == 0 ) { *ppszNextRule = pRule->m_pvPhoneClasses[i]->m_pszPhoneClassName; hr = S_OK; break; } } if ( hr == S_OK ) { break; } } return hr; } ////////////////////////////////////////////////////////////////////// // CPhoneContext // // GetWeight // /////////////////////////////////////////////////////// JOEM 3-2000 // HRESULT CPhoneContext::GetWeight(const CContextRule *pRule, const WCHAR *pszName, double *pdCost) { HRESULT hr = E_FAIL; USHORT i = 0; SPDBG_ASSERT (pRule); SPDBG_ASSERT (pszName); SPDBG_ASSERT (pdCost); for (i=0; i < pRule->m_unNPhoneClasses; i++) { if ( wcscmp(pRule->m_pvPhoneClasses[i]->m_pszPhoneClassName, pszName) == 0 ) { *pdCost = pRule->m_pvPhoneClasses[i]->m_dWeight; hr = S_OK; break; } } return hr; } ////////////////////////////////////////////////////////////////////// // CPhoneContext // // DeletePhoneClass // /////////////////////////////////////////////////////// JOEM 3-2000 // void CPhoneContext::DeletePhoneClass(CPhoneClass *pClass) { if (pClass) { if (pClass->m_pszPhoneClassName) { free (pClass->m_pszPhoneClassName); } if (pClass->m_pppszPhones) { int i; for (i=0; im_unNPhones; i++) { free (pClass->m_pppszPhones[i]); } free (pClass->m_pppszPhones); } free (pClass); } } ////////////////////////////////////////////////////////////////////// // CPhoneContext // // DeleteContextRule // /////////////////////////////////////////////////////// JOEM 3-2000 // void CPhoneContext::DeleteContextRule(CContextRule *pRule) { if (pRule) { if (pRule->m_pszRuleName) { free (pRule->m_pszRuleName); } if (pRule->m_pvPhoneClasses) { int i; for (i=0; im_unNPhoneClasses; i++) { DeletePhoneClass (pRule->m_pvPhoneClasses[i]); } free (pRule->m_pvPhoneClasses); } free (pRule); } } ////////////////////////////////////////////////////////////////////// // CPhoneContext // // DebugPhoneContext // // Function for debug help - just outputs the entire CPhoneContext // class. // /////////////////////////////////////////////////////// JOEM 3-2000 // void CPhoneContext::DebugContextClass() { USHORT i = 0; USHORT j = 0; USHORT k = 0; WCHAR* RuleName = NULL; WCHAR* PhoneClassName = NULL; WCHAR* Phone = NULL; ULONG NumRules = 0; USHORT NumPhoneClasses = 0; USHORT NumPhones = 0; USHORT RuleCount = 0; USHORT PCCount = 0; USHORT PhoneCount = 0; double Weight = 0.0; WCHAR DebugStr[128]; // Print out each rule for (i=0; im_pszRuleName; swprintf (DebugStr, L"Rule: %s, (%d of %d)\n", RuleName, RuleCount, NumRules); OutputDebugStringW(DebugStr); // Within each rule, print out the phone classes for (j=0; jm_unNPhoneClasses; j++) { PCCount = j+1; NumPhoneClasses = m_ppContextRules[i]->m_unNPhoneClasses; PhoneClassName = m_ppContextRules[i]->m_pvPhoneClasses[j]->m_pszPhoneClassName; Weight = m_ppContextRules[i]->m_pvPhoneClasses[j]->m_dWeight; swprintf (DebugStr, L"\tPhoneClass: %s, (%d of %d) ... weight=%f\n", PhoneClassName, PCCount, NumPhoneClasses, Weight); OutputDebugStringW(DebugStr); // Within each phone class, print out the phones for (k=0; km_pvPhoneClasses[j]->m_unNPhones; k++) { PhoneCount = k+1; NumPhones = m_ppContextRules[i]->m_pvPhoneClasses[j]->m_unNPhones; Phone = m_ppContextRules[i]->m_pvPhoneClasses[j]->m_pppszPhones[k]; swprintf (DebugStr, L"\t\tPhone: %s, (%d of %d)\n", Phone, PhoneCount, NumPhones); OutputDebugStringW(DebugStr); } } } } HRESULT CPhoneContext::LoadDefault() { HRESULT hr = S_OK; USHORT i = 0; USHORT j = 0; Macro* macros = NULL; USHORT nMacros = 0; WCHAR* pText = NULL; WCHAR* ptr = NULL; // Load the macros for ( i=0; i < g_nMacros; i++ ) { pText = wcsdup(g_macros[i]); if ( !pText ) { hr = E_OUTOFMEMORY; } else { hr = ReadMacro (pText, ¯os, &nMacros); free(pText); pText = NULL; } } // Load the rules for ( i=0; i < g_nRules && SUCCEEDED(hr); i++ ) { hr = CreateRule(g_rules[i].name); if ( SUCCEEDED(hr) ) { j=0; while ( SUCCEEDED(hr) && g_rules[i].rule[j] ) { if ( SUCCEEDED(hr) ) { pText = wcsdup(g_rules[i].rule[j]); if ( !pText ) { hr = E_OUTOFMEMORY; } else { ptr = pText; hr = ParsePhoneClass (macros, nMacros, m_ppContextRules[m_ulNRules-1], &ptr); free(pText); pText = NULL; } } j++; } } } if (macros) { free(macros); } //DebugContextClass(); return hr; }