954 lines
23 KiB
C++
954 lines
23 KiB
C++
|
//////////////////////////////////////////////////////////////////////
|
||
|
// 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 <stdio.h>
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// 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; i<m_ulNRules; i++)
|
||
|
{
|
||
|
DeleteContextRule( m_ppContextRules[i] );
|
||
|
}
|
||
|
free (m_ppContextRules);
|
||
|
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// CPhoneContext::Load
|
||
|
//
|
||
|
// Reads in the phone context file.
|
||
|
//
|
||
|
/////////////////////////////////////////////////////// JOEM 3-2000 //
|
||
|
HRESULT CPhoneContext::Load(const WCHAR *pszPathName)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
FILE* fp = NULL;
|
||
|
WCHAR line[256] = L"";
|
||
|
WCHAR* ptr = NULL;
|
||
|
Macro* macros = NULL;
|
||
|
USHORT nMacros = 0;
|
||
|
USHORT state = 0;
|
||
|
|
||
|
SPDBG_ASSERT (pszPathName);
|
||
|
|
||
|
if ((fp = _wfopen(pszPathName, L"r")) == NULL)
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
|
||
|
state = 0;
|
||
|
while ( SUCCEEDED(hr) && fgetws (line, sizeof(line), fp) )
|
||
|
{
|
||
|
// Strip off the newline character
|
||
|
if (line[wcslen(line)-1] == L'\n')
|
||
|
{
|
||
|
line[wcslen(line)-1] = L'\0';
|
||
|
}
|
||
|
// Line ends when a comment marker is found
|
||
|
if ( (ptr = wcschr (line, L'#')) != NULL )
|
||
|
{
|
||
|
*ptr = L'\0';
|
||
|
}
|
||
|
|
||
|
ptr = line;
|
||
|
WSkipWhiteSpace (ptr);
|
||
|
if (!*ptr)
|
||
|
{
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// Could be a macro
|
||
|
if (*ptr == L'%')
|
||
|
{
|
||
|
hr = ReadMacro (ptr, ¯os, &nMacros);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// It's not a macro, must be a rule
|
||
|
while ( SUCCEEDED(hr) && *ptr )
|
||
|
{
|
||
|
switch (state) {
|
||
|
case 0:
|
||
|
{
|
||
|
WCHAR* end;
|
||
|
|
||
|
end = ptr;
|
||
|
WSkipNonWhiteSpace(end);
|
||
|
*end++ = L'\0';
|
||
|
state = 1;
|
||
|
|
||
|
hr = CreateRule (ptr);
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
ptr = end;
|
||
|
WSkipWhiteSpace (ptr);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 1:
|
||
|
if (*ptr == L'{')
|
||
|
{
|
||
|
ptr++;
|
||
|
WSkipWhiteSpace(ptr);
|
||
|
state = 2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
break;
|
||
|
case 2:
|
||
|
// We are in a rule, load several phoneClasses
|
||
|
if (*ptr == L'}')
|
||
|
{
|
||
|
state = 0;
|
||
|
ptr++;
|
||
|
WSkipWhiteSpace (ptr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = ParsePhoneClass (macros, nMacros, m_ppContextRules[m_ulNRules-1], &ptr);
|
||
|
}
|
||
|
break;
|
||
|
default:
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
} // while (*ptr)
|
||
|
} // else (Not a macro)
|
||
|
} // while ( SUCCEEDED(hr) && fgetws ...
|
||
|
|
||
|
if (fp)
|
||
|
{
|
||
|
fclose(fp);
|
||
|
}
|
||
|
|
||
|
if (macros)
|
||
|
{
|
||
|
free(macros);
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// CPhoneContext::Apply
|
||
|
//
|
||
|
// Applies phone context rules to determine transition cost between
|
||
|
// the previous and current entry.
|
||
|
//
|
||
|
/////////////////////////////////////////////////////// JOEM 3-2000 //
|
||
|
HRESULT CPhoneContext::Apply(IPromptEntry *pPreviousIPE, IPromptEntry *pCurrentIPE, double *pdCost)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
double partialCost = 0;
|
||
|
|
||
|
const WCHAR* prevPhone = NULL;
|
||
|
const WCHAR* prevContext = NULL;
|
||
|
const WCHAR* curPhone = NULL;
|
||
|
const WCHAR* curContext = NULL;
|
||
|
|
||
|
SPDBG_ASSERT (pPreviousIPE);
|
||
|
SPDBG_ASSERT (pCurrentIPE);
|
||
|
SPDBG_ASSERT (pdCost);
|
||
|
|
||
|
*pdCost = 0.0;
|
||
|
|
||
|
// Should these two partial costs have the same weight?
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
hr = SearchPhoneTag (pPreviousIPE, &prevPhone, g_Phone_Tags[END_TAG]);
|
||
|
}
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
hr = SearchPhoneTag (pCurrentIPE, &curContext, g_Phone_Tags[LEFT_TAG]);
|
||
|
}
|
||
|
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
hr = ApplyPhoneticRule (prevPhone, curContext, &partialCost);
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
*pdCost += partialCost;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
hr = SearchPhoneTag (pPreviousIPE, &prevContext, g_Phone_Tags[RIGHT_TAG]);
|
||
|
}
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
SearchPhoneTag (pCurrentIPE, &curPhone, g_Phone_Tags[START_TAG]);
|
||
|
}
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
hr = ApplyPhoneticRule (curPhone, prevContext, &partialCost);
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
*pdCost += partialCost;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// CPhoneContext::ReadMacro
|
||
|
//
|
||
|
// Helper function to read in a macro from the Phone context file.
|
||
|
//
|
||
|
/////////////////////////////////////////////////////// JOEM 3-2000 //
|
||
|
HRESULT CPhoneContext::ReadMacro(const WCHAR *pszText, Macro **ppMacros, USHORT *punMacros)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
SPDBG_ASSERT(pszText);
|
||
|
SPDBG_ASSERT(ppMacros);
|
||
|
SPDBG_ASSERT(punMacros);
|
||
|
|
||
|
if (*ppMacros)
|
||
|
{
|
||
|
*ppMacros = (Macro*) realloc (*ppMacros, (*punMacros + 1) * sizeof (**ppMacros));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*ppMacros = (Macro*) malloc (sizeof (**ppMacros));
|
||
|
}
|
||
|
|
||
|
if (*ppMacros == NULL)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
if (swscanf (pszText, L"%%%32s %lf", (*ppMacros)[*punMacros].name, &(*ppMacros)[*punMacros].value) != 2)
|
||
|
{
|
||
|
hr = E_FAIL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
(*punMacros)++;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// CPhoneContext::CreateRule
|
||
|
//
|
||
|
// Helper function to read in a macro from the Phone context file.
|
||
|
//
|
||
|
/////////////////////////////////////////////////////// JOEM 3-2000 //
|
||
|
HRESULT CPhoneContext::CreateRule(const WCHAR *pszText)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
CContextRule* newRule = NULL;
|
||
|
SPDBG_ASSERT (pszText);
|
||
|
|
||
|
if (m_ppContextRules)
|
||
|
{
|
||
|
m_ppContextRules = (CContextRule**) realloc (m_ppContextRules, (m_ulNRules + 1) * sizeof(*m_ppContextRules));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_ppContextRules = (CContextRule**) malloc (sizeof(*m_ppContextRules));
|
||
|
}
|
||
|
|
||
|
if (!m_ppContextRules)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
if ((newRule = (CContextRule*) calloc (1, sizeof(*newRule))) == NULL)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
if ( (newRule->m_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; i<unMacros; i++)
|
||
|
{
|
||
|
if (wcsncmp (ptr, pMacros[i].name, wcslen(pMacros[i].name)) == 0)
|
||
|
{
|
||
|
pRule->m_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; i<pClass->m_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; i<pRule->m_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; i<m_ulNRules; i++)
|
||
|
{
|
||
|
RuleCount = i+1;
|
||
|
NumRules = m_ulNRules;
|
||
|
RuleName = m_ppContextRules[i]->m_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; j<m_ppContextRules[i]->m_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; k<m_ppContextRules[i]->m_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;
|
||
|
}
|