Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2914 lines
93 KiB

// Frontend.cpp : Implementation of CGramFrontEnd
#include "stdafx.h"
#include "FrontEnd.h"
#ifndef _WIN32_WCE
#include <wchar.h>
#endif
#include <initguid.h>
DEFINE_GUID(IID_IXMLNodeSource,0xd242361d,0x51a0,0x11d2,0x9c,0xaf,0x00,0x60,0xb0,0xec,0x3d,0x39);
DEFINE_GUID(IID_IXMLParser,0xd242361e,0x51a0,0x11d2,0x9c,0xaf,0x00,0x60,0xb0,0xec,0x3d,0x39);
DEFINE_GUID(IID_IXMLNodeFactory,0xd242361f,0x51a0,0x11d2,0x9c,0xaf,0x00,0x60,0xb0,0xec,0x3d,0x39);
DEFINE_GUID(CLSID_XMLParser,0xd2423620,0x51a0,0x11d2,0x9c,0xaf,0x00,0x60,0xb0,0xec,0x3d,0x39);
/****************************************************************************
* CXMLTreeNode::AddChild *
*------------------------*
* Description:
* Adds the child node to its parent in the XML node tree.
* Returns:
* S_OK
***************************************************************** PhilSch ***/
HRESULT CXMLTreeNode::AddChild(CXMLTreeNode * const pChild)
{
SPDBG_FUNC("CXMLTreeNode::AddChild");
SPDBG_ASSERT(pChild != NULL);
if (m_pFirstChild == NULL)
{
SPDBG_ASSERT(m_ulNumChildren == 0);
m_pFirstChild = pChild;
m_pLastChild = m_pFirstChild;
}
else
{
SPDBG_ASSERT(m_ulNumChildren > 0);
m_pLastChild->m_pNextSibling = pChild;
m_pLastChild = pChild;
}
m_ulNumChildren++;
pChild->m_pParent = this;
return S_OK;
}
/****************************************************************************
* CXMLTreeNode::ExtractVariant *
*------------------------------*
* Description (helper function):
* Extracts a numeric or boolean variant according to the following strategy:
* 1. compute dblVal (VT_R8)
* 2. compare in the following order both SUCCEEDED(hr = ChangeType())
* and value == dblVal:
* a. VT_UI4 (ulVal)
* b. VT_I4 (lVal)
* c. VT_R4 (fltVal)
* d. VT_R8 (dblVal)
* NOTE: we don't extract 64-bit integer values here!
* 3. if (2) failed check for VT_BOOL
* 4. if (3) failed assign to VT_BSTR
*
* Returns:
* S_OK, E_OUTOFMEMORY
* SPERR_STGF_ERRROR -- redefinition of attribute
***************************************************************** PhilSch ***/
HRESULT CXMLTreeNode::ExtractVariant(const WCHAR * pszAttribValue, SPVARIANTALLOWTYPE vtDesired, VARIANT *pvValue)
{
SPDBG_FUNC("CXMLNode::ExtractVariant");
HRESULT hr = S_OK;
if (pvValue->vt != VT_EMPTY)
{
// redefinition of an attribute value!!
return SPERR_STGF_ERROR;
}
CComVariant vSrc(pszAttribValue);
CComVariant vDest;
double dblVal;
switch (vtDesired)
{
case SPVAT_BSTR:
hr = vSrc.Detach(pvValue);
break;
case SPVAT_I4:
if (SUCCEEDED(vDest.ChangeType(VT_UI4, &vSrc)))
{
hr = vDest.Detach(pvValue);
}
else if (SUCCEEDED(vDest.ChangeType(VT_I4, &vSrc)))
{
hr = vDest.Detach(pvValue);
}
else
{
hr = SPERR_STGF_ERROR;
}
break;
case SPVAT_NUMERIC:
if (SUCCEEDED(vDest.ChangeType(VT_R8, &vSrc)))
{
dblVal = vDest.dblVal;
if (SUCCEEDED(vDest.ChangeType(VT_UI4, &vSrc)) && (dblVal == vDest.ulVal))
{
// we have a ULONG -- let's keep it
hr = vDest.Detach(pvValue);
}
else if (SUCCEEDED(vDest.ChangeType(VT_I4, &vSrc)) && (dblVal == vDest.lVal))
{
// we have a int -- let's keep it
hr = vDest.Detach(pvValue);
}
else if (SUCCEEDED(vDest.ChangeType(VT_R4, &vSrc)) && (dblVal == vDest.fltVal))
{
// we have a float -- let's keep it
hr = vDest.Detach(pvValue);
}
else
{
// we have a float -- let's keep it
hr = vDest.Detach(pvValue);
}
}
else
{
hr = SPERR_STGF_ERROR;
}
break;
default:
hr = SPERR_STGF_ERROR;
}
/* if (!(vtDesired & VT_BSTR) && SUCCEEDED(vDest.ChangeType(VT_R8, &vSrc)))
{
dblVal = vDest.dblVal;
if (SUCCEEDED(vDest.ChangeType(VT_UI4, &vSrc)) && (dblVal == vDest.ulVal))
{
// we have a ULONG -- let's keep it
hr = vDest.Detach(pvValue);
}
else if (SUCCEEDED(vDest.ChangeType(VT_I4, &vSrc)) && (dblVal == vDest.lVal))
{
// we have a int -- let's keep it
hr = vDest.Detach(pvValue);
}
else if (SUCCEEDED(vDest.ChangeType(VT_R4, &vSrc)) && (dblVal == vDest.fltVal))
{
// we have a float -- let's keep it
hr = vDest.Detach(pvValue);
}
else
{
// we have a float -- let's keep it
hr = vDest.Detach(pvValue);
}
}
else
{
if (vtDesired & VT_BSTR)
{
hr = vSrc.Detach(pvValue);
}
// check for "true", "false", "yes", "no"
else if (!wcsicmp(L"TRUE", pszAttribValue) || !wcsicmp(L"YES", pszAttribValue))
{
pvValue->boolVal = VARIANT_TRUE;
pvValue->vt = VT_BOOL;
}
else if (!wcsicmp(L"FALSE", pszAttribValue) || !wcsicmp(L"NO", pszAttribValue))
{
pvValue->boolVal = VARIANT_FALSE;
pvValue->vt = VT_BOOL;
}
else
{
hr = SPERR_STGF_ERROR;
}
}
if ((vtDesired != VT_EMPTY) && (((vtDesired | VT_BSTR) & pvValue->vt) == 0))
{
// we could not extract the requested variant type --> error upstairs!
hr = SPERR_STGF_ERROR;
}
*/
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CXMLTreeNode::ExtractFlag *
*---------------------------*
* Description:
* Extract an attribute value and set the corresponding bit if affirmative
*
* pszAttribValue -- pointer to attrib value
* usAttribFlag -- use this flag to OR a 'yes' to pvValue->ulVal
*
* Returns:
* S_OK
* SPERR_STGF_ERROR -- if invalid value --> use IDS_INCORR_ATTRIB_VALUE
***************************************************************** PhilSch ***/
HRESULT CXMLTreeNode::ExtractFlag(const WCHAR * pszAttribValue, USHORT usAttribFlag, VARIANT *pvValue)
{
SPDBG_FUNC("CXMLTreeNode::ExtractFlag");
HRESULT hr = S_OK;
SPDBG_ASSERT(pvValue->vt = VT_UI4);
if ((wcsicmp(L"1", pszAttribValue) == 0) ||
(wcsicmp(L"YES", pszAttribValue) == 0) ||
(wcsicmp(L"ACTIVE", pszAttribValue) == 0) ||
(wcsicmp(L"TRUE", pszAttribValue) == 0))
{
if (pvValue->vt == VT_EMPTY)
{
pvValue->vt = VT_UI4;
pvValue->ulVal = 0;
}
pvValue->ulVal |= usAttribFlag;
}
else if ((wcsicmp(L"0", pszAttribValue) == 0) ||
(wcsicmp(L"NO", pszAttribValue) == 0) ||
(wcsicmp(L"INACTIVE", pszAttribValue) == 0) ||
(wcsicmp(L"FALSE", pszAttribValue) == 0))
{
if (pvValue->vt == VT_EMPTY)
{
pvValue->vt = VT_UI4;
pvValue->ulVal = 0;
}
}
else
{
hr = SPERR_STGF_ERROR;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CXMLTreeNode::ConvertId *
*-------------------------*
* Description:
* Converts an id which was extracted as a VT_BSTR to either the value
* of the <ID> or a numberic (VT_UI4) value.
* Returns:
* S_OK
* SPERR_STGF_ERROR -- if id not defined
***************************************************************** PhilSch ***/
HRESULT CXMLTreeNode::ConvertId(const WCHAR *pszAttribValue,
CSpBasicQueue<CDefineValue> * pDefineValueList, VARIANT *pvValue)
{
SPDBG_FUNC("CXMLTreeNode::ConvertId");
HRESULT hr = S_OK;
CDefineValue *pDefValue = pDefineValueList->Find(pszAttribValue);
if (pDefValue)
{
pvValue->ulVal = pDefValue->m_vValue.ulVal;
pvValue->vt = pDefValue->m_vValue.vt;
}
else
{
if (!wcsicmp(pszAttribValue, L"INF"))
{
pvValue->vt = VT_UI2;
pvValue->uiVal = 255;
}
else
{
CComVariant vNewIdValue;
hr = ExtractVariant(pszAttribValue, SPVAT_I4, &vNewIdValue);
if (SUCCEEDED(hr) && ((vNewIdValue.vt | VT_BSTR) || (vNewIdValue.vt | VT_UI4)))
{
hr = vNewIdValue.Detach(pvValue);
}
else
{
hr = SPERR_STGF_ERROR;
}
}
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
CXMLTreeNode::~CXMLTreeNode() {}
/****************************************************************************
* CXMLNode::IsEndOfValue *
*------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
BOOL CXMLTreeNode::IsEndOfValue(USHORT cRecs, XML_NODE_INFO ** apNodeInfo, ULONG i)
{
BOOL fResult = TRUE;
SPDBG_ASSERT(cRecs > 0);
if (i < (ULONG) cRecs-1)
{
if ((apNodeInfo[i]->pwcText[apNodeInfo[i]->ulLen] != L'\"') &&
(apNodeInfo[i]->dwSubType == 0x0))
{
// no quote --> not end of attribute value
fResult = FALSE;
}
else if (apNodeInfo[i]->dwSubType == 0x3c)
{
// special XML character --> scan to see if '=' comes before '"'
const WCHAR *pStr = apNodeInfo[i+1]->pwcText;
while (pStr && (*pStr != L'='))
{
if (*pStr == L'\"')
{
fResult = FALSE;
break;
}
pStr++;
}
}
}
return fResult;
}
/****************************************************************************
* CGrammarNode::GetTable *
*------------------------*
* Description:
* Returns attribute table for <GRAMMAR>
* Returns:
* S_OK, E_OUTOFMEMORY
***************************************************************** PhilSch ***/
HRESULT CGrammarNode::GetTable(SPATTRIBENTRY ** pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CGrammarNode::GetTable");
HRESULT hr = S_OK;
SPATTRIBENTRY AETable[]=
{
// pszAttribName, vtDesired, fIsIdValue, pvarMember
{L"LANGID", SPVAT_BSTR, FALSE, &m_vLangId},
{L"WORDTYPE", SPVAT_BSTR, FALSE, &m_vWordType},
{L"LEXDELIMITER", SPVAT_BSTR, FALSE, &m_vDelimiter},
{L"xmlns", SPVAT_BSTR, FALSE, &m_vNamespace},
};
*pcTableEntries = sizeof(AETable)/sizeof(SPATTRIBENTRY);
*pTable = new SPATTRIBENTRY[*pcTableEntries];
if (*pTable)
{
memcpy(*pTable, &AETable, *pcTableEntries*sizeof(SPATTRIBENTRY));
}
else
{
hr = E_OUTOFMEMORY;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CGrammarNode::PostProcess *
*---------------------------*
* Description:
* Resets the compiler backend to the m_vLangId
* Returns:
* S_OK
***************************************************************** PhilSch ***/
HRESULT CGrammarNode::PostProcess(ISpGramCompBackend * pBackend,
CSpBasicQueue<CInitialRuleState> * pInitialRuleStateList,
CSpBasicQueue<CDefineValue> * pDefineValueList,
ULONG ulLineNumber, CXMLTreeNode * pThis, ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CGrammarNode::PostProcess");
HRESULT hr = S_OK;
if (m_vLangId.vt == VT_EMPTY)
{
m_vLangId = ::SpGetUserDefaultUILanguage();
hr = m_vLangId.ChangeType(VT_UI2);
}
else
{
// convert from hex to decimal
WCHAR *pStr = m_vLangId.bstrVal;
WCHAR *pStopString;
ULONG ulDecimalLangId = wcstoul(pStr, &pStopString, 16);
if (!IsValidLocale(MAKELCID(ulDecimalLangId,0), LCID_SUPPORTED))
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT2(ulLineNumber, IDS_INCORR_ATTRIB_VALUE, m_vLangId.bstrVal, L"LANGID");
}
else
{
m_vLangId.Clear();
m_vLangId.vt = VT_UI2;
m_vLangId.uiVal = (WORD) ulDecimalLangId;
}
}
if ((m_vWordType.vt == VT_BSTR) && wcsicmp(m_vWordType.bstrVal, L"LEXICAL"))
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT( -1, IDS_UNSUPPORTED_WORDTYPE, m_vWordType.bstrVal);
}
if (SUCCEEDED(hr))
{
hr = pBackend->ResetGrammar(m_vLangId.iVal);
if (FAILED(hr))
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT( -1, IDS_PARSER_INTERNAL_ERROR, L"internal to CSpPhoneConverter");
}
}
if (SUCCEEDED(hr))
{
switch (PRIMARYLANGID(m_vLangId.uiVal))
{
case LANG_JAPANESE:
// NTRAID#SPEECH-7343-2000/08/22-philsch: need separator for Japanese
pThis->m_pNodeFactory->m_pszSeparators = SP_JAPANESE_SEPARATORS;
break;
case LANG_CHINESE:
// NTRAID#SPEECH-7343-2000/08/22-philsch: need separator for Chinese
pThis->m_pNodeFactory->m_pszSeparators = SP_CHINESE_SEPARATORS;
break;
case LANG_ENGLISH:
default:
pThis->m_pNodeFactory->m_pszSeparators = SP_ENGLISH_SEPARATORS;
break;
}
if (m_vDelimiter.vt != VT_EMPTY)
{
if (wcslen(m_vDelimiter.bstrVal) > 1)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT(pThis->m_ulLineNumber, IDS_INCORR_DELIM, m_vDelimiter.bstrVal);
}
else
{
pThis->m_pNodeFactory->m_wcDelimiter = m_vDelimiter.bstrVal[0];
}
}
else
{
pThis->m_pNodeFactory->m_wcDelimiter = L'/';
}
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CGrammarNode::GenerateGrammarFromNode *
*---------------------------------------*
* Description:
* Generates the grammar by generating it's children,
* which should be all rules, in sequence.
* Returns:
* S_OK, ...
***************************************************************** PhilSch ***/
HRESULT CGrammarNode::GenerateGrammarFromNode(SPSTATEHANDLE hOuterFromNode,
SPSTATEHANDLE hOuterToNode,
ISpGramCompBackend * pBackend,
CXMLTreeNode *pThis,
ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("GenerateGrammarFromNode::GenerateGrammar");
HRESULT hr = S_OK;
if (pThis->m_eType == SPXML_ROOT)
{
// generate the grammar for the only child which should be SPXML_GRAMMAR
SPDBG_ASSERT(pThis->m_ulNumChildren == 1);
hr = pThis->m_pFirstChild->GenerateGrammar(hOuterFromNode, hOuterToNode,
pBackend, pErrorLog);
}
else
{
SPDBG_ASSERT(hOuterFromNode == NULL);
SPDBG_ASSERT(hOuterToNode == NULL);
CXMLTreeNode *pChild = pThis->m_pFirstChild;
for (ULONG i = 0; SUCCEEDED(hr) && (i < pThis->m_ulNumChildren); i++)
{
SPDBG_ASSERT(pChild);
if ((pChild->m_eType != SPXML_RULE) && (pChild->m_eType != SPXML_DEFINE))
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT2(pThis->m_ulLineNumber, IDS_CONTAINMENT_ERROR, L"<RULE>", L"<GRAMMAR>");
}
else
{
hr = pChild->GenerateGrammar(hOuterFromNode, hOuterToNode, pBackend, pErrorLog);
}
if (SUCCEEDED(hr))
{
pChild = pChild->m_pNextSibling;
}
}
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CRuleNode::GetTable *
*---------------------*
* Description:
* Returns attribute table for <RULE>
* Returns:
* S_OK, E_OUTOFMEMORY
***************************************************************** PhilSch ***/
HRESULT CRuleNode::GetTable(SPATTRIBENTRY ** pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CRuleNode::GetTable");
HRESULT hr = S_OK;
m_vActiveFlag.ulVal = 0;
m_vRuleFlags.ulVal = 0;
SPATTRIBENTRY AETable[]=
{
// pszAttribName, vtDesired, fIsFlag, pvarMember
{L"NAME", SPVAT_BSTR, FALSE, &m_vRuleName},
{L"ID", SPVAT_I4, FALSE, &m_vRuleId},
{L"TOPLEVEL", (SPVARIANTALLOWTYPE)SPRAF_Active, TRUE, &m_vActiveFlag},
{L"EXPORT", (SPVARIANTALLOWTYPE)SPRAF_Export, TRUE, &m_vRuleFlags},
{L"INTERPRETER", (SPVARIANTALLOWTYPE)SPRAF_Interpreter, TRUE, &m_vRuleFlags},
{L"DYNAMIC", (SPVARIANTALLOWTYPE)SPRAF_Dynamic, TRUE, &m_vRuleFlags},
{L"TEMPLATE", SPVAT_BSTR, FALSE, &m_vTemplate}
};
*pcTableEntries = sizeof(AETable)/sizeof(SPATTRIBENTRY);
*pTable = new SPATTRIBENTRY[*pcTableEntries];
if (*pTable)
{
memcpy(*pTable, &AETable, *pcTableEntries*sizeof(SPATTRIBENTRY));
}
else
{
hr = E_OUTOFMEMORY;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CRuleNode::PostProcess *
*------------------------*
* Description:
* Creates the rule and finds duplicates; sets the rule's initial state
* Returns:
* S_OK, SPERR_STGF_ERROR
***************************************************************** PhilSch ***/
HRESULT CRuleNode::PostProcess(ISpGramCompBackend * pBackend,
CSpBasicQueue<CInitialRuleState> * pInitialRuleStateList,
CSpBasicQueue<CDefineValue> * pDefineValueList,
ULONG ulLineNumber, CXMLTreeNode * pThis, ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CRuleNode::PostProcess");
HRESULT hr = S_OK;
if (m_vRuleName.vt == VT_EMPTY)
{
m_vRuleName.ulVal = 0;
}
if (m_vRuleId.vt == VT_EMPTY)
{
m_vRuleId.ulVal = 0;
}
if (m_vRuleFlags.vt == VT_EMPTY)
{
m_vRuleFlags.ulVal = 0;
}
if (m_vActiveFlag.vt != VT_EMPTY)
{
SPDBG_ASSERT(m_vActiveFlag.vt == VT_UI4);
if (m_vActiveFlag.ulVal)
{
m_vRuleFlags.ulVal |= SPRAF_Active;
}
m_vRuleFlags.ulVal |= SPRAF_TopLevel;
}
if (m_vTemplate.vt != VT_EMPTY)
{
m_vRuleFlags.ulVal |= SPRAF_Interpreter;
}
SPDBG_ASSERT((m_vRuleId.vt == VT_UI4) || (m_vRuleId.vt == VT_EMPTY));
hr = pBackend->GetRule(m_vRuleName.bstrVal, m_vRuleId.ulVal, m_vRuleFlags.ulVal,
TRUE, &m_hInitialState);
if (SUCCEEDED(hr))
{
CInitialRuleState *pState = new CInitialRuleState(m_vRuleName.bstrVal, m_vRuleId.ulVal, m_hInitialState);
if (pState && !pInitialRuleStateList->Find(m_vRuleName.bstrVal) && !pInitialRuleStateList->Find(m_vRuleId.ulVal))
{
pInitialRuleStateList->InsertTail(pState);
}
else
{
if (pState)
{
hr = SPERR_RULE_NAME_ID_CONFLICT;
if (m_vRuleId.vt != VT_EMPTY)
{
m_vRuleId.ChangeType(VT_BSTR);
}
LOGERRORFMT2(ulLineNumber, IDS_RULE_REDEFINITION, (m_vRuleName.vt == VT_EMPTY) ? L"" : m_vRuleName.bstrVal,
(m_vRuleId.vt == VT_EMPTY) ? L"" : m_vRuleId.bstrVal);
delete pState;
}
else
{
hr = E_OUTOFMEMORY;
LOGERRORFMT( -1, IDS_PARSER_INTERNAL_ERROR, L"E_OUTOFMEMORY");
}
}
}
else
{
if (SPERR_EXPORT_DYNAMIC_RULE == hr)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT(ulLineNumber, IDS_DYNAMIC_EXPORT, m_vRuleName.bstrVal);
}
else if (SPERR_RULE_NAME_ID_CONFLICT == hr)
{
hr = SPERR_STGF_ERROR;
if (m_vRuleId.vt != VT_EMPTY)
{
m_vRuleId.ChangeType(VT_BSTR);
}
LOGERRORFMT2(ulLineNumber, IDS_RULE_REDEFINITION, (m_vRuleName.vt == VT_EMPTY) ? L"" : m_vRuleName.bstrVal,
(m_vRuleId.vt == VT_EMPTY) ? L"" : m_vRuleId.bstrVal);
}
else
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT2( -1, IDS_MISSING_REQUIRED_ATTRIBUTE, L"NAME or ID", L"RULE");
}
}
if (SUCCEEDED(hr) && (m_vTemplate.vt != VT_EMPTY))
{
hr = pBackend->AddResource(m_hInitialState, L"TEMPLATE", m_vTemplate.bstrVal);
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CRuleNode::GetPropertyValueInfoFromNode *
*-----------------------------------------*
* Description:
* Get the property value info
* Returns:
* S_OK
* S_FALSE -- in case there is no property value
***************************************************************** PhilSch ***/
HRESULT CRuleNode::GetPropertyValueInfoFromNode(WCHAR **ppszValue, VARIANT *pvValue)
{
SPDBG_FUNC("CRuleNode::GetPropertyValueInfoFromNode");
pvValue->ulVal = (ULONG)(ULONG_PTR) m_hInitialState;
pvValue->vt = VT_UI4;
return S_OK;
}
/****************************************************************************
* CRuleNode::GenerateGrammarFromNode *
*------------------------------------*
* Description:
*
* Returns:
* S_OK
* SPERR_STGF_ERROR -- ...
***************************************************************** PhilSch ***/
HRESULT CRuleNode::GenerateGrammarFromNode(SPSTATEHANDLE hOuterFromNode,
SPSTATEHANDLE hOuterToNode,
ISpGramCompBackend * pBackend,
CXMLTreeNode *pThis,
ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CRuleNode::GenerateGrammarFromNode");
HRESULT hr = S_OK;
// check containment!
if (pThis->m_pParent->m_eType != SPXML_GRAMMAR)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT2(pThis->m_ulLineNumber, IDS_CONTAINMENT_ERROR, L"<RULE>", L"<GRAMMAR>");
}
else
{
SPDBG_ASSERT(hOuterFromNode == NULL);
SPDBG_ASSERT(hOuterToNode == NULL);
// deal with resources first
CXMLTreeNode *pChild = pThis->m_pFirstChild;
CXMLTreeNode *pLastChild = NULL;
ULONG ulOrigNumChildren = pThis->m_ulNumChildren;
for (ULONG i = 0; SUCCEEDED(hr) && pChild && (i < ulOrigNumChildren); i++)
{
SPDBG_ASSERT(pChild);
if (pChild->m_eType == SPXML_RESOURCE)
{
CXMLNode<CResourceNode> * pResNode = (CXMLNode<CResourceNode>*)pChild;
if (pChild->m_ulNumChildren != 0)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT2(pThis->m_ulLineNumber, IDS_CONTAINMENT_ERROR, L"<![CDATA[]]>", L"<RESOURCE>");
}
else
{
hr = pBackend->AddResource(m_hInitialState,
(pResNode->m_vName.vt == VT_BSTR) ? pResNode->m_vName.bstrVal : NULL,
(pResNode->m_vText.vt == VT_BSTR) ? pResNode->m_vText.bstrVal : NULL);
}
if (SUCCEEDED(hr))
{
if (pThis->m_pFirstChild == pChild)
{
pThis->m_pFirstChild = pChild->m_pNextSibling;
}
else
{
pLastChild->m_pNextSibling = pChild->m_pNextSibling;
}
pThis->m_ulNumChildren--;
}
}
else
{
pLastChild = pChild;
}
pChild = pChild->m_pNextSibling;
}
if (SUCCEEDED(hr))
{
if (pThis->m_ulNumChildren > 0)
{
hr = pThis->GenerateSequence(m_hInitialState, NULL, pBackend, pErrorLog);
}
else
{
if (!(m_vRuleFlags.ulVal & SPRAF_Dynamic))
{
hr = SPERR_STGF_ERROR;
m_vRuleId.ChangeType(VT_BSTR);
LOGERRORFMT2(pThis->m_ulLineNumber, IDS_EMPTY_XML_RULE, m_vRuleName.bstrVal, m_vRuleId.bstrVal);
}
}
}
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CDefineNode::GetTable *
*-----------------------*
* Description:
* Since this tag doesn't have any attribues, we simply return (NULL, 0)
* Returns:
* S_OK (always!!)
***************************************************************** PhilSch ***/
HRESULT CDefineNode::GetTable(SPATTRIBENTRY **pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CDefineNode::GetTable");
*pTable = NULL;
*pcTableEntries = 0;
return S_OK;
}
/****************************************************************************
* CIdNode::GetTable *
*-------------------*
* Description:
* Returns attribute table for <ID>
* Returns:
* S_OK, E_OUTOFMEMORY
***************************************************************** PhilSch ***/
HRESULT CIdNode::GetTable(SPATTRIBENTRY ** pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CIdNode::GetTable");
HRESULT hr = S_OK;
SPATTRIBENTRY AETable[]=
{
// pszAttribName, vtDesired, fIsFlag, pvarMember
{L"NAME", SPVAT_BSTR, FALSE, &m_vIdName},
{L"VAL", SPVAT_NUMERIC, FALSE, &m_vIdValue},
{L"VALSTR", SPVAT_BSTR, FALSE, &m_vIdValue}
};
*pcTableEntries = sizeof(AETable)/sizeof(SPATTRIBENTRY);
*pTable = new SPATTRIBENTRY[*pcTableEntries];
if (*pTable)
{
memcpy(*pTable, &AETable, *pcTableEntries*sizeof(SPATTRIBENTRY));
}
else
{
hr = E_OUTOFMEMORY;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CIdNode::PostProcess *
*----------------------*
* Description:
* Adds id to DefineValueList
* Returns:
* S_OK
* SPERR_STGF_ERROR -- IDS_ID_REDEFINITION
***************************************************************** PhilSch ***/
HRESULT CIdNode::PostProcess(ISpGramCompBackend * pBackend,
CSpBasicQueue<CInitialRuleState> * pInitialRuleStateList,
CSpBasicQueue<CDefineValue> * pDefineValueList,
ULONG ulLineNumber, CXMLTreeNode * pThis, ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CIdNode::PostProcess");
HRESULT hr = S_OK;
if (m_vIdName.vt == VT_EMPTY)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT2(ulLineNumber, IDS_MISSING_REQUIRED_ATTRIBUTE, L"NAME", L"ID");
}
if (SUCCEEDED(hr) && (m_vIdValue.vt == VT_EMPTY))
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT2(ulLineNumber, IDS_MISSING_REQUIRED_ATTRIBUTE, L"VAL", L"ID");
}
if (SUCCEEDED(hr))
{
CDefineValue *pDefVal = pDefineValueList->Find(m_vIdName.bstrVal);
if (!pDefVal)
{
CDefineValue *pNewVal = new CDefineValue(m_vIdName.bstrVal, m_vIdValue);
if (pNewVal)
{
pDefineValueList->InsertTail(pNewVal);
}
else
{
hr = E_OUTOFMEMORY;
LOGERRORFMT( -1, IDS_PARSER_INTERNAL_ERROR, L"E_OUTOFMEMORY");
}
}
else
{
hr = SPERR_STGF_ERROR;
m_vIdValue.ChangeType(VT_BSTR);
LOGERRORFMT2(ulLineNumber, IDS_ID_REDEFINITION, m_vIdName.bstrVal, m_vIdValue.bstrVal);
}
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CPhraseNode::GetTable *
*-----------------------*
* Description:
* Returns attribute table for <PHRASE>
* Returns:
* S_OK, E_OUTOFMEMORY
***************************************************************** PhilSch ***/
HRESULT CPhraseNode::GetTable(SPATTRIBENTRY ** pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CPhraseNode::GetTable");
HRESULT hr = S_OK;
SPATTRIBENTRY AETable[]=
{
// pszAttribName, vtDesired, fIsFlag, pvarMember
{L"PROPNAME", SPVAT_BSTR, FALSE, &m_vPropName},
{L"PROPID", SPVAT_I4, FALSE, &m_vPropId},
{L"VAL", SPVAT_I4, FALSE, &m_vPropVariantValue},
{L"VALSTR", SPVAT_BSTR, FALSE, &m_vPropValue},
{L"PRON", SPVAT_BSTR, FALSE, &m_vPron},
{L"DISP", SPVAT_BSTR, FALSE, &m_vDisp},
{L"MIN", SPVAT_I4, FALSE, &m_vMin},
{L"MAX", SPVAT_I4, FALSE, &m_vMax},
{L"WEIGHT", SPVAT_NUMERIC , FALSE, &m_vWeight}
};
*pcTableEntries = sizeof(AETable)/sizeof(SPATTRIBENTRY);
*pTable = new SPATTRIBENTRY[*pcTableEntries];
if (*pTable)
{
memcpy(*pTable, &AETable, *pcTableEntries*sizeof(SPATTRIBENTRY));
}
else
{
hr = E_OUTOFMEMORY;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CPhraseNode::PostProcess *
*--------------------------*
* Description:
* Initialize the weight if it's not already set (need to be empty
* initially to detect redefinition of its value!)
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CPhraseNode::PostProcess(ISpGramCompBackend * pBackend,
CSpBasicQueue<CInitialRuleState> * pInitialRuleStateList,
CSpBasicQueue<CDefineValue> * pDefineValueList,
ULONG ulLineNumber, CXMLTreeNode * pThis, ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CPhraseNode::PostProcess");
HRESULT hr = S_OK;
if (m_vWeight.vt == VT_EMPTY)
{
m_vWeight = 1.0f;
}
switch (m_vMin.vt)
{
case VT_BSTR:
m_vMin.uiVal = 255;
break;
case VT_EMPTY:
if (pThis->m_eType == SPXML_OPT)
{
m_vMin.uiVal = 0;
}
else
{
m_vMin.uiVal = 1;
}
break;
case VT_UI2:
case VT_UI4:
break;
default:
{
hr = SPERR_STGF_ERROR;
m_vMin.ChangeType(VT_BSTR);
LOGERRORFMT2(ulLineNumber, IDS_INCORR_ATTRIB_VALUE, m_vMin.bstrVal, L"MIN");
}
break;
}
m_vMin.vt = VT_UI2;
switch (m_vMax.vt)
{
case VT_BSTR:
m_vMax.uiVal = 255;
break;
case VT_EMPTY:
m_vMax.uiVal = 1;
break;
case VT_UI2:
case VT_UI4:
if (m_vMax.ulVal > 0)
{
break; // break if the value is ok
}
default:
{
hr = SPERR_STGF_ERROR;
m_vMax.ChangeType(VT_BSTR);
LOGERRORFMT2(ulLineNumber, IDS_INCORR_ATTRIB_VALUE, m_vMax.bstrVal, L"MAX");
}
break;
}
m_vMax.vt = VT_UI2;
if (SUCCEEDED(hr) && (pThis->m_eType == SPXML_OPT) && (m_vMin.uiVal > 0))
{
hr = SPERR_STGF_ERROR;
m_vMin.ChangeType(VT_BSTR);
LOGERRORFMT(ulLineNumber, IDS_MIN_IN_OPT, m_vMin.bstrVal);
}
if (SUCCEEDED(hr) &&(m_vMin.uiVal > m_vMax.uiVal))
{
hr = SPERR_STGF_ERROR;
m_vMin.ChangeType(VT_BSTR);
m_vMax.ChangeType(VT_BSTR);
LOGERRORFMT2(ulLineNumber, IDS_MIN_MAX_ERROR, m_vMin.bstrVal, m_vMax.bstrVal);
}
if (SUCCEEDED(hr) && (m_vWeight.fltVal < 0.0))
{
hr = SPERR_STGF_ERROR;
m_vWeight.ChangeType(VT_BSTR);
LOGERRORFMT2(ulLineNumber, IDS_INCORR_ATTRIB_VALUE, m_vWeight.bstrVal, L"WEIGHT");
}
return hr;
}
/****************************************************************************
* CPhraseNode::GetPropertyNameInfoFromNode *
*------------------------------------------*
* Description:
* Get the property name info
* Returns:
* S_OK
* S_FALSE -- in case there is no property name
***************************************************************** PhilSch ***/
HRESULT CPhraseNode::GetPropertyNameInfoFromNode(WCHAR **ppszPropName, ULONG *pulId)
{
SPDBG_FUNC("CPhraseNode::GetPropertyNameInfoFromNode");
HRESULT hr = S_OK;
if ((VT_EMPTY == m_vPropName.vt) && (VT_EMPTY == m_vPropId.vt))
{
hr = S_FALSE;
}
else
{
*ppszPropName = (m_vPropName.vt == VT_BSTR) ? m_vPropName.bstrVal : NULL;
*pulId = (m_vPropId.vt == VT_UI4) ? m_vPropId.ulVal : 0;
}
return hr;
}
/****************************************************************************
* CPhraseNode::GetPropertyValueInfoFromNode *
*-------------------------------------------*
* Description:
* Get the property value info
* Returns:
* S_OK
* S_FALSE -- in case there is no property value
***************************************************************** PhilSch ***/
HRESULT CPhraseNode::GetPropertyValueInfoFromNode(WCHAR **ppszValue, VARIANT *pvValue)
{
SPDBG_FUNC("CPhraseNode::GetPropertyValueInfoFromNode");
HRESULT hr = S_OK;
if (!m_fValidValue || (VT_EMPTY == (m_vPropValue.vt | m_vPropVariantValue.vt)))
{
return S_FALSE;
}
else
{
SPDBG_ASSERT(m_vPropValue.vt == VT_BSTR || m_vPropValue.vt == VT_EMPTY);
*ppszValue = (m_vPropValue.vt == VT_EMPTY) ? NULL : m_vPropValue.bstrVal;
*pvValue = m_vPropVariantValue;
m_fValidValue = false;
}
return hr;
}
/****************************************************************************
* CPhraseNode::GetPronAndDispInfoFromNode *
*-----------------------------------------*
* Description:
* Get m_vPron and m_vDisp.
* Returns:
* S_OK, or S_FALSE in case neither one is set.
***************************************************************** PhilSch ***/
HRESULT CPhraseNode::GetPronAndDispInfoFromNode(WCHAR **ppszPron, WCHAR **ppszDisp)
{
SPDBG_FUNC("CPhraseNode::GetPronAndDispInfoFromNode");
HRESULT hr = S_FALSE;
if (m_vPron.vt == VT_BSTR)
{
*ppszPron = m_vPron.bstrVal;
hr = S_OK;
}
if (m_vDisp.vt == VT_BSTR)
{
// we need to escape '\' and '/'
ULONG ulLen = wcslen(m_vDisp.bstrVal);
WCHAR *pStr = STACK_ALLOC(WCHAR, 2*ulLen+1); // twice the size to be sure
if (pStr)
{
WCHAR *p = m_vDisp.bstrVal;
WCHAR *q = pStr;
while(*p)
{
if (*p == L'\\' || *p == L'/')
{
*q++ = L'\\';
}
*q++ = *p++;
}
*q = 0;
CComBSTR bstr(pStr);
::SysFreeString(m_vDisp.bstrVal);
m_vDisp.bstrVal = bstr.Detach();
*ppszDisp = m_vDisp.bstrVal;
hr = S_OK;
}
else
{
hr = E_OUTOFMEMORY;
}
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CPhraseNode::SetPropertyInfo *
*------------------------------*
* Description:
* Sets the property info if it has one
* Returns:
* S_OK, SPERR_STGF_ERROR --
* fHasProperty -- used to determine if we need an epsilon transition
***************************************************************** PhilSch ***/
HRESULT CPhraseNode::SetPropertyInfo(SPPROPERTYINFO *p, CXMLTreeNode * pParent, BOOL *pfHasProperty, ULONG ulLineNumber, ISpErrorLog *pErrorLog)
{
SPDBG_FUNC("CPhraseNode::SetPropertyInfo");
HRESULT hr = S_OK;
hr = GetPropertyValueInfoFromNode(const_cast<WCHAR**>(&p->pszValue), &p->vValue);
*pfHasProperty = (S_OK == hr) ? TRUE : FALSE;
if (*pfHasProperty && (S_FALSE == GetPropertyNameInfoFromNode(const_cast<WCHAR**>(&p->pszName), &p->ulId)))
{
if ((pParent->m_eType == SPXML_PHRASE) || (pParent->m_eType == SPXML_OPT) || (pParent->m_eType == SPXML_LIST))
{
hr = pParent->GetPropertyNameInfo(const_cast<WCHAR**>(&p->pszName), &p->ulId);
}
else
{
GetPropertyValueInfoFromNode(const_cast<WCHAR**>(&p->pszValue), &p->vValue);
CComVariant vVal(p->vValue);
vVal.ChangeType(VT_BSTR);
hr = E_FAIL;
LOGERRORFMT2(ulLineNumber, IDS_MISSING_PROPERTY_NAME, p->pszValue ? p->pszValue : L"", vVal.bstrVal);
}
}
if (FAILED(hr))
{
*pfHasProperty = FALSE;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CPhraseNode::GenerateGrammarFromNode *
*--------------------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CPhraseNode::GenerateGrammarFromNode(SPSTATEHANDLE hOuterFromNode,
SPSTATEHANDLE hOuterToNode,
ISpGramCompBackend * pBackend,
CXMLTreeNode *pThis,
ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CPhraseNode::GenerateGrammarFromNode");
HRESULT hr = S_OK;
if (pThis->m_eType == SPXML_OPT)
{
// check to make sure that the parent for <OPT> is not <LIST>
if (pThis->m_pParent->m_eType == SPXML_LIST)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT(pThis->m_ulLineNumber, IDS_OPT_IN_LIST, L"OPT");
}
}
if (SUCCEEDED(hr) && (pThis->m_eType == SPXML_OPT || (m_vMin.uiVal == 0)))
{
SPDBG_ASSERT(m_vMin.vt == VT_UI2);
hr = pBackend->AddWordTransition(hOuterFromNode, hOuterToNode, NULL, NULL, SPWT_LEXICAL, 1.0f, NULL);
m_vMin.uiVal = 1;
if ( hr == SPERR_AMBIGUOUS_PROPERTY )
{
SPPROPERTYINFO prop;
if (S_FALSE == pThis->m_pParent->GetPropertyNameInfo(const_cast<WCHAR**>(&prop.pszName), &prop.ulId))
{
pThis->m_pParent->m_pParent->GetPropertyNameInfo(const_cast<WCHAR**>(&prop.pszName), &prop.ulId);
}
CComVariant var;
var.vt = VT_UI4;
var.ulVal = prop.ulId;
var.ChangeType(VT_BSTR);
LOGERRORFMT2(pThis->m_ulLineNumber, IDS_AMBIGUOUS_PROPERTY, prop.pszName, var.bstrVal);
}
}
if ((m_vPron.vt != VT_EMPTY) || (m_vDisp.vt != VT_EMPTY))
{
// we have custom pronunications, we better have only one leaf ...
if ((pThis->m_ulNumChildren > 1) || (pThis->m_pFirstChild->m_eType != SPXML_LEAF))
{
hr = SPERR_STGF_ERROR;
if (m_vPron.vt != VT_EMPTY)
{
LOGERRORFMT(pThis->m_ulLineNumber, IDS_PRON_WORD, m_vPron.bstrVal);
}
else
{
LOGERRORFMT(pThis->m_ulLineNumber, IDS_DISP_WORD, m_vDisp.bstrVal);
}
}
}
if (SUCCEEDED(hr))
{
SPSTATEHANDLE hFromNode = hOuterFromNode;
SPSTATEHANDLE hToNode = NULL;
for (ULONG i = 1; SUCCEEDED(hr) && (i <= m_vMax.uiVal); i++)
{
m_fValidValue = true;
// add epsilon transitions to hOuterToNode once we reach max - min ...
if (i < m_vMax.uiVal)
{
hr = pBackend->CreateNewState(hFromNode, &hToNode);
}
else
{
hToNode = hOuterToNode;
}
if (SUCCEEDED(hr))
{
hr = pThis->GenerateSequence(hFromNode, hToNode, pBackend, pErrorLog);
}
if (i > m_vMin.uiVal)
{
hr = pBackend->AddWordTransition(hFromNode, hOuterToNode, NULL, NULL, SPWT_LEXICAL, 1.0f, NULL);
}
if (SUCCEEDED(hr))
{
hFromNode = hToNode;
}
}
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CPhraseNode::GetWeightFromNode *
*--------------------------------------*
* Description:
*
* Because ExtractVirant would convert the attribute value to VT_UI4, next VT_I4, then VT_R4, at last VT_R8
* We need to convert the value back. We would loose precision for VT_R8
*
* Returns:
*
***************************************************************** PhilSch ***/
float CPhraseNode::GetWeightFromNode() {
if (m_vWeight.vt != VT_R8)
{
m_vWeight.ChangeType(VT_R4, NULL);
return m_vWeight.fltVal;
}
else
{
return (float)m_vWeight.dblVal;
}
}
/****************************************************************************
* CListNode::GetTable *
*-----------------------*
* Description:
* Returns attribute table for <LIST>
* Returns:
* S_OK, E_OUTOFMEMORY
***************************************************************** PhilSch ***/
HRESULT CListNode::GetTable(SPATTRIBENTRY ** pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CListNode::GetTable");
HRESULT hr = S_OK;
SPATTRIBENTRY AETable[]=
{
// pszAttribName, vtDesired, fIsFlag, pvarMember
{L"PROPNAME", SPVAT_BSTR, FALSE, &m_vPropName},
{L"PROPID", SPVAT_I4, FALSE, &m_vPropId}
};
*pcTableEntries = sizeof(AETable)/sizeof(SPATTRIBENTRY);
*pTable = new SPATTRIBENTRY[*pcTableEntries];
if (*pTable)
{
memcpy(*pTable, &AETable, *pcTableEntries*sizeof(SPATTRIBENTRY));
}
else
{
hr = E_OUTOFMEMORY;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CListNode::GetPropertyNameInfoFromNode *
*------------------------------------------*
* Description:
* Get the property name info
* Returns:
* S_OK
* S_FALSE -- in case there is no property name
***************************************************************** PhilSch ***/
HRESULT CListNode::GetPropertyNameInfoFromNode(WCHAR **ppszPropName, ULONG *pulId)
{
SPDBG_FUNC("CListNode::GetPropertyNameInfoFromNode");
HRESULT hr = S_OK;
if ((VT_EMPTY == m_vPropName.vt) && (VT_EMPTY == m_vPropId.vt))
{
hr = S_FALSE;
}
else
{
*ppszPropName = (m_vPropName.vt == VT_EMPTY) ? NULL : m_vPropName.bstrVal;
*pulId = (m_vPropId.vt == VT_EMPTY) ? 0 : m_vPropId.ulVal;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CListNode::GetPropertyValueInfoFromNode *
*-------------------------------------------*
* Description:
* Get the property value info
* Returns:
* S_OK
* S_FALSE -- in case there is no property value
***************************************************************** PhilSch ***/
HRESULT CListNode::GetPropertyValueInfoFromNode(WCHAR **ppszValue, VARIANT *pvValue)
{
SPDBG_FUNC("CListNode::GetPropertyValueInfoFromNode");
HRESULT hr = S_OK;
if (VT_EMPTY == (m_vPropValue.vt | m_vPropVariantValue.vt))
{
return S_FALSE;
}
else
{
SPDBG_ASSERT(m_vPropValue.vt == VT_BSTR || m_vPropValue.vt == VT_EMPTY);
*ppszValue = (m_vPropValue.vt == VT_EMPTY) ? NULL : m_vPropValue.bstrVal;
*pvValue = m_vPropVariantValue;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CListNode::GenerateGrammarFromNode *
*------------------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CListNode::GenerateGrammarFromNode(SPSTATEHANDLE hOuterFromNode,
SPSTATEHANDLE hOuterToNode,
ISpGramCompBackend * pBackend,
CXMLTreeNode *pThis,
ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CListNode::GenerateGrammarFromNode");
HRESULT hr = S_OK;
CXMLTreeNode *pChild = pThis->m_pFirstChild;
for (ULONG i = 0; SUCCEEDED(hr) && (i < pThis->m_ulNumChildren); i++)
{
SPDBG_ASSERT(pChild);
hr = pChild->GenerateGrammar(hOuterFromNode, hOuterToNode, pBackend, pErrorLog);
if (SUCCEEDED(hr))
{
pChild = pChild->m_pNextSibling;
}
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CWildCardNode::GetTable *
*-------------------------*
* Description:
* Empty table since <WILDCARD/> doesn't have any attribute at this time.
* Returns:
* S_OK (always!!)
***************************************************************** PhilSch ***/
HRESULT CWildCardNode::GetTable(SPATTRIBENTRY **pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CWildCardNode::GetTable");
HRESULT hr = S_OK;
*pTable = NULL;
*pcTableEntries = 0;
return S_OK;
}
/****************************************************************************
* CWildCardNode::GenerateGrammarFromNode *
*------------------------------------------*
* Description:
***************************************************************** PhilSch ***/
HRESULT CWildCardNode::GenerateGrammarFromNode(SPSTATEHANDLE hOuterFromNode,
SPSTATEHANDLE hOuterToNode,
ISpGramCompBackend * pBackend,
CXMLTreeNode *pThis,
ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CWildCardNode::GenerateGrammarFromNode");
HRESULT hr = S_OK;
// this is a terminal node --> error if it has children
if (pThis->m_ulNumChildren > 0)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT(pThis->m_ulLineNumber, IDS_TERMINAL_NODE, L"WILDCARD");
}
else
{
hr = pBackend->AddRuleTransition(hOuterFromNode, hOuterToNode,
SPRULETRANS_WILDCARD, DEFAULT_WEIGHT, NULL);
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CDictationNode::GetTable *
*--------------------------*
* Description:
* Empty table since <WILDCARD/> doesn't have any attribute at this time.
* Returns:
* S_OK (always!!)
***************************************************************** PhilSch ***/
HRESULT CDictationNode::GetTable(SPATTRIBENTRY **pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CDictationNode::GetTable");
HRESULT hr = S_OK;
SPATTRIBENTRY AETable[]=
{
// pszAttribName, vtDesired, fIsFlag, pvarMember
{L"PROPNAME", SPVAT_BSTR, FALSE, &m_vPropName},
{L"PROPID", SPVAT_I4, FALSE, &m_vPropId},
{L"MIN", SPVAT_I4, FALSE, &m_vMin},
{L"MAX", SPVAT_I4, FALSE, &m_vMax},
};
*pcTableEntries = sizeof(AETable)/sizeof(SPATTRIBENTRY);
*pTable = new SPATTRIBENTRY[*pcTableEntries];
if (*pTable)
{
memcpy(*pTable, &AETable, *pcTableEntries*sizeof(SPATTRIBENTRY));
}
else
{
hr = E_OUTOFMEMORY;
}
m_vMin.vt = m_vMax.vt = VT_UI4;
m_vMin.ulVal = m_vMax.ulVal = 1;
SPDBG_REPORT_ON_FAIL( hr );
return S_OK;
}
/****************************************************************************
* CDictationNode::GenerateGrammarFromNode *
*-----------------------------------------*
* Description:
***************************************************************** PhilSch ***/
HRESULT CDictationNode::GenerateGrammarFromNode(SPSTATEHANDLE hOuterFromNode,
SPSTATEHANDLE hOuterToNode,
ISpGramCompBackend * pBackend,
CXMLTreeNode *pThis,
ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CDictationNode::GenerateGrammarFromNode");
HRESULT hr = S_OK;
// this is a terminal node --> error if it has children
if (pThis->m_ulNumChildren > 0)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT(pThis->m_ulLineNumber, IDS_TERMINAL_NODE, L"DICTATION");
}
else
{
SPPROPERTYINFO prop;
memset(&prop, 0, sizeof(SPPROPERTYINFO));
BOOL fHasProperty = FALSE;
if (S_OK == pThis->GetPropertyNameInfo(const_cast<WCHAR**>(&prop.pszName), &prop.ulId))
{
fHasProperty = TRUE;
}
if (m_vPropName.vt == VT_BSTR)
{
prop.pszName = m_vPropName.bstrVal;
fHasProperty = TRUE;
}
if (m_vPropId.vt == VT_UI4)
{
prop.ulId = m_vPropId.ulVal;
fHasProperty = TRUE;
}
if (m_vMin.vt == VT_EMPTY)
{
m_vMin.ulVal = 1;
m_vMin.vt = VT_UI4;
}
if (m_vMax.vt == VT_EMPTY)
{
m_vMax.ulVal = 1;
m_vMax.vt = VT_UI4;
}
if (m_vMax.ulVal == 0)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT2(pThis->m_ulLineNumber, IDS_INCORR_ATTRIB_VALUE, 0, L"MAX");
}
if (SUCCEEDED(hr) && (m_vMin.uiVal > m_vMax.uiVal))
{
hr = SPERR_STGF_ERROR;
m_vMin.ChangeType(VT_BSTR);
m_vMax.ChangeType(VT_BSTR);
LOGERRORFMT2(pThis->m_ulLineNumber, IDS_MIN_MAX_ERROR, m_vMin.bstrVal, m_vMax.bstrVal);
}
// NTRAID#SPEECH-7344-2000/08/22-philsch: map INF to self-loop rather than repeat ...
SPSTATEHANDLE hFromNode = hOuterFromNode;
SPSTATEHANDLE hToNode = NULL;
if (SUCCEEDED(hr))
{
// construct self loop if INF repetitions
if ((m_vMin.uiVal < 2) && (m_vMax.uiVal == 255))
{
// create temporary node
hr = pBackend->CreateNewState(hFromNode, &hToNode);
if (SUCCEEDED(hr))
{
hr = pBackend->AddRuleTransition(hFromNode, hToNode,
SPRULETRANS_DICTATION, DEFAULT_WEIGHT, (fHasProperty)? &prop :NULL);
}
// create the self loop now
if (SUCCEEDED(hr))
{
hr = pBackend->AddRuleTransition(hToNode, hToNode,
SPRULETRANS_DICTATION, DEFAULT_WEIGHT, (fHasProperty)? &prop :NULL);
}
// create an epsilon transition to hOuterToNode
if (SUCCEEDED(hr))
{
hr = pBackend->AddWordTransition(hToNode, hOuterToNode, NULL, NULL, SPWT_LEXICAL, 1.0f, NULL);
}
// add epsilon if min == 0
if (SUCCEEDED(hr) && (m_vMin.uiVal == 0))
{
hr = pBackend->AddWordTransition(hOuterFromNode, hOuterToNode, NULL, NULL, SPWT_LEXICAL, 1.0f, NULL);
}
}
else
{
for (ULONG i = 0; SUCCEEDED(hr) && (i < m_vMax.uiVal); i++)
{
// add epsilon transitions to hOuterToNode once we reach max - min ...
if (i < (ULONG)(m_vMax.uiVal - 1))
{
hr = pBackend->CreateNewState(hFromNode, &hToNode);
}
else
{
hToNode = hOuterToNode;
}
if (SUCCEEDED(hr))
{
hr = pBackend->AddRuleTransition(hFromNode, hToNode,
SPRULETRANS_DICTATION, DEFAULT_WEIGHT, (fHasProperty)? &prop :NULL);
}
if (i >= m_vMin.uiVal)
{
hr = pBackend->AddWordTransition(hFromNode, hOuterToNode, NULL, NULL, SPWT_LEXICAL, 1.0f, NULL);
}
if (SUCCEEDED(hr))
{
hFromNode = hToNode;
}
}
}
}
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CTextBufferNode::GetPropertyNameInfoFromNode *
*----------------------------------------------*
* Description:
* Get the property name info
* Returns:
* S_OK
* S_FALSE -- in case there is no property name
***************************************************************** PhilSch ***/
HRESULT CDictationNode::GetPropertyNameInfoFromNode(WCHAR **ppszPropName, ULONG *pulId)
{
SPDBG_FUNC("CDictationNode::GetPropertyNameInfoFromNode");
HRESULT hr = S_OK;
if ((VT_EMPTY == m_vPropName.vt) && (VT_EMPTY == m_vPropId.vt))
{
hr = S_FALSE;
}
else
{
*ppszPropName = (m_vPropName.vt == VT_BSTR) ? m_vPropName.bstrVal : NULL;
*pulId = (m_vPropId.vt == VT_UI4) ? m_vPropId.ulVal : 0;
}
return hr;
}
/****************************************************************************
* CLeafNode::GetTable *
*---------------------*
* Description:
* single line so we can store result in m_vText!
* Returns:
* S_OK (always!!)
***************************************************************** PhilSch ***/
HRESULT CLeafNode::GetTable(SPATTRIBENTRY **pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CLeafNode::GetTable");
HRESULT hr = S_OK;
SPATTRIBENTRY AETable[]=
{
// pszAttribName, vtDesired, fIsFlag, pvarMember
{NULL, SPVAT_BSTR, FALSE, &m_vText}
};
*pcTableEntries = sizeof(AETable)/sizeof(SPATTRIBENTRY);
SPDBG_ASSERT(*pcTableEntries == 1);
*pTable = new SPATTRIBENTRY[*pcTableEntries];
if (*pTable)
{
memcpy(*pTable, &AETable, *pcTableEntries*sizeof(SPATTRIBENTRY));
}
else
{
hr = E_OUTOFMEMORY;
}
return S_OK;
}
/****************************************************************************
* CRuleRefNode::GetTable *
*-----------------------*
* Description:
* Returns attribute table for <RULEREF>
* Returns:
* S_OK, E_OUTOFMEMORY
***************************************************************** PhilSch ***/
HRESULT CRuleRefNode::GetTable(SPATTRIBENTRY ** pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CRuleRefNode::GetTable");
HRESULT hr = S_OK;
SPATTRIBENTRY AETable[]=
{
// pszAttribName, vtDesired, fIsFlag, pvarMember
{L"NAME", SPVAT_BSTR, FALSE, &m_vRuleRefName},
{L"REFID", SPVAT_I4, FALSE, &m_vRuleRefId},
{L"OBJECT", SPVAT_BSTR, FALSE, &m_vObject},
{L"URL", SPVAT_BSTR, FALSE, &m_vURL},
{L"PROPNAME", SPVAT_BSTR, FALSE, &m_vPropName},
{L"PROPID", SPVAT_I4, FALSE, &m_vPropId},
{L"VAL", SPVAT_I4, FALSE, &m_vPropVariantValue},
{L"VALSTR", SPVAT_BSTR, FALSE, &m_vPropValue},
{L"WEIGHT", SPVAT_NUMERIC, FALSE, &m_vWeight}
};
*pcTableEntries = sizeof(AETable)/sizeof(SPATTRIBENTRY);
*pTable = new SPATTRIBENTRY[*pcTableEntries];
if (*pTable)
{
memcpy(*pTable, &AETable, *pcTableEntries*sizeof(SPATTRIBENTRY));
}
else
{
hr = E_OUTOFMEMORY;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CRuleRefNode::PostProcess *
*--------------------------*
* Description:
* Initialize the weight if it's not already set (need to be empty
* initially to detect redefinition of its value!)
* Returns:
* S_OK
***************************************************************** PhilSch ***/
HRESULT CRuleRefNode::PostProcess(ISpGramCompBackend * pBackend,
CSpBasicQueue<CInitialRuleState> * pInitialRuleStateList,
CSpBasicQueue<CDefineValue> * pDefineValueList,
ULONG ulLineNumber, CXMLTreeNode * pThis, ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CRuleRefNode::PostProcess");
HRESULT hr = S_OK;
if (m_vWeight.vt == VT_EMPTY)
{
m_vWeight = 1.0f;
}
else if (m_vWeight.fltVal < 0.0)
{
hr = SPERR_STGF_ERROR;
m_vWeight.ChangeType(VT_BSTR);
LOGERRORFMT2(ulLineNumber, IDS_INCORR_ATTRIB_VALUE, m_vWeight.bstrVal, L"WEIGHT");
}
return hr;
}
/****************************************************************************
* CRuleRefNode::GetPropertyNameInfoFromNode *
*------------------------------------------*
* Description:
* Get the property name info
* Returns:
* S_OK
* S_FALSE -- in case there is no property name
***************************************************************** PhilSch ***/
HRESULT CRuleRefNode::GetPropertyNameInfoFromNode(WCHAR **ppszPropName, ULONG *pulId)
{
SPDBG_FUNC("CRuleRefNode::GetPropertyNameInfoFromNode");
HRESULT hr = S_OK;
if ((VT_EMPTY == m_vPropName.vt) && (VT_EMPTY == m_vPropId.vt))
{
hr = S_FALSE;
}
else
{
*ppszPropName = (m_vPropName.vt == VT_BSTR) ? m_vPropName.bstrVal : NULL;
*pulId = (m_vPropId.vt == VT_UI4) ? m_vPropId.ulVal : 0;
}
return hr;
}
/****************************************************************************
* CRuleRefNode::GetPropertyValueInfoFromNode *
*-------------------------------------------*
* Description:
* Get the property value info
* Returns:
* S_OK
* S_FALSE -- in case there is no property value
***************************************************************** PhilSch ***/
HRESULT CRuleRefNode::GetPropertyValueInfoFromNode(WCHAR **ppszValue, VARIANT *pvValue)
{
SPDBG_FUNC("CRuleRefNode::GetPropertyValueInfoFromNode");
HRESULT hr = S_OK;
if (VT_EMPTY == (m_vPropValue.vt | m_vPropVariantValue.vt))
{
return S_FALSE;
}
else
{
SPDBG_ASSERT(m_vPropValue.vt == VT_BSTR || m_vPropValue.vt == VT_EMPTY);
*ppszValue = (m_vPropValue.vt == VT_EMPTY) ? NULL : m_vPropValue.bstrVal;
*pvValue = m_vPropVariantValue;
}
return hr;
}
/****************************************************************************
* CRuleRefNode::SetPropertyInfo *
*------------------------------*
* Description:
* Sets the property info if it has one
* Returns:
* S_OK, SPERR_STGF_ERROR --
* fHasProperty -- used to determine if we need an epsilon transition
***************************************************************** PhilSch ***/
HRESULT CRuleRefNode::SetPropertyInfo(SPPROPERTYINFO *p, CXMLTreeNode * pParent, BOOL *pfHasProperty, ULONG ulLineNumber, ISpErrorLog *pErrorLog)
{
SPDBG_FUNC("CRuleRefNode::SetPropertyInfo");
HRESULT hr = S_OK;
hr = GetPropertyNameInfoFromNode(const_cast<WCHAR**>(&p->pszName), &p->ulId);
*pfHasProperty = (S_OK == hr) ? TRUE : FALSE;
if (S_OK == hr)
{
hr = GetPropertyValueInfoFromNode(const_cast<WCHAR**>(&p->pszValue), &p->vValue);
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CRuleRefNode::GenerateGrammarFromNode *
*---------------------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CRuleRefNode::GenerateGrammarFromNode(SPSTATEHANDLE hOuterFromNode,
SPSTATEHANDLE hOuterToNode,
ISpGramCompBackend * pBackend,
CXMLTreeNode *pThis,
ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CRuleRefNode::GenerateGrammarFromNode");
HRESULT hr = S_OK;
// this is a terminal node --> error if it has children
if (pThis->m_ulNumChildren > 0)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT(pThis->m_ulLineNumber, IDS_TERMINAL_NODE, L"RULEREF");
}
else
{
SPPROPERTYINFO prop;
memset(&prop, 0, sizeof(SPPROPERTYINFO));
BOOL fHasProperty = FALSE;
if (S_OK == pThis->GetPropertyNameInfo(const_cast<WCHAR**>(&prop.pszName), &prop.ulId))
{
fHasProperty = TRUE;
}
hr = pThis->GetPropertyValueInfo(const_cast<WCHAR**>(&prop.pszValue), &prop.vValue);
// get the handle of the target rule
SPSTATEHANDLE hTargetRule = 0;
if (SUCCEEDED(hr))
{
hr = GetTargetRuleHandle(pBackend, &hTargetRule);
}
if (SUCCEEDED(hr))
{
hr = pBackend->AddRuleTransition(hOuterFromNode, hOuterToNode, hTargetRule,
m_vWeight.fltVal, fHasProperty ? &prop : NULL);
}
else
{
m_vRuleRefName.ChangeType(VT_BSTR);
m_vRuleRefId.ChangeType(VT_BSTR);
hr = SPERR_STGF_ERROR;
LOGERRORFMT2(pThis->m_ulLineNumber, IDS_INVALID_RULEREF, m_vRuleRefName.bstrVal, m_vRuleRefId.bstrVal);
}
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CRuleRefNode::GetWeightFromNode *
*--------------------------------------*
* Description:
*
* Because ExtractVirant would convert the attribute value to VT_UI4, next VT_I4, then VT_R4, at last VT_R8
* We need to convert the value back. We would loose precision for VT_R8
*
* Returns:
*
***************************************************************** PhilSch ***/
float CRuleRefNode::GetWeightFromNode() {
if (m_vWeight.vt != VT_R8)
{
m_vWeight.ChangeType(VT_R4, NULL);
return m_vWeight.fltVal;
}
else
{
return (float)m_vWeight.dblVal;
}
}
/****************************************************************************
* CRuleRefNode::GetTargetRuleHandle *
*-----------------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CRuleRefNode::GetTargetRuleHandle(ISpGramCompBackend * pBackend, SPSTATEHANDLE *phTarget)
{
SPDBG_FUNC("CRuleRefNode::GetTargetRuleHandle");
HRESULT hr = S_OK;
if ((m_vRuleRefName.vt != VT_BSTR) && (m_vRuleRefId.vt == VT_EMPTY))
{
return SPERR_STGF_ERROR;
}
CSpDynamicString dstr;
BOOL fImport = FALSE;
if (m_vRuleRefName.vt == VT_BSTR)
{
if (m_vObject.vt == VT_BSTR)
{
// check to see if this can be converted into a REFCLSID
if (IsValidREFCLSID(m_vObject.bstrVal))
{
dstr.Append2(L"SAPI5OBJECT:", m_vObject.bstrVal);
dstr.Append2(L"\\\\", m_vRuleRefName.bstrVal);
fImport = TRUE;
}
else
{
hr = SPERR_STGF_ERROR;
}
}
else if (m_vURL.vt == VT_BSTR)
{
// check to see if this can be converted into a GUID
if (IsValidURL(m_vURL.bstrVal))
{
dstr.Append2(L"URL:", m_vURL.bstrVal);
dstr.Append2(L"\\\\", m_vRuleRefName.bstrVal);
fImport = TRUE;
}
else
{
hr = SPERR_STGF_ERROR;
}
}
else
{
dstr.Append(m_vRuleRefName.bstrVal);
}
}
if (SUCCEEDED(hr))
{
hr = pBackend->GetRule((m_vRuleRefName.vt == VT_EMPTY)? NULL : dstr.m_psz,
(m_vRuleRefId.vt == VT_EMPTY) ? 0 : m_vRuleRefId.ulVal,
fImport ? SPRAF_Import : 0, fImport, phTarget);
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CLeafNode::GenerateGrammarFromNode *
*------------------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CLeafNode::GenerateGrammarFromNode(SPSTATEHANDLE hOuterFromNode,
SPSTATEHANDLE hOuterToNode,
ISpGramCompBackend * pBackend,
CXMLTreeNode *pThis,
ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CLeafNode::GenerateGrammarFromNode");
HRESULT hr = S_OK;
SPPROPERTYINFO prop;
memset(&prop, 0, sizeof(SPPROPERTYINFO));
BOOL fHasProperty = FALSE;
WCHAR *p = m_vText.bstrVal;
ULONG ulLen = wcslen(p);
WCHAR *q = p + ulLen -1;
for (ULONG i = 0; iswspace(*p) && (i < ulLen); i++, p++);
for (ULONG j = 0; iswspace(*q) && (p < q) && (j < ulLen); j++, q--);
ULONG cnt = ulLen - j - i;
CComBSTR bstr(cnt, m_vText.bstrVal + i);
if (pThis->m_pNodeFactory->m_wcDelimiter != L'/')
{
WCHAR *pStr = STACK_ALLOC(WCHAR, 2*(ulLen +1)); // to be on the save size
// convert "|D|L|P;" to "/D/L/P;" note that D could contain unescaped '/'
ULONG ulNumSepFound = 0;
bstr.Empty();
p = m_vText.bstrVal + i;
q = pStr;
for (ULONG k = 0; k < cnt; k++, p++, q++)
{
// don't replace any of the separators if we have seen 3 of them - we are
// now copying pronunciation strings
if ((*p == pThis->m_pNodeFactory->m_wcDelimiter) && ( ulNumSepFound < 3))
{
*q = L'/';
}
else if ((*p == L'/') || (*p == L'\\') && (ulNumSepFound != 3))
{
// needs to be escaped now
*(q++) = L'\\';
*q = *p;
}
else
{
*q = *p;
if (*p == L';')
{
ulNumSepFound = 0;
}
}
}
*q = 0;
bstr = pStr;
}
if (S_FALSE == pThis->m_pParent->GetPropertyNameInfo(const_cast<WCHAR**>(&prop.pszName), &prop.ulId))
{
hr = pThis->m_pParent->m_pParent->GetPropertyNameInfo(const_cast<WCHAR**>(&prop.pszName), &prop.ulId);
}
HRESULT hrVal = pThis->m_pParent->GetPropertyValueInfo(const_cast<WCHAR**>(&prop.pszValue), &prop.vValue);
if (S_FALSE == hr && S_OK == hrVal)
{
hr = SPERR_STGF_ERROR;
CComVariant var(prop.vValue);
var.ChangeType(VT_BSTR);
LOGERRORFMT2(pThis->m_ulLineNumber, IDS_MISSING_PROPERTY_NAME, prop.pszValue, var.bstrVal);
}
else
{
fHasProperty = (S_OK == hr) ? TRUE : FALSE;
}
if (SUCCEEDED(hr))
{
WCHAR *pszPron = NULL;
WCHAR *pszDisp = NULL;
hr = pThis->m_pParent->GetPronAndDispInfo(&pszPron, &pszDisp);
if (S_OK == hr)
{
// trim the string first
ULONG ulLen = wcslen(bstr);
WCHAR * psz = STACK_ALLOC(WCHAR, ulLen + 1);
WCHAR * pszEnd = psz + ulLen-1;
memcpy(psz, bstr, (ulLen +1) *sizeof(*psz));
// trim from the front
while(iswspace(*psz))
{
psz++;
}
// trim from the back
while((psz < pszEnd) && iswspace(*pszEnd))
{
pszEnd--;
}
*(pszEnd+1) = 0;
// skip over leading + and ? before doing the check
if (psz &&
((psz[0] == pThis->m_pNodeFactory->m_wcDelimiter) ||
( fIsSpecialChar(psz[0]) &&
((psz[1] == pThis->m_pNodeFactory->m_wcDelimiter)) ||
(fIsSpecialChar(psz[1]) && (psz[2] == pThis->m_pNodeFactory->m_wcDelimiter)))))
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT(pThis->m_ulLineNumber, IDS_CUSTOM_PRON_EXISTS, psz);
}
else if (wcsstr(psz, pThis->m_pNodeFactory->m_pszSeparators))
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT(pThis->m_ulLineNumber, IDS_PRON_SINGLE_WORD, psz);
}
if (SUCCEEDED(hr))
{
CComBSTR bstr1(L"/");
if (pszDisp)
{
bstr1.Append(pszDisp);
}
bstr1.Append(L"/");
bstr1.Append(psz);
bstr1.Append(L"/");
if (pszPron)
{
bstr1.Append(pszPron);
}
bstr1.Append(L";");
bstr = bstr1.Detach();
}
}
}
if (SUCCEEDED(hr))
{
hr = pBackend->AddWordTransition(hOuterFromNode, hOuterToNode,
bstr, pThis->m_pNodeFactory->m_pszSeparators,
SPWT_LEXICAL, pThis->m_pParent->GetWeight(), fHasProperty ? &prop : NULL);
}
if (SPERR_WORDFORMAT_ERROR == hr)
{
LOGERRORFMT(pThis->m_ulLineNumber, IDS_INCORR_WORDFORMAT, bstr);
}
else if (SPERR_AMBIGUOUS_PROPERTY == hr)
{
CComVariant var;
var.vt = VT_UI4;
var.ulVal = prop.ulId;
var.ChangeType(VT_BSTR);
LOGERRORFMT2(pThis->m_ulLineNumber, IDS_AMBIGUOUS_PROPERTY, prop.pszName, var.bstrVal);
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CResourceNode::GetTable *
*-------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CResourceNode::GetTable(SPATTRIBENTRY ** pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CResourceNode::GetTable");
HRESULT hr = S_OK;
SPATTRIBENTRY AETable[]=
{
// pszAttribName, vtDesired, fIsFlag, pvarMember
{L"NAME", SPVAT_BSTR, FALSE, &m_vName}
};
*pcTableEntries = sizeof(AETable)/sizeof(SPATTRIBENTRY);
*pTable = new SPATTRIBENTRY[*pcTableEntries];
if (*pTable)
{
memcpy(*pTable, &AETable, *pcTableEntries*sizeof(SPATTRIBENTRY));
}
else
{
hr = E_OUTOFMEMORY;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CResourceNode::PostProcess *
*----------------------------*
* Description:
* Resets the compiler backend to the m_vLangId
* Returns:
* S_FALSE -- so we don't add it to the node tree
***************************************************************** PhilSch ***/
HRESULT CResourceNode::PostProcess(ISpGramCompBackend * pBackend,
CSpBasicQueue<CInitialRuleState> * pInitialRuleStateList,
CSpBasicQueue<CDefineValue> * pDefineValueList,
ULONG ulLineNumber, CXMLTreeNode * pThis, ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CResourceNode::PostProcess");
HRESULT hr = S_OK;
if (m_vName.vt == VT_EMPTY)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT2(ulLineNumber, IDS_MISSING_REQUIRED_ATTRIBUTE, L"NAME", L"RESOURCE");
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CResourceNode::GetPropertyValueInfoFromNode *
*---------------------------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CResourceNode::GetPropertyValueInfoFromNode(WCHAR **ppszValue, VARIANT *pvValue)
{
SPDBG_FUNC("CResourceNode::GetPropertyValueInfoFromNode");
*ppszValue = m_vName.bstrVal;
pvValue->bstrVal = m_vText.bstrVal;
pvValue->vt = VT_BSTR;
return S_OK;
}
/****************************************************************************
* CResourceNode::AddResourceValue *
*---------------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CResourceNode::AddResourceValue(const WCHAR *pszResourceValue, ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CResourceNode::AddResourceValue");
HRESULT hr = S_OK;
CComBSTR bstr(pszResourceValue);
if (bstr)
{
m_vText.bstrVal = bstr.Detach();
m_vText.vt = VT_BSTR;
}
else
{
hr = E_OUTOFMEMORY;
LOGERRORFMT( -1, IDS_PARSER_INTERNAL_ERROR, L"E_OUTOFMEMORY");
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CTextBufferNode::GetTable *
*---------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CTextBufferNode::GetTable(SPATTRIBENTRY ** pTable, ULONG *pcTableEntries)
{
SPDBG_FUNC("CTextBufferNode::GetTable");
HRESULT hr = S_OK;
SPATTRIBENTRY AETable[]=
{
// pszAttribName, vtDesired, fIsFlag, pvarMember
{L"PROPNAME", SPVAT_BSTR, FALSE, &m_vPropName},
{L"PROPID", SPVAT_I4, FALSE, &m_vPropId},
{L"WEIGHT", SPVAT_NUMERIC, FALSE, &m_vWeight}
};
*pcTableEntries = sizeof(AETable)/sizeof(SPATTRIBENTRY);
*pTable = new SPATTRIBENTRY[*pcTableEntries];
if (*pTable)
{
memcpy(*pTable, &AETable, *pcTableEntries*sizeof(SPATTRIBENTRY));
}
else
{
hr = E_OUTOFMEMORY;
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CTextBufferNode::GetPropertyNameInfoFromNode *
*----------------------------------------------*
* Description:
* Get the property name info
* Returns:
* S_OK
* S_FALSE -- in case there is no property name
***************************************************************** PhilSch ***/
HRESULT CTextBufferNode::GetPropertyNameInfoFromNode(WCHAR **ppszPropName, ULONG *pulId)
{
SPDBG_FUNC("CTextBufferNode::GetPropertyNameInfoFromNode");
HRESULT hr = S_OK;
if ((VT_EMPTY == m_vPropName.vt) && (VT_EMPTY == m_vPropId.vt))
{
hr = S_FALSE;
}
else
{
*ppszPropName = (m_vPropName.vt == VT_BSTR) ? m_vPropName.bstrVal : NULL;
*pulId = (m_vPropId.vt == VT_UI4) ? m_vPropId.ulVal : 0;
}
return hr;
}
/****************************************************************************
* CTextBufferNode::GenerateGrammarFromNode *
*------------------------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CTextBufferNode::GenerateGrammarFromNode(SPSTATEHANDLE hOuterFromNode,
SPSTATEHANDLE hOuterToNode,
ISpGramCompBackend * pBackend,
CXMLTreeNode *pThis,
ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CTextBufferNode::GenerateGrammarFromNode");
HRESULT hr = S_OK;
// this is a terminal node --> error if it has children
if (pThis->m_ulNumChildren > 0)
{
hr = SPERR_STGF_ERROR;
LOGERRORFMT(pThis->m_ulLineNumber, IDS_TERMINAL_NODE, L"TEXTBUFFER");
}
else
{
SPPROPERTYINFO prop;
memset(&prop, 0, sizeof(SPPROPERTYINFO));
BOOL fHasProperty = FALSE;
if (S_OK == pThis->GetPropertyNameInfo(const_cast<WCHAR**>(&prop.pszName), &prop.ulId))
{
fHasProperty = TRUE;
}
// get the handle of the target rule
if (SUCCEEDED(hr))
{
hr = pBackend->AddRuleTransition(hOuterFromNode, hOuterToNode, SPRULETRANS_TEXTBUFFER,
m_vWeight.fltVal, fHasProperty? &prop : NULL);
}
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CTextBufferNode::PostProcess *
*------------------------------*
* Description:
* Initialize the weight if it's not already set (need to be empty
* initially to detect redefinition of its value!)
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CTextBufferNode::PostProcess(ISpGramCompBackend * pBackend,
CSpBasicQueue<CInitialRuleState> * pInitialRuleStateList,
CSpBasicQueue<CDefineValue> * pDefineValueList,
ULONG ulLineNumber, CXMLTreeNode * pThis, ISpErrorLog * pErrorLog)
{
SPDBG_FUNC("CTextBufferNode::PostProcess");
HRESULT hr = S_OK;
if (m_vWeight.vt == VT_EMPTY)
{
m_vWeight = 1.0f;
}
else if (m_vWeight.fltVal < 0.0)
{
hr = SPERR_STGF_ERROR;
m_vWeight.ChangeType(VT_BSTR);
LOGERRORFMT2(ulLineNumber, IDS_INCORR_ATTRIB_VALUE, m_vWeight.bstrVal, L"WEIGHT");
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
// --------------------------------------------------------------------------------
// Node Factory for IXMLParser
// --------------------------------------------------------------------------------
/****************************************************************************
* CNodeFactory::CreateNode *
*--------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CNodeFactory::CreateNode(IXMLNodeSource * pSource, PVOID pNodeParent, USHORT cNumRecs, XML_NODE_INFO ** apNodeInfo)
{
SPDBG_FUNC("CNodeFactory::CreateNode");
HRESULT hr = S_OK;
CXMLTreeNode * pNode = NULL;
ISpErrorLog *pErrorLog = m_pErrorLog; // needed for LOGERRORFMT macro
if (pNodeParent && (((CXMLTreeNode*)pNodeParent)->m_eType == SPXML_ID))
{
// <ID> cannot have any children
hr = SPERR_STGF_ERROR;
LOGERRORFMT(pSource->GetLineNumber(), IDS_TERMINAL_NODE, L"ID");
}
else
{
switch (apNodeInfo[0]->dwType)
{
case XML_DOCTYPE:
case XML_COMMENT:
case XML_XMLDECL:
case XML_PI:
break;
case XML_CDATA:
{
if (pNodeParent && ((CXMLTreeNode*)pNodeParent)->m_eType == SPXML_RESOURCE)
{
CComBSTR bstrResourceValue(apNodeInfo[0]->ulLen, apNodeInfo[0]->pwcText);
CXMLNode<CResourceNode> *pResNode = (CXMLNode<CResourceNode> *)pNodeParent;
if (bstrResourceValue)
{
hr = pResNode->AddResourceValue(bstrResourceValue, pErrorLog);
}
else
{
hr = E_OUTOFMEMORY;
LOGERRORFMT( -1, IDS_PARSER_INTERNAL_ERROR, L"E_OUTOFMEMORY");
}
}
else
{
// CDATA has to be direct child of <RESOURCE>
hr = SPERR_STGF_ERROR;
LOGERRORFMT2( pSource->GetLineNumber(), IDS_CONTAINMENT_ERROR, L"CDATA", L"RESOURCE");
}
break;
}
case XML_PCDATA:
{
if (pNodeParent &&
(((CXMLTreeNode*)pNodeParent)->m_eType != SPXML_PHRASE) &&
((((CXMLTreeNode*)pNodeParent)->m_eType != SPXML_OPT)))
{
if (IsAllWhiteSpace(apNodeInfo[0]->pwcText, apNodeInfo[0]->ulLen))
{
break;
}
else
{
hr = SPERR_STGF_ERROR;
if (((CXMLTreeNode*)pNodeParent)->m_eType == SPXML_RESOURCE)
{
LOGERRORFMT2( pSource->GetLineNumber(), IDS_CONTAINMENT_ERROR, L"CDATA", L"PHRASE");
}
else
{
LOGERRORFMT2( pSource->GetLineNumber(), IDS_CONTAINMENT_ERROR, L"text", L"PHRASE");
}
break;
}
}
}
case XML_ELEMENT:
{
// find the correct NodeTableEntry
for (ULONG i = 0; i < m_cXMLNodeEntries; i++)
{
if ((wcsicmp(m_pXMLNodeTable[i].pszNodeName, apNodeInfo[0]->pwcText) == 0) ||
(apNodeInfo[0]->fTerminal && (m_pXMLNodeTable[i].eXMLNodeType == SPXML_LEAF)))
{
// only create a new node if the parent doesn't already have a SPXML_LEAF
if ((m_pXMLNodeTable[i].eXMLNodeType == SPXML_LEAF) && pNodeParent &&
((((CXMLTreeNode*)pNodeParent)->m_eType == SPXML_PHRASE) ||
(((CXMLTreeNode*)pNodeParent)->m_eType == SPXML_OPT)))
{
CXMLTreeNode *pParent = (CXMLTreeNode *)pNodeParent;
if (pParent && (pParent->m_ulNumChildren > 0))
{
for(CXMLTreeNode *pChild = pParent->m_pFirstChild;
pChild && pChild->m_pNextSibling;
pChild = pChild->m_pNextSibling);
if (pChild && pChild->m_eType == SPXML_LEAF)
{
CXMLNode<CLeafNode> *pLeafNode = (CXMLNode<CLeafNode>*)pChild;
if (pLeafNode)
{
CComBSTR bstr(pLeafNode->m_vText.bstrVal);
::SysFreeString(pLeafNode->m_vText.bstrVal);
CComBSTR bstrNew(apNodeInfo[0]->ulLen, apNodeInfo[0]->pwcText);
bstr.Append(bstrNew);
pLeafNode->m_vText.bstrVal = bstr.Detach();
break;
}
}
}
}
pNode = m_pXMLNodeTable[i].pfnCreateFunc();
if (pNode)
{
m_NodeList.AddNode(pNode);
pNode->m_eType = m_pXMLNodeTable[i].eXMLNodeType;
pNode->m_pNodeFactory = this;
pNode->m_ulLineNumber = pSource->GetLineNumber();
hr = pNode->ProcessAttribs(cNumRecs, apNodeInfo,
m_cpBackend,
&m_InitialRuleStateList,
&m_DefineValueList,
m_pErrorLog);
}
else
{
hr = E_OUTOFMEMORY;
}
break;
}
}
if (i == m_cXMLNodeEntries)
{
hr = SPERR_STGF_ERROR;
ISpErrorLog *pErrorLog = m_pErrorLog; // needed for LOGERRORFMT macro
LOGERRORFMT(pSource->GetLineNumber(), IDS_UNKNOWN_TAG, apNodeInfo[0]->pwcText);
}
}
break;
default:
break;
}
}
if (SUCCEEDED(hr) && pNodeParent && pNode)
{
apNodeInfo[0]->pNode = pNode;
hr = ((CXMLTreeNode*)pNodeParent)->AddChild(pNode);
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CNodeFactory::BeginChildren *
*-----------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CNodeFactory::BeginChildren(IXMLNodeSource * pSource, XML_NODE_INFO * pNodeInfo)
{
SPDBG_FUNC("CNodeFactory::BeginChildren");
return S_OK;
}
/****************************************************************************
* CNodeFactory::EndChildren *
*---------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CNodeFactory::EndChildren(IXMLNodeSource * pSource, BOOL fEmptyNode, XML_NODE_INFO * pNodeInfo)
{
SPDBG_FUNC("CNodeFactory::EndChildren");
return S_OK;
}
/****************************************************************************
* CNodeFactory::NotifyEvent *
*---------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CNodeFactory::NotifyEvent(IXMLNodeSource * pSource, XML_NODEFACTORY_EVENT iEvt)
{
SPDBG_FUNC("CNodeFactory::NotifyEvent");
return S_OK;
}
/****************************************************************************
* CNodeFactory::Error *
*---------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CNodeFactory::Error(IXMLNodeSource * pSource, HRESULT hrErrorCode, USHORT cNumRecs, XML_NODE_INFO ** apNodeInfo)
{
SPDBG_FUNC("CNodeFactory::Error");
HRESULT hr = S_OK;
if (SP_IS_BAD_INTERFACE_PTR(pSource))
{
SPDBG_REPORT_ON_FAIL( hr );
return E_INVALIDARG;
}
if (hrErrorCode == SPERR_STGF_ERROR)
{
return S_OK;
}
ISpErrorLog *pErrorLog = m_pErrorLog; // needed in macro
ULONG ulLine = pSource->GetLineNumber();
CComBSTR bstrErrorInfo;
hr = pSource->GetErrorInfo(&bstrErrorInfo);
if (SUCCEEDED(hr))
{
//
// remove the .\r\n from the BSTR.
//
bstrErrorInfo.m_str[ bstrErrorInfo.Length() - 3 ] = 0;
hr = SPERR_STGF_ERROR;
LOGERRORFMT( ulLine, IDS_XML_FORMAT_ERROR, bstrErrorInfo);
}
else
{
hr = E_OUTOFMEMORY;
LOGERRORFMT( ulLine, IDS_PARSER_INTERNAL_ERROR, L"<out of memory>");
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CNodeFactory::IsAllWhiteSpace *
*-------------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
BOOL CNodeFactory::IsAllWhiteSpace(const WCHAR * pszText, const ULONG ulLen)
{
for(DWORD i = 0; pszText && (i < ulLen); i++, pszText++)
{
if (!iswspace(*pszText) && (*pszText != L'\x3000'))
{
return FALSE;
}
}
return TRUE;
}
/****************************************************************************
* CGramFrontEnd::WriteDefines *
*-----------------------------*
* Description:
*
* Returns:
*
***************************************************************** PhilSch ***/
HRESULT CGramFrontEnd::WriteDefines(IStream * pHeader)
{
SPDBG_FUNC("CGramFrontEnd::WriteDefines()");
HRESULT hr = S_OK;
USES_CONVERSION;
for (CDefineValue *pTok = m_pNodeFactory->m_DefineValueList.GetHead(); SUCCEEDED(hr) && pTok; pTok = pTok->m_pNext)
{
TCHAR szDefine[256];
switch (pTok->m_vValue.vt)
{
case VT_R8:
wsprintf(szDefine, _T("#define %s %e\r\n"), W2T(pTok->m_dstrIdName), (double)pTok->m_vValue.dblVal);
break;
case VT_R4:
wsprintf(szDefine, _T("#define %s %ff\r\n"), W2T(pTok->m_dstrIdName), (float)pTok->m_vValue.fltVal);
break;
case VT_INT:
wsprintf(szDefine, _T("#define %s %d\r\n"), W2T(pTok->m_dstrIdName), pTok->m_vValue.intVal);
break;
case VT_UINT:
wsprintf(szDefine, _T("#define %s %d\r\n"), W2T(pTok->m_dstrIdName), pTok->m_vValue.uintVal);
break;
case VT_I4:
wsprintf(szDefine, _T("#define %s %d\r\n"), W2T(pTok->m_dstrIdName), pTok->m_vValue.lVal);
break;
case VT_UI4:
wsprintf(szDefine, _T("#define %s %d\r\n"), W2T(pTok->m_dstrIdName), pTok->m_vValue.ulVal);
break;
case VT_BOOL:
wsprintf(szDefine, _T("#define %s %s\r\n"), W2T(pTok->m_dstrIdName), pTok->m_vValue.boolVal ? "L\"TRUE\"" : "L\"FALSE\"");
break;
default:
SPDBG_ASSERT(false); // did we miss a type??
}
hr = WriteStream(pHeader, T2A(szDefine));
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}
/****************************************************************************
* CGramFrontEnd::CompileStream *
*------------------------------*
* Description:
* Loads the XML file into the DOM. Also loads the XML that contains the
* <DEFINE> in case it is different from the main file (specified via -d).
*
* Returns:
*
***************************************************************** PhilSch ***/
STDMETHODIMP CGramFrontEnd::CompileStream(IStream *pSource, IStream *pDest,
IStream *pHeader, IUnknown *pReserved,
ISpErrorLog * pErrorLog, DWORD dwFlags)
{
SPDBG_FUNC("CGramFrontEnd::CompileStream");
HRESULT hr = S_OK;
SPAUTO_OBJ_LOCK;
m_LangId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
// parameter checking
if (SP_IS_BAD_INTERFACE_PTR(pSource) || SP_IS_BAD_INTERFACE_PTR(pDest) ||
SP_IS_BAD_OPTIONAL_INTERFACE_PTR(pHeader) || pReserved != NULL ||
SP_IS_BAD_OPTIONAL_INTERFACE_PTR(pErrorLog))
{
return E_INVALIDARG;
}
SPNODEENTRY XMLNodeTable[] =
{
{L"GRAMMAR", CXMLNode<CGrammarNode>::CreateNode, SPXML_GRAMMAR},
{L"RULE", CXMLNode<CRuleNode>::CreateNode, SPXML_RULE},
{L"DEFINE", CXMLNode<CDefineNode>::CreateNode, SPXML_DEFINE},
{L"ID", CXMLNode<CIdNode>::CreateNode, SPXML_ID},
{L"PHRASE", CXMLNode<CPhraseNode>::CreateNode, SPXML_PHRASE},
{L"PN", CXMLNode<CPhraseNode>::CreateNode, SPXML_PHRASE},
{L"P", CXMLNode<CPhraseNode>::CreateNode, SPXML_PHRASE},
{L"OPT", CXMLNode<CPhraseNode>::CreateNode, SPXML_OPT},
{L"O", CXMLNode<CPhraseNode>::CreateNode, SPXML_OPT},
{L"LIST", CXMLNode<CListNode>::CreateNode, SPXML_LIST},
{L"LN", CXMLNode<CListNode>::CreateNode, SPXML_LIST},
{L"L", CXMLNode<CListNode>::CreateNode, SPXML_LIST},
{L"RULEREF", CXMLNode<CRuleRefNode>::CreateNode, SPXML_RULEREF},
{L"TEXTBUFFER", CXMLNode<CTextBufferNode>::CreateNode, SPXML_TEXTBUFFER},
{L"WILDCARD", CXMLNode<CWildCardNode>::CreateNode, SPXML_WILDCARD},
{L"DICTATION", CXMLNode<CDictationNode>::CreateNode, SPXML_DICTATION},
{L"RESOURCE", CXMLNode<CResourceNode>::CreateNode, SPXML_RESOURCE},
{L"", CXMLNode<CLeafNode>::CreateNode, SPXML_LEAF}
};
ULONG cXMLNodeEntries = sizeof(XMLNodeTable) / sizeof(SPNODEENTRY);
CComPtr<IXMLParser> cpParser;
hr = cpParser.CoCreateInstance(CLSID_XMLParser);
if (SUCCEEDED(hr))
{
if ((m_pNodeFactory = new CNodeFactory(XMLNodeTable, cXMLNodeEntries, pErrorLog)))
{
hr = cpParser->SetFactory(m_pNodeFactory);
}
else
{
hr = E_OUTOFMEMORY;
}
if (SUCCEEDED(hr))
{
m_pNodeFactory->Release();
}
}
else
{
LOGERRORFMT( -1, IDS_IE5_REQUIRED, L"");
}
if (SUCCEEDED(hr))
{
hr = cpParser->SetInput(pSource);
}
if (SUCCEEDED(hr))
{
hr = m_pNodeFactory->m_cpBackend.CoCreateInstance(CLSID_SpGramCompBackend);
}
if (SUCCEEDED(hr))
{
hr = m_pNodeFactory->m_cpBackend->SetSaveObjects(pDest, pErrorLog);
}
if (SUCCEEDED(hr))
{
m_pRoot = new CXMLNode<CGrammarNode>;
if (m_pRoot)
{
m_pRoot->m_eType = SPXML_ROOT;
hr = cpParser->SetRoot(m_pRoot);
if (SUCCEEDED(hr))
{
m_pNodeFactory->m_NodeList.AddNode(m_pRoot);
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
if (SUCCEEDED(hr) && cpParser)
{
hr = cpParser->SetFlags(XMLFLAG_CASEINSENSITIVE | XMLFLAG_NOWHITESPACE);
}
if (SUCCEEDED(hr) && cpParser)
{
hr = cpParser->Run(-1);
}
if (SUCCEEDED(hr) && m_pRoot)
{
hr = m_pRoot->GenerateGrammar(NULL, NULL, m_pNodeFactory->m_cpBackend, pErrorLog);
}
if (SUCCEEDED(hr) && m_pNodeFactory)
{
hr = m_pNodeFactory->m_cpBackend->Commit(0);
}
if (SUCCEEDED(hr) && m_pNodeFactory && m_pNodeFactory->m_cpBackend)
{
m_pNodeFactory->m_cpBackend->SetSaveObjects(NULL, NULL);
}
if (SUCCEEDED(hr) && pHeader)
{
hr = WriteDefines(pHeader);
}
SPDBG_REPORT_ON_FAIL( hr );
return hr;
}