windows-nt/Source/XPSP1/NT/enduser/speech/sapi/sapi/cfggrammar.cpp
2020-09-26 16:20:57 +08:00

1702 lines
54 KiB
C++

/*******************************************************************************
* CFGGrammar.cpp *
*--------------*
* Description:
*-------------------------------------------------------------------------------
* Created By: RAL
* Copyright (C) 1998, 1999 Microsoft Corporation
* All Rights Reserved
*******************************************************************************/
#include "stdafx.h"
#include "CFGEngine.h"
#include "CFGGrammar.h"
/////////////////////////////////////////////////////////////////////////////
//
/****************************************************************************
* CBaseGrammar::CBaseGrammar *
*----------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
CBaseGrammar::CBaseGrammar()
{
SPDBG_FUNC("CBaseGrammar::CBaseGrammar");
m_LoadedType = Uninitialized;
m_InLoadType = Uninitialized;
m_eGrammarState = SPGS_ENABLED;
m_hFile = INVALID_HANDLE_VALUE;
m_hMapFile = NULL;
m_pData = NULL; // If this is non-null then if m_hFile != INVALID_HANDLE_VALUE then we allocated the memory
memset(&m_clsidGrammar, 0, sizeof(m_clsidGrammar));
m_hInstanceModule = NULL;
}
/****************************************************************************
* CBaseGrammar::~CBaseGrammar *
*-----------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
CBaseGrammar::~CBaseGrammar()
{
Clear();
}
/****************************************************************************
* CBaseGrammar::Clear *
*---------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
void CBaseGrammar::Clear()
{
SPDBG_FUNC("CBaseGrammar::Clear");
if (m_LoadedType == File)
{
::UnmapViewOfFile(m_pData);
::CloseHandle(m_hMapFile);
::CloseHandle(m_hFile);
m_hMapFile = NULL;
m_hFile = INVALID_HANDLE_VALUE;
}
if (m_LoadedType == Memory)
{
delete[] m_pData;
m_pData = NULL;
}
if (m_hInstanceModule)
{
::FreeLibrary(m_hInstanceModule);
m_hInstanceModule = NULL;
}
memset(&m_clsidGrammar, 0, sizeof(m_clsidGrammar));
m_cpInterpreter.Release();
m_LoadedType = Uninitialized;
}
/****************************************************************************
* CBaseGrammar::InitFromMemory *
*------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
HRESULT CBaseGrammar::InitFromMemory(const SPCFGSERIALIZEDHEADER * pSerializedHeader, const WCHAR *pszGrammarName)
{
SPDBG_FUNC("CBaseGrammar::InitFromMemory");
HRESULT hr = S_OK;
SPDBG_ASSERT(m_LoadedType == Uninitialized);
ULONG cb = pSerializedHeader->ulTotalSerializedSize;
m_dstrGrammarName = pszGrammarName;
m_pData = new BYTE[cb];
if (m_pData)
{
memcpy(m_pData, pSerializedHeader, cb);
m_LoadedType = Memory;
hr = CompleteLoad();
if (FAILED(hr))
{
m_LoadedType = Uninitialized;
delete [] m_pData;
m_pData = NULL;
}
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
/****************************************************************************
* CBaseGrammar::InitFromFile *
*----------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
HRESULT CBaseGrammar::InitFromFile(const WCHAR * pszGrammarName)
{
SPDBG_FUNC("CBaseGrammar::InitFromFile");
HRESULT hr = S_OK;
SPDBG_ASSERT(m_LoadedType == Uninitialized);
m_LoadedType = File; // Assume it will work!
#ifdef _WIN32_WCE
m_hFile = g_Unicode.CreateFileForMapping(pszGrammarName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#else
m_hFile = g_Unicode.CreateFile(pszGrammarName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
#endif
if (m_hFile != INVALID_HANDLE_VALUE)
{
m_hMapFile = ::CreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (m_hMapFile)
{
m_pData = (BYTE *)::MapViewOfFile(m_hMapFile, FILE_MAP_READ, 0, 0, 0);
}
}
if (m_pData == NULL)
{
hr = SpHrFromLastWin32Error();
}
else
{
m_dstrGrammarName.Append2(L"file://", pszGrammarName);
if (m_dstrGrammarName == NULL)
{
hr = E_OUTOFMEMORY;
}
else
{
hr = CompleteLoad();
}
}
if (FAILED(hr))
{
m_LoadedType = Uninitialized;
m_dstrGrammarName.Clear();
if (m_pData)
{
::UnmapViewOfFile(m_pData);
m_pData = NULL;
}
if (m_hMapFile)
{
::CloseHandle(m_hMapFile);
m_hMapFile = NULL;
}
if (m_hFile != INVALID_HANDLE_VALUE)
{
::CloseHandle(m_hFile);
m_hFile = INVALID_HANDLE_VALUE;
}
}
return hr;
}
/****************************************************************************
* CBaseGrammar::InitFromResource *
*-------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
HRESULT CBaseGrammar::InitFromResource(const WCHAR * pszModuleName,
const WCHAR * pszResourceName,
const WCHAR * pszResourceType,
WORD wLanguage)
{
SPDBG_FUNC("CBaseGrammar::InitFromResource");
HRESULT hr = S_OK;
m_LoadedType = Resource;
m_wResLanguage = wLanguage;
#ifdef _WIN32_WCE
// CAUTION!!!
// Dont use LoadLibraryEx on WinCE. It compiles and links on Cedar but ends up corrupting the stack
m_hInstanceModule = g_Unicode.LoadLibrary(pszModuleName);
#else
m_hInstanceModule = g_Unicode.LoadLibraryEx(pszModuleName, NULL, LOAD_LIBRARY_AS_DATAFILE);
#endif
if (m_hInstanceModule)
{
m_dstrModuleName = pszModuleName;
#ifdef _WIN32_WCE
// FindResourceEx is not supported in CE. So just use FindResource. That means in the module
// the resources have to be uniquely named across LCIDs.
HRSRC hResInfo = g_Unicode.FindResource(m_hInstanceModule, pszResourceName, pszResourceType);
#else
HRSRC hResInfo = g_Unicode.FindResourceEx(m_hInstanceModule, pszResourceType, pszResourceName, wLanguage);
#endif
if (hResInfo)
{
WCHAR temp[16];
m_dstrGrammarName.Append2(L"res://", pszModuleName);
if (HIWORD(pszResourceType))
{
m_dstrGrammarName.Append2(L"/", pszResourceType);
m_dstrResourceType = pszResourceType;
m_ResIdType = 0;
}
else
{
m_ResIdType = LOWORD(pszResourceType);
swprintf(temp, L"/%i", m_ResIdType);
m_dstrGrammarName.Append(temp);
}
if (HIWORD(pszResourceName))
{
m_dstrGrammarName.Append2(L"#", pszResourceName);
m_ResIdName = 0;
}
else
{
m_ResIdName = LOWORD(pszResourceName);
swprintf(temp, L"#%i", m_ResIdName);
m_dstrGrammarName.Append(temp);
}
HGLOBAL hData = ::LoadResource(m_hInstanceModule, hResInfo);
if (hData)
{
m_pData = (BYTE *)::LockResource(hData);
}
}
}
if (m_pData == NULL)
{
hr = SpHrFromLastWin32Error();
}
else
{
hr = CompleteLoad();
}
if (FAILED(hr))
{
m_LoadedType = Uninitialized;
if (m_hInstanceModule)
{
::FreeLibrary(m_hInstanceModule);
m_hInstanceModule = NULL;
}
}
return hr;
}
/****************************************************************************
* CBaseGrammar::InitFromCLSID *
*-----------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
HRESULT CBaseGrammar::InitFromCLSID(REFCLSID rcid, const WCHAR * pszGrammarName)
{
SPDBG_FUNC("CBaseGrammar::InitFromCLSID");
HRESULT hr = S_OK;
hr = m_cpInterpreter.CoCreateInstance(rcid);
if (SUCCEEDED(hr))
{
hr = m_cpInterpreter->InitGrammar(pszGrammarName, (const void **)&m_pData);
}
if (SUCCEEDED(hr) && pszGrammarName)
{
m_dstrGrammarName = pszGrammarName;
if (m_dstrGrammarName == NULL)
{
hr = E_OUTOFMEMORY;
}
}
if (SUCCEEDED(hr))
{
m_InLoadType = Object;
hr = CompleteLoad();
}
if (SUCCEEDED(hr))
{
m_LoadedType = Object;
}
else
{
m_cpInterpreter.Release();
}
return hr;
}
/////////////////////////////////////////////////////////////////////////////
//
/****************************************************************************
* CCFGGrammar::FinalConstruct *
*-----------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
HRESULT CCFGGrammar::FinalConstruct()
{
SPDBG_FUNC("CCFGGrammar::FinalConstruct");
HRESULT hr = S_OK;
m_pReplacementData = NULL;
m_pEngine = NULL;
m_pRuleTable = NULL;
m_cNonImportRules = 0;
m_cTopLevelRules = 0;
m_fLoading = false;
m_ulDictationTags = 0;
m_IndexToWordHandle = NULL;
m_pvOwnerCookie = NULL;
m_pvClientCookie = NULL;
memset( &m_Header, 0, sizeof( m_Header ) );
return hr;
}
/****************************************************************************
* CCFGGrammar::BasicInit *
*------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
void CCFGGrammar::BasicInit(ULONG ulGrammarID, CCFGEngine * pEngine)
{
SPDBG_FUNC("CCFGGrammar::BasicInit");
m_ulGrammarID = ulGrammarID;
m_pEngine = pEngine;
m_pEngine->AddRef();
}
/****************************************************************************
* CCFGGrammar::FinalRelease *
*---------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
void CCFGGrammar::FinalRelease()
{
SPDBG_FUNC("CCFGGrammar::FinalRelease");
// tell CFGEngine to remove words from this grammar
if (m_pRuleTable)
{
for (ULONG i = 0; i < m_Header.cRules; i++)
{
if (m_pRuleTable[i].fEngineActive)
{
m_pEngine->DeactivateRule(m_ulGrammarID, i);
m_pRuleTable[i].fEngineActive = FALSE;
}
}
}
if (m_pEngine)
{
if (m_LoadedType != Uninitialized)
{
m_pEngine->RemoveRules(this);
m_pEngine->RemoveWords(this);
}
m_pEngine->RemoveGrammar(m_ulGrammarID);
m_pEngine->Release();
}
if (m_pRuleTable)
{
for (ULONG i = 0; i < m_Header.cRules; i++)
{
if (m_pRuleTable[i].pRefGrammar && m_pRuleTable[i].pRefGrammar != this)
{
m_pRuleTable[i].pRefGrammar->Release();
}
}
delete[] m_pRuleTable;
}
if (m_IndexToWordHandle)
{
delete[] m_IndexToWordHandle;
}
if (m_pReplacementData)
{
delete[] m_pReplacementData;
}
}
/****************************************************************************
* CCFGGrammar::CompleteLoad *
*---------------------------*
* Description:
* NOTE: This function assumes that the m_LoadedType is set by the caller
*
* Returns:
*
********************************************************************* RAL ***/
HRESULT CCFGGrammar::CompleteLoad()
{
SPDBG_FUNC("CCFGGrammar::CompleteLoad");
HRESULT hr = S_OK;
m_fLoading = true;
m_pEngine->m_cLoadsInProgress++;
//
// If the m_cpInterpreter is NULL then just set it to the engine. If we're being
// loaded from an object, it will already be set.
//
if (!m_cpInterpreter)
{
m_cpInterpreter = m_pEngine;
}
hr = SpConvertCFGHeader((SPCFGSERIALIZEDHEADER *)m_pData, &m_Header);
if (SUCCEEDED(hr))
{
//
// Now see if the language ID matches the supported languages.
// We would like to set the langid of the words to be what they
// are in the grammar (pGrammar->m_Header.LangID), but WordStringBlob can't
// handle words with different langids.
// So if multiple grammars get loaded we will fail if the langids are inconsistent.
// If the langids match on primary language and the engine has specified it can
// handle all secondary languages then we will succeed and tell the engine that
// all words have the same langid as the first grammar loaded.
if(m_pEngine->m_CurLangID)
{
// Already specified a current language
if(m_Header.LangID != m_pEngine->m_CurLangID)
{
// New grammar id is different - see if there is a conflict
hr = SPERR_LANGID_MISMATCH;
for (ULONG i = 0; SPERR_LANGID_MISMATCH == hr && i < m_pEngine->m_cLangIDs; i++)
{
if (PRIMARYLANGID(m_pEngine->m_aLangIDs[i]) == PRIMARYLANGID(m_Header.LangID) &&
PRIMARYLANGID(m_pEngine->m_aLangIDs[i]) == PRIMARYLANGID(m_pEngine->m_CurLangID) &&
SUBLANGID(m_pEngine->m_aLangIDs[i]) == SUBLANG_NEUTRAL)
{
hr = S_OK;
}
}
}
}
else
{
// No language currently specified
if (m_pEngine->m_cLangIDs == 0)
{
// Engine didn't list any supported languages. Always succeed.
m_pEngine->m_CurLangID = m_Header.LangID;
}
else
{
// See if there is an exact match
hr = SPERR_LANGID_MISMATCH;
for (ULONG i = 0; SPERR_LANGID_MISMATCH == hr && i < m_pEngine->m_cLangIDs; i++)
{
if (m_pEngine->m_aLangIDs[i] == m_Header.LangID)
{
m_pEngine->m_CurLangID = m_Header.LangID;
hr = S_OK;
}
}
// Else see if there is a 'fuzzy' match based on primary id
LANGID LangEngine = 0;
bool fPrimaryMatch = false;
for (ULONG i = 0; SPERR_LANGID_MISMATCH == hr && i < m_pEngine->m_cLangIDs; i++)
{
if (PRIMARYLANGID(m_pEngine->m_aLangIDs[i]) == PRIMARYLANGID(m_Header.LangID))
{
if (SUBLANGID(m_pEngine->m_aLangIDs[i]) == SUBLANG_NEUTRAL)
{
fPrimaryMatch = true;
}
else
{
if(!LangEngine)
{
LangEngine = m_pEngine->m_aLangIDs[i];
}
}
if(fPrimaryMatch && LangEngine)
{
m_pEngine->m_CurLangID = LangEngine;
hr = S_OK;
}
}
}
}
}
if (SUCCEEDED(hr))
{
hr = AllocateArray(&m_pRuleTable, m_Header.cRules);
}
if (SUCCEEDED(hr))
{
//
// Deal with imports
//
for (ULONG i = 0; SUCCEEDED(hr) && i < m_Header.cRules; i++)
{
if (m_Header.pRules[i].fImport)
{
hr = ImportRule(i);
}
else
{
m_pRuleTable[i].pRefGrammar = this;
m_pRuleTable[i].ulGrammarRuleIndex = i;
m_pRuleTable[i].fDynamic = m_Header.pRules[i].fDynamic;
m_pRuleTable[i].fEngineActive = FALSE; // NOT m_Header.pRules[i].fDefaultActive -- use CComPtr<ISpCFGGrammar>::ActivateRule(NULL, SPRIF_ACTIVATE);
m_pRuleTable[i].fAppActive = FALSE;
m_pRuleTable[i].fAutoPause = FALSE;
m_pRuleTable[i].pvClientContext = NULL;
m_pRuleTable[i].eCacheStatus = CACHE_VOID;
m_pRuleTable[i].pFirstList = NULL;
}
}
//
// In the case of failure, DO NOT free the m_pRuleTable, let the cleanup
// code in FinalRelease() do it. It will release references to
//
}
if (SUCCEEDED(hr))
{
m_ulDictationTags = 0;
for(ULONG nArc = 0; nArc < m_Header.cArcs; nArc++)
{
if (m_Header.pArcs[nArc].TransitionIndex == SPDICTATIONTRANSITION)
{
m_ulDictationTags++;
}
}
}
}
m_fLoading = false;
m_pEngine->m_cLoadsInProgress--;
if (SUCCEEDED(hr))
{
hr = m_pEngine->AddWords(this, 0, 0);
}
if (SUCCEEDED(hr))
{
hr = m_pEngine->AddRules(this, 0);
if (FAILED(hr))
{
m_pEngine->RemoveWords(this); // ignore HRESULT since we already have a failure!
}
}
return hr;
}
/****************************************************************************
* CCFGGrammar::_FindRuleIndexByID *
*---------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAP ***/
HRESULT CCFGGrammar::_FindRuleIndexByID(DWORD dwRuleId, ULONG *pulRuleIndex)
{
SPDBG_ASSERT(pulRuleIndex);
for (ULONG i = 0; i < m_Header.cRules; i++)
{
const SPCFGRULE * pRule = m_Header.pRules + i;
if (pRule->RuleId == dwRuleId)
{
*pulRuleIndex = i;
return S_OK;
}
}
return S_FALSE;
}
/****************************************************************************
* CCFGGrammar::_FindRuleIndexByName *
*-----------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAP ***/
HRESULT CCFGGrammar::_FindRuleIndexByName(const WCHAR * pszRuleName, ULONG *pulRuleIndex)
{
SPDBG_ASSERT(pulRuleIndex);
for (ULONG i = 0; i < m_Header.cRules; i++)
{
const SPCFGRULE * pRule = m_Header.pRules + i;
if (_wcsicmp(pszRuleName, &m_Header.pszSymbols[pRule->NameSymbolOffset]) == 0)
{
*pulRuleIndex = i;
return S_OK;
}
}
return S_FALSE;
}
/****************************************************************************
* CCFGGrammar::_FindRuleIndexByNameAndID *
*----------------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAP ***/
HRESULT CCFGGrammar::_FindRuleIndexByNameAndID( const WCHAR * pszRuleName, DWORD dwRuleId, ULONG * pulRuleIndex )
{
SPDBG_ASSERT( pulRuleIndex );
HRESULT hr = S_OK;
ULONG ulName;
ULONG ulID;
if (S_OK != _FindRuleIndexByName( pszRuleName, &ulName ) ||
S_OK != _FindRuleIndexByID( dwRuleId, &ulID ) ||
ulName != ulID )
{
hr = SPERR_RULE_NAME_ID_CONFLICT;
}
else
{
*pulRuleIndex = ulName;
}
return hr;
}
/****************************************************************************
* CCFGGrammar::ActivateRule *
*---------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAP ***/
STDMETHODIMP CCFGGrammar::ActivateRule(const WCHAR * pszRuleName, DWORD dwRuleId, SPRULESTATE NewState, ULONG * pulRulesActivated)
{
SPAUTO_OBJ_LOCK;
HRESULT hr = S_OK;
ULONG cnt = 0;
if( NewState == SPRS_INACTIVE )
{
return E_INVALIDARG;
}
if (pszRuleName == NULL && dwRuleId == 0)
{
BOOL fFoundTopLevel = false;
BYTE * pfActivated = STACK_ALLOC_AND_ZERO(BYTE, m_Header.cRules);
const BOOL fAutoPause = (NewState == SPRS_ACTIVE_WITH_AUTO_PAUSE);
for (ULONG i = 0; hr == S_OK && i < m_Header.cRules; i++)
{
const SPCFGRULE * pRule = m_Header.pRules + i;
if (pRule->fTopLevel)
{
fFoundTopLevel = true;
m_pRuleTable[i].fAutoPause = fAutoPause;
if (pRule->fDefaultActive && (!m_pRuleTable[i].fAppActive))
{
if (m_eGrammarState == SPGS_ENABLED)
{
SPDBG_ASSERT(!m_pRuleTable[i].fEngineActive);
hr = m_pEngine->ActivateRule(this, i);
}
if (hr == S_OK)
{
m_pRuleTable[i].fAppActive = TRUE;
cnt++;
pfActivated[i] = true;
}
}
}
}
//
// If we fail for some reason, back out anything we have activated already...
//
if (hr == S_OK)
{
if (!fFoundTopLevel)
{
hr = SPERR_NOT_TOPLEVEL_RULE;
}
}
else
{
// This can only fail in the case where m_eGrammarState == ENABLED since this is the
// only place we call the engine.
SPDBG_ASSERT(m_eGrammarState == SPGS_ENABLED);
for (ULONG j = 0; j < i; j++)
{
if (pfActivated[j])
{
SPDBG_ASSERT(m_pRuleTable[j].fEngineActive);
m_pEngine->DeactivateRule(this->m_ulGrammarID, j);
m_pRuleTable[j].fAppActive = FALSE;
}
}
cnt = 0;
}
}
else
{
ULONG ulRuleIndex;
if( pszRuleName && SP_IS_BAD_STRING_PTR( pszRuleName ) )
{
hr = E_INVALIDARG;
}
else if( dwRuleId && pszRuleName )
{
hr = _FindRuleIndexByNameAndID( pszRuleName, dwRuleId, &ulRuleIndex );
}
else if( pszRuleName )
{
hr = _FindRuleIndexByName(pszRuleName, &ulRuleIndex);
}
else
{
hr = _FindRuleIndexByID(dwRuleId, &ulRuleIndex);
}
if (hr == S_OK)
{
const SPCFGRULE * pRule = m_Header.pRules + ulRuleIndex;
if (pRule->fTopLevel)
{
m_pRuleTable[ulRuleIndex].fAutoPause = (NewState == SPRS_ACTIVE_WITH_AUTO_PAUSE);
if (!m_pRuleTable[ulRuleIndex].fAppActive)
{
if (m_eGrammarState == SPGS_ENABLED)
{
SPDBG_ASSERT(!m_pRuleTable[ulRuleIndex].fEngineActive);
hr = m_pEngine->ActivateRule(this, ulRuleIndex);
}
if (hr == S_OK)
{
m_pRuleTable[ulRuleIndex].fAppActive = TRUE;
cnt++;
}
}
}
else
{
hr = SPERR_NOT_TOPLEVEL_RULE;
}
}
else if (S_FALSE == hr)
{
hr = SPERR_NOT_TOPLEVEL_RULE;
}
}
*pulRulesActivated = cnt;
return hr;
}
/****************************************************************************
* CCFGGrammar::DeactivateRule *
*-----------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAP ***/
STDMETHODIMP CCFGGrammar::DeactivateRule(const WCHAR * pszRuleName, DWORD dwRuleId, ULONG * pulRulesDeactivated)
{
SPAUTO_OBJ_LOCK;
HRESULT hr = S_OK;
ULONG cnt = 0;
if (pszRuleName == NULL && dwRuleId == 0)
{
// deactivate all currently active top level rules
for (ULONG i = 0; i < m_Header.cRules; i++)
{
if (m_Header.pRules[i].fTopLevel && m_pRuleTable[i].fAppActive)
{
cnt++;
m_pRuleTable[i].fAppActive = FALSE;
m_pRuleTable[i].fAutoPause = FALSE;
if (m_pRuleTable[i].fEngineActive)
{
HRESULT hrEngine = m_pEngine->DeactivateRule(m_ulGrammarID, i);
if (hr == S_OK && FAILED(hrEngine))
{
hr = hrEngine;
}
}
}
}
}
else
{
ULONG ulRuleIndex;
if( pszRuleName && SP_IS_BAD_STRING_PTR( pszRuleName ) )
{
hr = E_INVALIDARG;
}
else if( dwRuleId && pszRuleName )
{
hr = _FindRuleIndexByNameAndID( pszRuleName, dwRuleId, &ulRuleIndex );
}
else if( pszRuleName )
{
hr = _FindRuleIndexByName(pszRuleName, &ulRuleIndex);
}
else
{
hr = _FindRuleIndexByID(dwRuleId, &ulRuleIndex);
}
if (hr == S_OK)
{
if (m_Header.pRules[ulRuleIndex].fTopLevel)
{
if (m_pRuleTable[ulRuleIndex].fAppActive)
{
cnt = 1;
m_pRuleTable[ulRuleIndex].fAppActive = FALSE;
m_pRuleTable[ulRuleIndex].fAutoPause = FALSE;
if (m_pRuleTable[ulRuleIndex].fEngineActive)
{
hr = m_pEngine->DeactivateRule(m_ulGrammarID, ulRuleIndex);
}
}
}
else
{
hr = SPERR_NOT_TOPLEVEL_RULE;
}
}
}
*pulRulesDeactivated = cnt;
return hr;
}
/****************************************************************************
* CCFGGrammar::SetGrammarState *
*------------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CCFGGrammar::SetGrammarState(SPGRAMMARSTATE eGrammarState)
{
SPDBG_FUNC("CCFGGrammar::SetGrammarState");
HRESULT hr = S_OK;
if (eGrammarState != m_eGrammarState)
{
ULONG i;
switch (eGrammarState)
{
case SPGS_ENABLED:
// restore state of all rules of this grammar
for (i = 0; i < m_Header.cRules; i++)
{
const SPCFGRULE * pRule = m_Header.pRules + i;
if (pRule->fTopLevel && m_pRuleTable[i].fAppActive)
{
SPDBG_ASSERT(!m_pRuleTable[i].fEngineActive);
hr = m_pEngine->ActivateRule(this, i);
if (FAILED(hr))
{
for (ULONG j = 0; j < i; j++)
{
pRule = m_Header.pRules + j;
if (pRule->fTopLevel && m_pRuleTable[j].fEngineActive)
{
m_pEngine->DeactivateRule(m_ulGrammarID, j);
}
}
break;
}
}
}
if (SUCCEEDED(hr))
{
m_eGrammarState = SPGS_ENABLED;
}
break;
case SPGS_DISABLED:
// send RuleNotify() for each active rule and remember that the rule
// was active before this call
for (i = 0; i < m_Header.cRules; i++)
{
const SPCFGRULE * pRule = m_Header.pRules + i;
if (pRule->fTopLevel && m_pRuleTable[i].fEngineActive)
{
SPDBG_ASSERT(m_pRuleTable[i].fAppActive);
HRESULT hrEngine = m_pEngine->DeactivateRule(m_ulGrammarID, i);
if (hr == S_OK && FAILED(hrEngine))
{
hr = hrEngine;
}
}
}
m_eGrammarState = SPGS_DISABLED;
break;
case SPGS_EXCLUSIVE:
SPDBG_ASSERT(TRUE); // Exclusive grammars are implemented by SrRecoInstGrammar, not CFG Engine...
hr = E_NOTIMPL;
break;
}
}
SPDBG_REPORT_ON_FAIL(hr);
return hr;
}
/****************************************************************************
* CCFGGrammar::ImportRule *
*-------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
HRESULT CCFGGrammar::ImportRule(ULONG ulImportRuleIndex)
{
SPDBG_FUNC("CCFGGrammar::ImportRule");
HRESULT hr = S_OK;
//
// Import names can have two forms: GrammarName\Rule for files or resources OR
// Object\Grammar\Rule for global grammars. Other forms are not allowed.
//
CSpDynamicString dstrName(m_Header.pszSymbols + m_Header.pRules[ulImportRuleIndex].NameSymbolOffset);
CSpDynamicString dstrName2;
ISpCFGGrammar * pComGramInterface = NULL;
WCHAR *pszRuleName;
bool fUseParentDir = false;
if (dstrName)
{
ULONG ulLength = wcslen(dstrName);
// read the protocol
if ((ulLength > 12) && !wcsncmp(dstrName,L"SAPI5OBJECT", 11))
{
if (dstrName[11] != L':')
{
return SPERR_INVALID_IMPORT;
}
// now we expect ProgId.ProgId\\RuleName
WCHAR *pszProgId = dstrName + 12;
pszRuleName = wcsstr(pszProgId,L"\\\\");
if (!pszRuleName || (wcslen(pszRuleName) < 3))
{
return SPERR_INVALID_IMPORT;
}
*pszRuleName = L'\0';
pszRuleName += 2;
CLSID clsid;
if (SUCCEEDED(::CLSIDFromString(pszProgId, &clsid)) ||
SUCCEEDED(::CLSIDFromProgID(pszProgId, &clsid)))
{
hr = m_pEngine->InternalLoadGrammarFromObject(clsid, pszProgId, NULL, NULL, FALSE, &pComGramInterface);
}
else
{
hr = SPERR_INVALID_IMPORT;
}
}
else if ((ulLength > 4) && !wcsncmp(dstrName,L"URL", 3))
{
if (dstrName[3] != L':') // URL:blah
{
return SPERR_INVALID_IMPORT;
}
// now we expect Protocol://protocol specifics \\RuleName
WCHAR *pszUrl = dstrName + 4;
if (pszUrl[0] == 0)
{
return SPERR_INVALID_IMPORT;
}
WCHAR *pszEndProt = wcsstr(pszUrl, L":"); // e.g. file:// - finds ':' if file:// present
if (pszEndProt == (pszUrl + 1)) // c:\ with no file://
{
pszEndProt = NULL;
}
pszRuleName = wcsstr(pszUrl,L"\\\\");
if (pszRuleName == pszUrl || // i.e. \\somename\somedir\somefile\\rulename - found first \\ incorrectly
pszRuleName == (pszEndProt + 3)) // i.e. file://\\somename\somedir\somefile\\rulename - found first \\ incorrectly.
{
pszRuleName = wcsstr(pszRuleName + 2,L"\\\\");
}
if (!pszRuleName || !pszEndProt || (wcslen(pszRuleName) < 3) || (wcslen(pszEndProt ) < 4))
{
// May need to use fully qualified name from parent grammar to get protocol.
fUseParentDir = true;
dstrName2 = m_dstrGrammarName;
pszUrl = dstrName2;
if (!pszUrl)
{
return SPERR_INVALID_IMPORT;
}
pszEndProt = wcsstr(pszUrl, L":");
if (pszEndProt)
{
*pszEndProt = 0;
}
pszEndProt = dstrName + 4;
if (!pszRuleName || !pszEndProt || (wcslen(pszRuleName) < 3) || (wcslen(pszEndProt ) < 4))
{
return SPERR_INVALID_IMPORT;
}
*pszRuleName = L'\0';
pszRuleName += 2;
}
else
{
*pszRuleName = L'\0';
pszRuleName += 2;
*pszEndProt = L'\0';
// wcslen(pszEndProt) before previous line is 4 or more. Not enough. Hence need to explicitly check length again.
if (wcslen(pszEndProt + 1) > 4 && // file://c: as minimum
pszEndProt[4] != L':' && // file://c: format
wcsncmp(&pszEndProt[3], L"\\\\", 2) != 0 &&
(!wcscmp(pszUrl, L"file") || !wcscmp(pszUrl, L"res"))) // file://\\ format
{
// Need to allow for file://computer/dir/grammar.ext here.
// Also res://computer/dir/file/GRAMMAR#ID
// Need to not do http://computer/dir & https / ftp etc.
// Can't skip over //. Need to skip over the nulled : still however.
pszEndProt += 1;
}
else
{
// We have the format "file://c:\..." and can skip over the // happily.
// Or the format file://\\computer\somedir\somefile
// Note pszEndProt points to the : in file://whatever (: has been set to zero).
pszEndProt += 3;
}
// Note the only support formats for file:// are:
// file://X:\dir\name
// file://X:/dir/name
// file://computer/dir/name
// file://computer\dir\name
// file://\\computer\dir\name
// file://\\computer/dir/name
// i.e. file://..\something will not work.
// file://file.cfg will probably work as a side effect. This is unfortunate.
}
// find protocol: if it is file:// then LoadCmdFromFile
// res:// then LoadCmdFromResource
// otherwise use urlmon
if (!wcscmp(pszUrl,L"file"))
{
hr = m_pEngine->InternalLoadGrammarFromFile(pszEndProt, NULL, NULL, FALSE, &pComGramInterface);
if (FAILED(hr) && fUseParentDir && wcsrchr(m_dstrGrammarName + 7, L'\\') !=0 )
{
CSpDynamicString dstr = m_dstrGrammarName + 7;
*(wcsrchr(dstr, L'\\')+1) = 0;
dstr.Append(pszEndProt);
hr = m_pEngine->InternalLoadGrammarFromFile(dstr, NULL, NULL, FALSE, &pComGramInterface);
}
if (FAILED(hr) && fUseParentDir && wcsrchr(m_dstrGrammarName + 7, L'/') !=0 )
{
CSpDynamicString dstr = m_dstrGrammarName + 7;
*(wcsrchr(dstr, L'/')+1) = 0;
dstr.Append(pszEndProt);
hr = m_pEngine->InternalLoadGrammarFromFile(dstr, NULL, NULL, FALSE, &pComGramInterface);
}
}
else if (!wcscmp(pszUrl,L"res"))
{
// the format is res://[resourcedir/]<resource file>[/resource type]#[<resource id> / <resource name>]
// e.g. res://filedir/filename/SRGRAMMAR#134
// e.g. res://filedir/filename/SRGRAMMAR } Equivalent
// e.g. res://filedir/filename/SRGRAMMAR#SRGRAMMAR }
// e.g. res://filedir/filename/SRGRAMMAR#GRAMMAR1 // Named resource rather than ID.
WCHAR *pszResourceType = NULL;
WCHAR *pszResourceId = NULL;
long lResourceId = 0;
WCHAR *pszRes = wcsrchr(pszEndProt, L'/');
if (pszRes)
{
*pszRes = L'\0';
pszRes++;
}
else
{
// Must have trailing /GRAMMARTYPE as a minimum.
// This minimum is equivalent to /GRAMMARTYPE#GRAMMARTYPE
hr = SPERR_INVALID_IMPORT;
}
if (SUCCEEDED(hr))
{
WCHAR *pszHash = wcschr(pszRes,L'#');
if (pszHash)
{
*pszHash = L'\0';
pszHash++;
pszResourceType = pszRes;
pszResourceId = pszHash;
}
else
{
// Must have trailing /GRAMMARTYPE as a minimum.
// This minimum is equivalent to /GRAMMARTYPE#GRAMMARTYPE
pszResourceId = pszRes;
}
if (pszResourceId[0] >= L'0' && pszResourceId[0] <= L'9')
{
// If the #[0-9] assume we have numeric resource id.
// Otherwise we assume we have a named resource.
lResourceId = _wtol(&pszResourceId[0]);
}
}
if (SUCCEEDED(hr) && pszResourceId)
{
hr = m_pEngine->InternalLoadGrammarFromResource(pszEndProt, lResourceId ? MAKEINTRESOURCEW(lResourceId) : pszResourceId,
pszResourceType, MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL), NULL, NULL, FALSE,
&pComGramInterface);
if (FAILED(hr) && fUseParentDir && wcsrchr(m_dstrGrammarName + 6, L'/') !=0 )
{
CSpDynamicString dstr = m_dstrGrammarName + 6;
*(wcsrchr(dstr, L'/')) = 0;
hr = m_pEngine->InternalLoadGrammarFromResource(dstr, lResourceId ? MAKEINTRESOURCEW(lResourceId) : pszResourceId,
pszResourceType, MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL), NULL, NULL, FALSE,
&pComGramInterface);
}
// Don't need to test for L'\\' form as lacking a L'/' means the parent didn't have a correctly specified resource and
// hence we would never get here (or have a valid parent to attempt to use).
}
else
{
hr = SPERR_INVALID_IMPORT;
}
}
else
{
// assume it is another URL protocol that URL Moniker is going to deal with
IStream *pStream;
HRESULT hr1 = S_OK;
char *pBuffer = NULL;
DWORD dwGot;
CSpDynamicString dstrURL;
dstrURL.Append2(pszUrl,L"://");
dstrURL.Append(pszEndProt);
SPCFGSERIALIZEDHEADER SerialHeader;
hr = URLOpenBlockingStreamW( 0, dstrURL, &pStream, 0, 0);
if (FAILED(hr) && fUseParentDir && wcsrchr(m_dstrGrammarName, L'/') !=0 )
{
dstrURL.Clear();
dstrURL = m_dstrGrammarName;
*(wcsrchr(dstrURL, L'/')+1) = 0;
dstrURL.Append(pszEndProt);
hr = URLOpenBlockingStreamW( 0, dstrURL, &pStream, 0, 0);
}
if (FAILED(hr) && fUseParentDir && wcsrchr(m_dstrGrammarName, L'\\') !=0 )
{
dstrURL.Clear();
dstrURL = m_dstrGrammarName;
*(wcsrchr(dstrURL, L'\\')+1) = 0;
dstrURL.Append(pszEndProt);
hr = URLOpenBlockingStreamW( 0, dstrURL, &pStream, 0, 0);
}
if (SUCCEEDED(hr))
{
//
// If the extension of the file is ".xml" then attempt to compile it
//
ULONG cch = wcslen(dstrURL);
if (cch > 4 && _wcsicmp(dstrURL + cch - 4, L".xml") == 0)
{
CComPtr<IStream> cpDestMemStream;
CComPtr<ISpGrammarCompiler> m_cpCompiler;
hr = ::CreateStreamOnHGlobal(NULL, TRUE, &cpDestMemStream);
if (SUCCEEDED(hr))
{
hr = m_cpCompiler.CoCreateInstance(CLSID_SpGrammarCompiler);
}
if (SUCCEEDED(hr))
{
hr = m_cpCompiler->CompileStream(pStream, cpDestMemStream, NULL, NULL, NULL, 0);
}
if (SUCCEEDED(hr))
{
HGLOBAL hGlobal;
hr = ::GetHGlobalFromStream(cpDestMemStream, &hGlobal);
if (SUCCEEDED(hr))
{
#ifndef _WIN32_WCE
SPCFGSERIALIZEDHEADER * pBinaryData = (SPCFGSERIALIZEDHEADER * )::GlobalLock(hGlobal);
#else
SPCFGSERIALIZEDHEADER * pBinaryData = (SPCFGSERIALIZEDHEADER * )GlobalLock(hGlobal);
#endif // _WIN32_WCE
if (pBinaryData)
{
hr = m_pEngine->InternalLoadGrammarFromMemory((const SPCFGSERIALIZEDHEADER*)pBinaryData, NULL, NULL, FALSE, &pComGramInterface, dstrURL);
#ifndef _WIN32_WCE
::GlobalUnlock(hGlobal);
#else
GlobalUnlock(hGlobal);
#endif // _WIN32_WCE
}
}
}
if (FAILED(hr))
{
hr = SPERR_INVALID_IMPORT;
}
}
else
{
hr = pStream->Read( &SerialHeader, sizeof(SerialHeader), &dwGot);
if (SUCCEEDED(hr))
{
if (dwGot == sizeof(SerialHeader))
{
pBuffer = (char*) malloc(SerialHeader.ulTotalSerializedSize*sizeof(char));
if (!pBuffer)
{
hr = E_OUTOFMEMORY;
}
}
else
{
hr = SPERR_INVALID_IMPORT;
}
if (pBuffer)
{
memcpy(pBuffer, &SerialHeader, sizeof(SerialHeader));
hr = pStream->Read(pBuffer+sizeof(SerialHeader), SerialHeader.ulTotalSerializedSize - sizeof(SerialHeader), &dwGot);
}
}
if (SUCCEEDED(hr))
{
hr = m_pEngine->InternalLoadGrammarFromMemory((const SPCFGSERIALIZEDHEADER*)pBuffer, NULL, NULL, FALSE, &pComGramInterface, dstrURL);
free(pBuffer);
}
}
}
}
}
else
{
hr = SPERR_INVALID_IMPORT;
}
}
else
{
hr = E_OUTOFMEMORY;
}
//
// Now we've found the grammar, so find the rule
//
if (SUCCEEDED(hr))
{
hr = SPERR_INVALID_IMPORT; // Assume we won't find it.
CCFGGrammar * pRefGrammar = static_cast<CCFGGrammar *>(pComGramInterface);
for (ULONG i = 0; i < pRefGrammar->m_Header.cRules; i++)
{
if (pRefGrammar->m_Header.pRules[i].fExport &&
_wcsicmp(pszRuleName, pRefGrammar->RuleName(i)) == 0)
{
m_pRuleTable[ulImportRuleIndex].pRefGrammar = pRefGrammar;
m_pRuleTable[ulImportRuleIndex].ulGrammarRuleIndex = i;
m_pRuleTable[ulImportRuleIndex].eCacheStatus = CACHE_VOID;
m_pRuleTable[ulImportRuleIndex].pFirstList = NULL;
hr = S_OK;
break;
}
}
if (FAILED(hr))
{
pRefGrammar->Release();
}
}
#ifdef _DEBUG
if (FAILED(hr))
{
USES_CONVERSION;
SPDBG_DMSG0("Failed to import a rule.\n");
if (m_dstrGrammarName)
{
SPDBG_DMSG1("Importing grammar: %s.\n", W2T(m_dstrGrammarName));
}
CSpDynamicString dstr(m_Header.pszSymbols + m_Header.pRules[ulImportRuleIndex].NameSymbolOffset);
if (dstr)
{
SPDBG_DMSG1("Imported grammar: %s.\n", W2T(dstr));
}
if (pszRuleName)
{
SPDBG_DMSG1("Rule name : %s.\n", W2T(pszRuleName));
}
}
#endif
return hr;
}
/****************************************************************************
* CCFGGrammar::IsEqualResource *
*------------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
BOOL CCFGGrammar::IsEqualResource(const WCHAR * pszModuleName,
const WCHAR * pszResourceName,
const WCHAR * pszResourceType,
WORD wLanguage)
{
SPDBG_FUNC("CCFGGrammar::IsEqualResouce");
if (m_LoadedType != Resource ||
_wcsicmp(pszModuleName, m_dstrModuleName) != 0 ||
wLanguage != m_wResLanguage)
{
return FALSE;
}
if (HIWORD(pszResourceName))
{
if (m_ResIdName || _wcsicmp(pszResourceName, m_dstrGrammarName) != 0)
{
return FALSE;
}
}
else
{
if (LOWORD(pszResourceName) != m_ResIdName)
{
return FALSE;
}
}
if (HIWORD(pszResourceType))
{
if (m_ResIdType || _wcsicmp(pszResourceType, m_dstrResourceType) != 0)
{
return FALSE;
}
}
else
{
if (m_dstrResourceType.m_psz || LOWORD(pszResourceType) != m_ResIdType)
{
return FALSE;
}
}
return TRUE;
}
/****************************************************************************
* CCFGGrammar::IsEqualFile *
*--------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
BOOL CCFGGrammar::IsEqualFile(const WCHAR * pszFileName)
{
return (m_LoadedType == File && (wcscmp(m_dstrGrammarName, pszFileName) == 0));
}
/****************************************************************************
* CCFGGrammar::IsEqualObject *
*----------------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
BOOL CCFGGrammar::IsEqualObject(REFCLSID rcid, const WCHAR * pszGrammarName)
{
return (((m_LoadedType == Object) || (m_InLoadType == Object)) && (wcscmp(m_dstrGrammarName, pszGrammarName) == 0));
}
/****************************************************************************
* CCFGGrammar::InternalReload *
*---------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
HRESULT CCFGGrammar::InternalReload( const SPBINARYGRAMMAR * pBinaryData )
{
SPDBG_FUNC("CCFGGrammar::InternalReload");
HRESULT hr;
ULONG cOldWords = m_Header.cWords;
ULONG cchOldWords = m_Header.cchWords;
ULONG cOldRules = m_Header.cRules;
//
// Load the new header.
//
SPCFGSERIALIZEDHEADER * pSerializedHeader = (SPCFGSERIALIZEDHEADER *) pBinaryData;
ULONG cb = pSerializedHeader->ulTotalSerializedSize;
BYTE * pReplace = new BYTE[cb];
if (pReplace)
{
memcpy(pReplace, pSerializedHeader, cb);
hr = SpConvertCFGHeader((SPCFGSERIALIZEDHEADER *)pReplace, &m_Header);
m_pReplacementData = pReplace;
if (SUCCEEDED(hr) && m_LoadedType == Memory)
{
m_pData = NULL;
}
}
else
{
hr = E_OUTOFMEMORY;
}
// If there are any new words or rules add them
if (SUCCEEDED(hr) && cchOldWords < m_Header.cchWords)
{
hr = m_pEngine->AddWords(this, cOldWords, cchOldWords);
}
// If there are new rules allocate space for them.
if (SUCCEEDED(hr) && cOldRules < m_Header.cRules)
{
hr = CopyAndExpandArray(&m_pRuleTable, cOldRules, &m_pRuleTable, m_Header.cRules);
if (SUCCEEDED(hr))
{
for (ULONG i = cOldRules; i < m_Header.cRules; i++)
{
m_pRuleTable[i].ulGrammarRuleIndex = i;
m_pRuleTable[i].pRefGrammar = this;
m_pRuleTable[i].fEngineActive = FALSE; //pRule->fDefaultActive;
m_pRuleTable[i].fAppActive = FALSE;
m_pRuleTable[i].fAutoPause = FALSE;
m_pRuleTable[i].pvClientContext = NULL;
m_pRuleTable[i].fDynamic = TRUE; // additional rules have to be dynamic in a reload
m_pRuleTable[i].eCacheStatus = CACHE_VOID;
m_pRuleTable[i].pFirstList = NULL;
}
}
}
if (SUCCEEDED(hr))
{
hr = m_pEngine->AddRules(this, cOldRules);
}
// Now invalidate any rules which have changed
if (SUCCEEDED(hr) && m_pEngine->m_pClient && cOldRules)
{
SPRULEENTRY * ahRule = STACK_ALLOC(SPRULEENTRY, cOldRules);
for (ULONG i = 0, cDirtyDynamic = 0; i < cOldRules; i++)
{
if (m_pRuleTable[i].fDynamic && (m_Header.pRules[i].fDirtyRule || (cDirtyDynamic > 0)))
{
ahRule[cDirtyDynamic].hRule = CRuleHandle(this, i);
ahRule[cDirtyDynamic].pvClientRuleContext = m_pRuleTable[i].pvClientContext;
ahRule[cDirtyDynamic].pvClientGrammarContext = this->m_pvClientCookie;
ULONG Attrib = 0;
if (m_Header.pRules[i].fTopLevel)
{
Attrib |= SPRAF_TopLevel;
}
if (m_pRuleTable[i].fEngineActive)
{
Attrib |= SPRAF_Active;
}
if (m_Header.pRules[i].fPropRule)
{
Attrib |= SPRAF_Interpreter;
}
ahRule[cDirtyDynamic].Attributes = Attrib;
cDirtyDynamic++;
}
}
if (cDirtyDynamic> 0)
{
hr = m_pEngine->m_pClient->RuleNotify(SPCFGN_INVALIDATE, cDirtyDynamic, ahRule);
}
}
return hr;
}
/****************************************************************************
* CCFGGrammar::Reload *
*---------------------*
* Description:
*
* Returns:
*
********************************************************************* RAL ***/
STDMETHODIMP CCFGGrammar::Reload(const SPBINARYGRAMMAR *pBinaryData)
{
SPAUTO_OBJ_LOCK;
SPDBG_FUNC("CCFGGrammar::Reload");
HRESULT hr = S_OK;
if( SP_IS_BAD_READ_PTR( pBinaryData ) )
{
return E_INVALIDARG;
}
//
// We need to figure out the differneces between the previous grammar and the
// current one. We only want to add the new words and rules.
//
SPDBG_ASSERT( m_pEngine != NULL );
SPDBG_ASSERT( !SP_IS_BAD_READ_PTR( m_pRuleTable ) );
m_pEngine->InvalidateCache( this );
// Store old state information.
BYTE * old_pReplacementData;
RUNTIMERULEENTRY * old_pRuleTable;
SPCFGHEADER old_Header;
SPGRAMMARTYPE old_LoadedType;
BYTE * old_pData;
memcpy( &old_Header, &m_Header, sizeof( SPCFGHEADER ) );
old_pReplacementData = m_pReplacementData;
old_pRuleTable = m_pRuleTable;
old_pData = m_pData;
old_LoadedType = m_LoadedType;
hr = InternalReload( pBinaryData );
if( SUCCEEDED( hr ) )
{
// Clean up the old state.
delete[] old_pReplacementData;
if( m_LoadedType == Memory )
{
delete [] old_pData;
}
if( old_Header.cRules != m_Header.cRules )
{
delete [] old_pRuleTable;
}
m_ulDictationTags = 0;
for(ULONG nArc = 0; nArc < m_Header.cArcs; nArc++)
{
if (m_Header.pArcs[nArc].TransitionIndex == SPDICTATIONTRANSITION)
{
m_ulDictationTags++;
}
}
}
else
{
// Copy the header.
// Restore the old state.
memcpy( &m_Header, &old_Header, sizeof( SPCFGHEADER ) );
if( m_pReplacementData != old_pReplacementData )
{
delete [] m_pReplacementData;
m_pReplacementData = old_pReplacementData;
m_pData = old_pData;
}
if( m_pRuleTable != old_pRuleTable )
{
delete [] m_pRuleTable;
m_pRuleTable = old_pRuleTable;
}
}
return hr;
}
/****************************************************************************
* CCFGGrammar::GetNumberDictationTags *
*-------------------------------------*
* Description:
* Returns the number of embedded dictation tags within the current CFG.
* This is used by the srrecoinstgrammar to keep track of whether it should
* load dictation for this CFG.
*
* Returns:
*
****************************************************************** davewood ***/
STDMETHODIMP CCFGGrammar::GetNumberDictationTags(ULONG * pulTags)
{
SPAUTO_OBJ_LOCK;
SPDBG_FUNC("CCFGGrammar::NumberDictationTags");
*pulTags = m_ulDictationTags;
return S_OK;
}