Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Speech / Src / Result / RecognizedPhrase.cs / 1 / RecognizedPhrase.cs
//------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------- using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; using System.Speech.Internal.SapiInterop; using System.Speech.Internal.SrgsCompiler; using System.Speech.Internal.SrgsParser; using System.Text; using System.Xml; using System.Xml.XPath; #pragma warning disable 1634, 1691 // Allows suppression of certain PreSharp messages. #pragma warning disable 56500 // Remove all the catch all statements warnings used by the interop layer namespace System.Speech.Recognition { /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognizedPhrase"]/*' /> [Serializable] [DebuggerDisplay ("{Text}")] public class RecognizedPhrase { //******************************************************************* // // Constructors // //******************************************************************* #region Constructors internal RecognizedPhrase () { } #endregion //******************************************************************** // // Public Methods // //******************************************************************* #region Public Methods /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.ConstructSMLFromSemantics"]/*' /> public IXPathNavigable ConstructSmlFromSemantics () { if (!string.IsNullOrEmpty (_smlContent)) { XmlDocument smlDocument = new XmlDocument (); smlDocument.LoadXml (_smlContent); return smlDocument; } if (_serializedPhrase.SemanticErrorInfoOffset != 0) { ThrowInvalidSemanticInterpretationError (); } XmlDocument document = new XmlDocument (); XmlElement root = document.CreateElement ("SML"); NumberFormatInfo nfo = new NumberFormatInfo (); nfo.NumberDecimalDigits = 3; document.AppendChild (root); root.SetAttribute ("text", Text); root.SetAttribute ("utteranceConfidence", Confidence.ToString ("f", nfo)); root.SetAttribute ("confidence", Confidence.ToString ("f", nfo)); if (Semantics.Count > 0) { AppendPropertiesSML (document, root, Semantics, nfo); } else if (Semantics.Value != null) { XmlText valueText = document.CreateTextNode (Semantics.Value.ToString ()); root.AppendChild (valueText); } // now append the alternates for (int i = 0; i < _recoResult.Alternates.Count; i++) { RecognizedPhrase alternate = _recoResult.Alternates [i]; alternate.AppendSml (document, i + 1, nfo); } _smlContent = document.OuterXml; return document; } #endregion //******************************************************************** // // Public Properties // //******************************************************************** #region Public Properties /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Text"]/*' /> public string Text { get { if (_text == null) { Collectionreplacements = ReplacementWordUnits; ReplacementText replacement; int iCurReplacementIndex = 0; int iWordReplacement = NextReplacementWord (replacements, out replacement, ref iCurReplacementIndex); StringBuilder sb = new StringBuilder (); for (int i = 0; i < Words.Count; i++) { DisplayAttributes displayAttribute; string text; if (i == iWordReplacement) { displayAttribute = replacement.DisplayAttributes; text = replacement.Text; i += replacement.CountOfWords - 1; iWordReplacement = NextReplacementWord (replacements, out replacement, ref iCurReplacementIndex); } else { displayAttribute = Words [i].DisplayAttributes; text = Words [i].Text; } // Remove leading spaces if ((displayAttribute & DisplayAttributes.ConsumeLeadingSpaces) != 0) { while (sb.Length > 0 && sb [sb.Length - 1] == ' ') { sb.Remove (sb.Length - 1, 1); } } // Append text sb.Append (text); // Add trailing spaces if ((displayAttribute & DisplayAttributes.ZeroTrailingSpaces) != 0) { // no action } else if ((displayAttribute & DisplayAttributes.OneTrailingSpace) != 0) { sb.Append (" "); } else if ((displayAttribute & DisplayAttributes.TwoTrailingSpaces) != 0) { sb.Append (" "); } } _text = sb.ToString ().Trim (' '); } return _text; } } /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Confidence"]/*' /> public float Confidence { get { return _confidence; } } /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Words"]/*' /> public ReadOnlyCollection Words { get { if (_words == null) { int countOfElements = (int) _serializedPhrase.Rule.ulCountOfElements; int elementsOffset = (int) _serializedPhrase.ElementsOffset; List wordList = new List (countOfElements); int sizeofPhraseElement = Marshal.SizeOf (typeof (SPSERIALIZEDPHRASEELEMENT)); GCHandle gc = GCHandle.Alloc (_phraseBuffer, GCHandleType.Pinned); try { IntPtr buffer = gc.AddrOfPinnedObject (); for (int i = 0; i < countOfElements; i++) { IntPtr elementBuffer = new IntPtr ((long) buffer + elementsOffset + i * sizeofPhraseElement); SPSERIALIZEDPHRASEELEMENT element = (SPSERIALIZEDPHRASEELEMENT) Marshal.PtrToStructure (elementBuffer, typeof (SPSERIALIZEDPHRASEELEMENT)); string displayForm = null, lexicalForm = null, pronunciation = null; if (element.pszDisplayTextOffset != 0) { IntPtr displayFormBuffer = new IntPtr ((long) buffer + (int) element.pszDisplayTextOffset); displayForm = Marshal.PtrToStringUni (displayFormBuffer); } if (element.pszLexicalFormOffset != 0) { IntPtr lexicalFormBuffer = new IntPtr ((long) buffer + (int) element.pszLexicalFormOffset); lexicalForm = Marshal.PtrToStringUni (lexicalFormBuffer); } if (element.pszPronunciationOffset != 0) { IntPtr pronunciationBuffer = new IntPtr ((long) buffer + (int) element.pszPronunciationOffset); pronunciation = Marshal.PtrToStringUni (pronunciationBuffer); if (!_hasIPAPronunciation) { pronunciation = _recoResult.ConvertPronunciation (pronunciation, _serializedPhrase.LangID); } } DisplayAttributes displayAttributes = RecognizedWordUnit.SapiAttributesToDisplayAttributes (element.bDisplayAttributes); // On SAPI 5.1, the engine confidence is not set. Force a value in this case if (!_isSapi53Header) { element.SREngineConfidence = 1.0f; } wordList.Add (new RecognizedWordUnit (displayForm, element.SREngineConfidence, pronunciation, lexicalForm, displayAttributes, new TimeSpan (element.ulAudioTimeOffset * TimeSpan.TicksPerMillisecond / 10000), new TimeSpan (element.ulAudioSizeTime * TimeSpan.TicksPerMillisecond / 10000))); } _words = new ReadOnlyCollection (wordList); } finally { gc.Free (); } } return _words; } } // Semantic data about result: /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Semantics"]/*' /> public SemanticValue Semantics { get { if (_serializedPhrase.SemanticErrorInfoOffset != 0) { ThrowInvalidSemanticInterpretationError (); } if (_phraseBuffer == null) { throw new NotSupportedException (); } if (_semantics == null) { CalcSemantics (Grammar); } return _semantics; } } // Homophonic alternates for this phrase /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Homophones"]/*' /> public ReadOnlyCollection Homophones { get { if (_phraseBuffer == null) { throw new NotSupportedException (); } if (_homophones == null) { // Walks the list of alternates and collects all phrases that have the same // homophoneGroupId at the phrase List homophones = new List (_recoResult.Alternates.Count); for (int i = 0; i < _recoResult.Alternates.Count; i++) { if ((_recoResult.Alternates [i]._homophoneGroupId == _homophoneGroupId) && (_recoResult.Alternates [i].Text != this.Text)) { homophones.Add (_recoResult.Alternates [i]); } } _homophones = new ReadOnlyCollection (homophones); } return _homophones; } } /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Grammar"]/*' /> public Grammar Grammar { get { // If this phrase comes from a deserialize, then throw if (_grammarId == unchecked ((UInt64) (-1))) { throw new NotSupportedException (SR.Get (SRID.CantGetPropertyFromSerializedInfo, "Grammar")); } if (_grammar == null && _recoResult.Recognizer != null) { _grammar = _recoResult.Recognizer.GetGrammarFromId (_grammarId); } return _grammar; } } /// TODOC public Collection ReplacementWordUnits { get { if (_replacementText == null) { _replacementText = new Collection (); GCHandle gc = GCHandle.Alloc (_phraseBuffer, GCHandleType.Pinned); try { IntPtr buffer = gc.AddrOfPinnedObject (); // Get the ITN and Look for replacement phrase/ IntPtr itnBuffer = new IntPtr ((long) buffer + _serializedPhrase.ReplacementsOffset); for (int i = 0; i < _serializedPhrase.cReplacements; i++, itnBuffer = (IntPtr) ((long) itnBuffer + Marshal.SizeOf (typeof (SPPHRASEREPLACEMENT)))) { SPPHRASEREPLACEMENT replacement = (SPPHRASEREPLACEMENT) Marshal.PtrToStructure (itnBuffer, typeof (SPPHRASEREPLACEMENT)); string text = Marshal.PtrToStringUni (new IntPtr ((long) buffer + replacement.pszReplacementText)); DisplayAttributes displayAttributes = RecognizedWordUnit.SapiAttributesToDisplayAttributes (replacement.bDisplayAttributes); _replacementText.Add (new ReplacementText (displayAttributes, text, (int) replacement.ulFirstElement, (int) replacement.ulCountOfElements)); } } finally { gc.Free (); } } return _replacementText; } } /// /// TODOC /// public int HomophoneGroupId { get { return _homophoneGroupId; } } #endregion //******************************************************************* // // Internal Methods // //******************************************************************** #region Internal Methods static internal SPSERIALIZEDPHRASE GetPhraseHeader (IntPtr phraseBuffer, uint expectedPhraseSize, bool isSapi53Header) { SPSERIALIZEDPHRASE serializedPhrase; if (isSapi53Header) { serializedPhrase = (SPSERIALIZEDPHRASE) Marshal.PtrToStructure (phraseBuffer, typeof (SPSERIALIZEDPHRASE)); } else { SPSERIALIZEDPHRASE_Sapi51 legacyPhrase = (SPSERIALIZEDPHRASE_Sapi51) Marshal.PtrToStructure (phraseBuffer, typeof (SPSERIALIZEDPHRASE_Sapi51)); serializedPhrase = new SPSERIALIZEDPHRASE (legacyPhrase); } if (serializedPhrase.ulSerializedSize > expectedPhraseSize) { throw new FormatException (SR.Get (SRID.ResultInvalidFormat)); } return serializedPhrase; } internal void InitializeFromSerializedBuffer (RecognitionResult recoResult, SPSERIALIZEDPHRASE serializedPhrase, IntPtr phraseBuffer, int phraseLength, bool isSapi53Header, bool hasIPAPronunciation) { _recoResult = recoResult; _isSapi53Header = isSapi53Header; _serializedPhrase = serializedPhrase; _confidence = _serializedPhrase.Rule.SREngineConfidence; _grammarId = _serializedPhrase.ullGrammarID; _homophoneGroupId = _serializedPhrase.wHomophoneGroupId; _hasIPAPronunciation = hasIPAPronunciation; // Save the phrase blob _phraseBuffer = new byte [phraseLength]; Marshal.Copy (phraseBuffer, _phraseBuffer, 0, phraseLength); // Get the grammar options _grammarOptions = recoResult.Grammar != null ? recoResult.Grammar._semanticTag : GrammarOptions.KeyValuePairSrgs; // This triggers the semantic processing if any CalcSemantics (recoResult.Grammar); } #endregion //******************************************************************* // // Internal Properties // //******************************************************************* #region Internal Properties internal ulong GrammarId { get { return _grammarId; } } internal string SmlContent { #if SPEECHSERVER set { _smlContent = value; } #endif get { if (_smlContent == null) { // this method already sets _smlContent ConstructSmlFromSemantics (); } return _smlContent; } } #endregion //******************************************************************* // // Internal Properties // //******************************************************************** #region Internal fields internal SPSERIALIZEDPHRASE _serializedPhrase; internal byte [] _phraseBuffer; internal bool _isSapi53Header; internal bool _hasIPAPronunciation; #endregion //******************************************************************* // // Private Methods // //******************************************************************** #region Private Methods // Semantic data about result: /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Semantics"]/*' /> private void CalcSemantics (Grammar grammar) { if (_semantics == null && _serializedPhrase.SemanticErrorInfoOffset == 0) { GCHandle gc = GCHandle.Alloc (_phraseBuffer, GCHandleType.Pinned); try { IntPtr buffer = gc.AddrOfPinnedObject (); if (!CalcILSemantics (buffer)) { // List of recognized words IListwords = Words; // Build the list of rules and property values RuleNode ruleTree = ExtractRules (grammar, _serializedPhrase.Rule, buffer); List propertyList = BuildRecoPropertyTree (_serializedPhrase, buffer, ruleTree, words, _isSapi53Header); // Recursively build the dictionary of properties _semantics = RecursiveBuildSemanticProperties (words, propertyList, ruleTree, _grammarOptions & GrammarOptions.TagFormat, ref _dupItems); #if !NO_STG // Delay the call to TryExecuteOnRecognition until the _semantics has been set _semantics.Value = TryExecuteOnRecognition (grammar, _recoResult, ruleTree._rule); #endif } } finally { gc.Free (); } } } private bool CalcILSemantics (IntPtr phraseBuffer) { if ((_grammarOptions & (GrammarOptions.MssV1 | GrammarOptions.W3cV1)) != 0 || _grammarOptions == GrammarOptions.KeyValuePairs) { IList words = Words; _semantics = new SemanticValue (" ", null, _confidence); if (_serializedPhrase.PropertiesOffset != 0) { RecursivelyExtractSemanticValue (phraseBuffer, (int) _serializedPhrase.PropertiesOffset, _semantics, words, _isSapi53Header, _grammarOptions & GrammarOptions.TagFormat); } return true; } return false; } static private List BuildRecoPropertyTree (SPSERIALIZEDPHRASE serializedPhrase, IntPtr phraseBuffer, RuleNode ruleTree, IList words, bool isSapi53Header) { List propertyList = new List (); // Array of string containing the rule names. if ((int) serializedPhrase.PropertiesOffset > 0) { RecursivelyExtractSemanticProperties (propertyList, (int) serializedPhrase.PropertiesOffset, phraseBuffer, ruleTree, words, isSapi53Header); } return propertyList; } static private SemanticValue RecursiveBuildSemanticProperties (IList words, List properties, RuleNode ruleTree, GrammarOptions semanticTag, ref Collection dupItems) { SemanticValue semanticValue = new SemanticValue (ruleTree._name, null, ruleTree._confidence); // Add the semantic values from the child rules for (RuleNode children = ruleTree._child; children != null; children = children._next) { // Propagate up the semantic values calculated at the children level SemanticValue childrenSemantics = RecursiveBuildSemanticProperties (words, properties, children, semanticTag, ref dupItems); if (!children._hasName) { foreach (KeyValuePair kv in childrenSemantics._dictionary) { InsertSemanticValueToDictionary (semanticValue, kv.Key, kv.Value, semanticTag, ref dupItems); } if (childrenSemantics.Value != null) { if ((semanticTag & (GrammarOptions.MssV1 | GrammarOptions.W3cV1)) == 0 && semanticValue._valueFieldSet && !semanticValue.Value.Equals (childrenSemantics.Value)) { throw new InvalidOperationException (SR.Get (SRID.DupSemanticValue, ruleTree._name)); } semanticValue.Value = childrenSemantics.Value; semanticValue._valueFieldSet = true; } } else { // If no value has been set then the recognized text is returned as the value if (!childrenSemantics._valueFieldSet && childrenSemantics.Count == 0) { StringBuilder sb = new StringBuilder (); for (int i = 0; i < children._count; i++) { if (sb.Length > 0) { sb.Append (" "); } sb.Append (words [(int) children._firstElement + i].Text); } childrenSemantics._valueFieldSet = true; childrenSemantics.Value = sb.ToString (); } semanticValue._dictionary.Add (children._name, childrenSemantics); } } // Add the semantic value from the properties foreach (ResultPropertiesRef property in properties) { if (property._ruleNode == ruleTree) { InsertSemanticValueToDictionary (semanticValue, property._name, property._value, semanticTag, ref dupItems); } } #if !NO_STG Exception exceptionThrown = null; // Try to execute the semantic value if OnParse is defined object newValue; bool doneOnParse = TryExecuteOnParse (ruleTree, semanticValue, words, out newValue, ref exceptionThrown); if (exceptionThrown != null) { throw exceptionThrown; } // if (doneOnParse) { semanticValue._dictionary.Clear (); semanticValue.Value = newValue; semanticValue._valueFieldSet = true; } #endif return semanticValue; } static private void RecursivelyExtractSemanticProperties (List propertyList, int semanticsOffset, IntPtr phraseBuffer, RuleNode ruleTree, IList words, bool isSapi53Header) { IntPtr propertyBuffer = new IntPtr ((long) phraseBuffer + semanticsOffset); SPSERIALIZEDPHRASEPROPERTY property = (SPSERIALIZEDPHRASEPROPERTY) Marshal.PtrToStructure (propertyBuffer, typeof (SPSERIALIZEDPHRASEPROPERTY)); string propertyName; SemanticValue thisSemanticValue = ExtractSemanticValueInformation (semanticsOffset, property, phraseBuffer, isSapi53Header, out propertyName); RuleNode node = ruleTree.Find (property.ulFirstElement, property.ulCountOfElements); if (propertyName == "SemanticKey") { node._name = (string) thisSemanticValue.Value; node._hasName = true; } else { propertyList.Add (new ResultPropertiesRef (propertyName, thisSemanticValue, node)); } if (property.pFirstChildOffset > 0) { // add children to the new node RecursivelyExtractSemanticProperties (propertyList, (int) property.pFirstChildOffset, phraseBuffer, ruleTree, words, isSapi53Header); } if (property.pNextSiblingOffset > 0) { // add siblings to parent node RecursivelyExtractSemanticProperties (propertyList, (int) property.pNextSiblingOffset, phraseBuffer, ruleTree, words, isSapi53Header); } } private void RecursivelyExtractSemanticValue (IntPtr phraseBuffer, int semanticsOffset, SemanticValue semanticValue, IList words, bool isSapi53Header, GrammarOptions semanticTag) { IntPtr propertyBuffer = new IntPtr ((long) phraseBuffer + semanticsOffset); SPSERIALIZEDPHRASEPROPERTY property = (SPSERIALIZEDPHRASEPROPERTY) Marshal.PtrToStructure (propertyBuffer, typeof (SPSERIALIZEDPHRASEPROPERTY)); string propertyName; SemanticValue thisSemanticValue = ExtractSemanticValueInformation (semanticsOffset, property, phraseBuffer, isSapi53Header, out propertyName); if (propertyName == "_value" && semanticValue != null) { // 'remove' the _value node from the tree by setting its value to the parent's value // and use the parent as the node to add children (if present) semanticValue.Value = thisSemanticValue.Value; if (property.pFirstChildOffset > 0) { thisSemanticValue = semanticValue; } } else { InsertSemanticValueToDictionary (semanticValue, propertyName, thisSemanticValue, semanticTag, ref _dupItems); } if (property.pFirstChildOffset > 0) { // add children to the new node RecursivelyExtractSemanticValue (phraseBuffer, (int) property.pFirstChildOffset, thisSemanticValue, words, isSapi53Header, semanticTag); } if (property.pNextSiblingOffset > 0) { // add siblings to parent node RecursivelyExtractSemanticValue (phraseBuffer, (int) property.pNextSiblingOffset, semanticValue, words, isSapi53Header, semanticTag); } } static private void InsertSemanticValueToDictionary (SemanticValue semanticValue, string propertyName, SemanticValue thisSemanticValue, GrammarOptions semanticTag, ref Collection dupItems) { string key = propertyName; if ((key == "$" && semanticTag == GrammarOptions.MssV1) || (key == "=" && (semanticTag == GrammarOptions.KeyValuePairSrgs || semanticTag == GrammarOptions.KeyValuePairs)) || (thisSemanticValue.Count == -1 && semanticTag == GrammarOptions.W3cV1)) { if ((semanticTag & (GrammarOptions.MssV1 | GrammarOptions.W3cV1)) == 0 && semanticValue._valueFieldSet && !semanticValue.Value.Equals (thisSemanticValue.Value)) { throw new InvalidOperationException (SR.Get (SRID.DupSemanticValue, semanticValue.KeyName)); } semanticValue.Value = thisSemanticValue.Value; semanticValue._valueFieldSet = true; } else { bool containsKey = semanticValue._dictionary.ContainsKey (key); if (!containsKey) { semanticValue._dictionary.Add (key, thisSemanticValue); } else { if (!semanticValue._dictionary [key].Equals (thisSemanticValue)) { // Error out for Srgs grammars if (semanticTag == GrammarOptions.KeyValuePairSrgs) { throw new InvalidOperationException (SR.Get (SRID.DupSemanticKey, propertyName, semanticValue.KeyName)); } // Append a _* on the key name for none SAPI grammars int count = 0; do { key = propertyName + string.Format (CultureInfo.InvariantCulture, "_{0}", count++); } while (semanticValue._dictionary.ContainsKey (key)); semanticValue._dictionary.Add (key, thisSemanticValue); if (dupItems == null) { dupItems = new Collection (); } SemanticValue s = semanticValue._dictionary [key]; dupItems.Add (s); } } } } static private SemanticValue ExtractSemanticValueInformation (int semanticsOffset, SPSERIALIZEDPHRASEPROPERTY property, IntPtr phraseBuffer, bool isSapi53Header, out string propertyName) { object propertyValue; bool isIdName = false; if (property.pszNameOffset > 0) { IntPtr nameBuffer = new IntPtr ((long) phraseBuffer + (int) property.pszNameOffset); propertyName = Marshal.PtrToStringUni (nameBuffer); } else { propertyName = property.ulId.ToString (CultureInfo.InvariantCulture); isIdName = true; } if (property.pszValueOffset > 0) { IntPtr valueStringBuffer = new IntPtr ((long) phraseBuffer + (int) property.pszValueOffset); propertyValue = Marshal.PtrToStringUni (valueStringBuffer); if (!isSapi53Header && isIdName && ((string) propertyValue).Contains ("$")) { // SAPI 5.1 result that contains script fragments rather than output of executing script. // Strip this information as script-based grammars aren't supported on 5.1. throw new NotSupportedException (SR.Get (SRID.NotSupportedWithThisVersionOfSAPI)); } } else { if (property.SpVariantSubset >= 0) { IntPtr valueBuffer = new IntPtr ((long) phraseBuffer + +semanticsOffset + SpVariantSubsetOffset); switch ((VarEnum) property.vValue) { case VarEnum.VT_I4: propertyValue = Marshal.ReadInt32 (valueBuffer); break; case VarEnum.VT_UI4: propertyValue = Marshal.PtrToStructure (valueBuffer, typeof (UInt32)); break; case VarEnum.VT_I8: propertyValue = Marshal.ReadInt64 (valueBuffer); break; case VarEnum.VT_UI8: propertyValue = Marshal.PtrToStructure (valueBuffer, typeof (UInt64)); break; case VarEnum.VT_R4: propertyValue = Marshal.PtrToStructure (valueBuffer, typeof (float)); break; case VarEnum.VT_R8: propertyValue = Marshal.PtrToStructure (valueBuffer, typeof (double)); break; case VarEnum.VT_BOOL: propertyValue = (Marshal.ReadByte (valueBuffer) != 0); break; case VarEnum.VT_EMPTY: propertyValue = null; break; default: throw new NotSupportedException (SR.Get (SRID.UnhandledVariant)); } } else { propertyValue = String.Empty; } } return new SemanticValue (propertyName, propertyValue, property.SREngineConfidence); } static private RuleNode ExtractRules (Grammar grammar, SPSERIALIZEDPHRASERULE rule, IntPtr phraseBuffer) { // Get the rule name IntPtr nameBuffer = new IntPtr ((long) phraseBuffer + (int) rule.pszNameOffset); // Add the rule name to the proper element index string name = Marshal.PtrToStringUni (nameBuffer); // find the grammar for this rule. If the grammar does not belong to any existing ruleref then // it must be local. #if !NO_STG Grammar ruleRef = grammar != null ? grammar.Find (name) : null; if (ruleRef != null) { grammar = ruleRef; } #endif RuleNode node = new RuleNode (grammar, name, rule.SREngineConfidence, rule.ulFirstElement,rule.ulCountOfElements); if (rule.NextSiblingOffset > 0) { IntPtr elementBuffer = new IntPtr ((long) phraseBuffer + rule.NextSiblingOffset); SPSERIALIZEDPHRASERULE ruleNext = (SPSERIALIZEDPHRASERULE) Marshal.PtrToStructure (elementBuffer, typeof (SPSERIALIZEDPHRASERULE)); node._next = ExtractRules (grammar, ruleNext, phraseBuffer); } if (rule.FirstChildOffset > 0) { IntPtr elementBuffer = new IntPtr ((long) phraseBuffer + rule.FirstChildOffset); SPSERIALIZEDPHRASERULE ruleFirst = (SPSERIALIZEDPHRASERULE) Marshal.PtrToStructure (elementBuffer, typeof (SPSERIALIZEDPHRASERULE)); node._child = ExtractRules (grammar, ruleFirst, phraseBuffer); } return node; } private void ThrowInvalidSemanticInterpretationError () { //string error; if (!_isSapi53Header) { throw new NotSupportedException (SR.Get (SRID.NotSupportedWithThisVersionOfSAPI)); } GCHandle gc = GCHandle.Alloc (_phraseBuffer, GCHandleType.Pinned); try { IntPtr smlBuffer = gc.AddrOfPinnedObject (); SPSEMANTICERRORINFO semanticError = (SPSEMANTICERRORINFO) Marshal.PtrToStructure ((IntPtr) ((long) smlBuffer + (int) _serializedPhrase.SemanticErrorInfoOffset), typeof (SPSEMANTICERRORINFO)); string source = Marshal.PtrToStringUni (new IntPtr ((long) smlBuffer + semanticError.pszSourceOffset)); string description = Marshal.PtrToStringUni (new IntPtr ((long) smlBuffer + semanticError.pszDescriptionOffset)); string script = Marshal.PtrToStringUni (new IntPtr ((long) smlBuffer + semanticError.pszScriptLineOffset)); string error = string.Format (CultureInfo.InvariantCulture, "Error while evaluating semantic interpretation:\n" + " HRESULT: {0:x}\n" + " Line: {1}\n" + " Source: {2}\n" + " Description: {3}\n" + " Script: {4}\n", semanticError.hrResultCode, semanticError.ulLineNumber, source, description, script); throw new InvalidOperationException (error); } finally { gc.Free (); } } #if !NO_STG static private bool TryExecuteOnParse (RuleNode ruleRef, SemanticValue value, IList words, out object newValue, ref Exception exceptionThrown) { newValue = null; bool doneOnParse = false; Grammar grammar = ruleRef._grammar; if (grammar != null && grammar._scripts != null) { // Check if the Inner try { if (exceptionThrown == null) { doneOnParse = ExecuteOnParse (grammar, ruleRef, value, words, out newValue); } else { if (ExecuteOnError (grammar, ruleRef, exceptionThrown)) { exceptionThrown = null; } } } catch (Exception e) { if (exceptionThrown == null) { exceptionThrown = e; // Try to execute on Error on this thread try { if (ExecuteOnError (grammar, ruleRef, exceptionThrown)) { exceptionThrown = null; } } catch (Exception e2) { exceptionThrown = e2; } } } } return doneOnParse; } private static bool ExecuteOnParse (Grammar grammar, RuleNode ruleRef, SemanticValue value, IList words, out object newValue) { // Get the rule list ScriptRef [] scripts = grammar._scripts; bool doneOnParse = false; newValue = null; // Look if an OnParse exist for this method for (int iScript = 0; iScript < scripts.Length; iScript++) { ScriptRef script = scripts [iScript]; if (ruleRef._rule == script._rule) { if (script._method == RuleMethodScript.onParse) { // Get the method to invoke RecognizedWordUnit [] recoUnits = new RecognizedWordUnit [ruleRef._count]; for (int i = 0; i < ruleRef._count; i++) { recoUnits [i] = words [i]; } object [] parameters = new object [2] { value, recoUnits }; if (grammar._proxy != null) { Exception appDomainException; newValue = grammar._proxy.OnParse (script._rule, script._sMethod, parameters, out appDomainException); if (appDomainException != null) { throw appDomainException; } } else { MethodInfo onParse; System.Speech.Recognition.Grammar rule; GetRuleInstance (grammar, script._rule, script._sMethod, out onParse, out rule); // Execute the parse routine newValue = onParse.Invoke (rule, parameters); } doneOnParse = true; } } } return doneOnParse; } private static bool ExecuteOnError (Grammar grammar, RuleNode ruleRef, Exception e) { // Get the rule list ScriptRef [] scripts = grammar._scripts; bool invoked = false; // Look if an OnParse exist for this method for (int iScript = 0; iScript < scripts.Length; iScript++) { ScriptRef script = scripts [iScript]; if (ruleRef._rule == script._rule) { if (script._method == RuleMethodScript.onError) { // Get the method to invoke object [] parameters = new object [] { e }; if (grammar._proxy != null) { Exception appDomainException; grammar._proxy.OnError (script._rule, script._sMethod, parameters, out appDomainException); if (appDomainException != null) { throw appDomainException; } } else { MethodInfo onError; System.Speech.Recognition.Grammar rule; GetRuleInstance (grammar, script._rule, script._sMethod, out onError, out rule); // Execute the parse routine onError.Invoke (rule, parameters); } invoked = true; } } } return invoked; } private static object TryExecuteOnRecognition (Grammar grammar, RecognitionResult result, string rootRule) { object resultValue = result.Semantics.Value; if (grammar != null && grammar._scripts != null) { // Get the rule list ScriptRef [] scripts = grammar._scripts; // Look if an OnRecognition exist for this method for (int iScript = 0; iScript < scripts.Length; iScript++) { ScriptRef script = scripts [iScript]; if (rootRule == script._rule) { if (script._method == RuleMethodScript.onRecognition) { // Get the method to invoke object [] parameters = new object [1] { result }; if (grammar._proxy != null) { Exception appDomainException; resultValue = grammar._proxy.OnRecognition (script._sMethod, parameters, out appDomainException); if (appDomainException != null) { throw appDomainException; } } else { Type grammarType = grammar.GetType (); MethodInfo onRecognition = grammarType.GetMethod (script._sMethod, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); // Execute the parse routine resultValue = onRecognition.Invoke (grammar, parameters); } } } } } return resultValue; } #endif #if !SPEECHSERVER static private void GetRuleInstance (Grammar grammar, string rule, string method, out MethodInfo onParse, out Grammar ruleInstance) { Type grammarType = grammar.GetType (); Assembly assembly = grammarType.Assembly; Type ruleClass = rule == grammarType.Name ? grammarType : GetTypeForRule (assembly, rule); if (ruleClass == null || !ruleClass.IsSubclassOf (typeof (System.Speech.Recognition.Grammar))) { throw new FormatException (SR.Get (SRID.RecognizerInvalidBinaryGrammar)); } ruleInstance = ruleClass == grammarType ? grammar : (System.Speech.Recognition.Grammar) assembly.CreateInstance (ruleClass.FullName); onParse = ruleInstance.MethodInfo (method); } static private Type GetTypeForRule (Assembly assembly, string rule) { Type [] types = assembly.GetTypes (); for (int iType = 0; iType < types.Length; iType++) { Type type = types [iType]; if (type.Name == rule && type.IsPublic && type.IsSubclassOf (typeof (System.Speech.Recognition.Grammar))) { return type; } } return null; } #endif static private int NextReplacementWord (Collection replacements, out ReplacementText replacement, ref int posInCollection) { if (posInCollection < replacements.Count) { replacement = replacements [posInCollection++]; return replacement.FirstWordIndex; } else { replacement = null; return -1; } } private void AppendSml (XmlDocument document, int i, NumberFormatInfo nfo) { XmlNode root = document.DocumentElement; XmlElement alternateNode = document.CreateElement ("alternate"); root.AppendChild (alternateNode); alternateNode.SetAttribute ("Rank", i.ToString (CultureInfo.CurrentUICulture)); alternateNode.SetAttribute ("text", Text); alternateNode.SetAttribute ("utteranceConfidence", Confidence.ToString ("f", nfo)); alternateNode.SetAttribute ("confidence", Confidence.ToString ("f", nfo)); if (_semantics.Value != null) { XmlText valueText = document.CreateTextNode (_semantics.Value.ToString ()); alternateNode.AppendChild (valueText); } // recursively add the properties now AppendPropertiesSML (document, alternateNode, _semantics, nfo); } private void AppendPropertiesSML (XmlDocument document, XmlElement alternateNode, SemanticValue semanticsNode, NumberFormatInfo nfo) { if (semanticsNode != null) { foreach (KeyValuePair kv in semanticsNode) { if (kv.Key == "_attributes") { // all the attributes are located under the attribute property. AppendAttributes (alternateNode, kv.Value); if (string.IsNullOrEmpty (alternateNode.InnerText) && semanticsNode.Value != null) { XmlText valueText = document.CreateTextNode (semanticsNode.Value.ToString ()); alternateNode.AppendChild (valueText); } } else { string keyName = kv.Key; if (_dupItems != null && _dupItems.Contains (kv.Value)) { keyName = RemoveTrailingNumber (kv.Key); } XmlElement propertyNode = document.CreateElement (keyName); propertyNode.SetAttribute ("confidence", semanticsNode [kv.Key].Confidence.ToString ("f", nfo)); alternateNode.AppendChild (propertyNode); if (kv.Value.Count > 0) { if (kv.Value.Value != null) { XmlText valueText = document.CreateTextNode (kv.Value.Value.ToString ()); propertyNode.AppendChild (valueText); } AppendPropertiesSML (document, propertyNode, kv.Value, nfo); } else if (kv.Value.Value != null) { XmlText valueText = document.CreateTextNode (kv.Value.Value.ToString ()); propertyNode.AppendChild (valueText); } } } } } private string RemoveTrailingNumber (string name) { return name.Substring (0, name.LastIndexOf ('_')); } private void AppendAttributes (XmlElement propertyNode, SemanticValue semanticValue) { foreach (KeyValuePair kv in semanticValue) { if (propertyNode.Attributes [kv.Key] == null) { propertyNode.SetAttribute (kv.Key, kv.Value.Value.ToString ()); } } } #if VSCOMPILE static private void DumpAll (RuleNode ruleTree, IList words, SPSERIALIZEDPHRASE serializedPhrase, IntPtr phraseBuffer, bool isSapi53Header) { DumpWords (words); Console.WriteLine ("Rules"); DumpRules (0, ruleTree); if (serializedPhrase.PropertiesOffset != 0) { Console.WriteLine ("Semantics"); DumpSemantics (0, (int) serializedPhrase.PropertiesOffset, phraseBuffer, isSapi53Header); } else { Console.WriteLine ("No Semantics"); } } static private void DumpWords (IList words) { StringBuilder sb = new StringBuilder (); foreach (RecognizedWordUnit word in words) { sb.Append (word.Text + " "); } Console.WriteLine (sb.ToString ()); } static private void DumpRules (int depth, RuleNode node) { StringBuilder sb = new StringBuilder (); for (int i = 0; i < depth; i++) { sb.Append ("----"); } Console.WriteLine (sb.ToString () + " " + node._rule + "[" + node._firstElement + "," + node._firstElement + node._count + "," + "]"); if (node._next != null) { DumpRules (depth, node._next); } if (node._child != null) { DumpRules (depth + 1, node._child); } } static private void DumpSemantics (int depth, int semanticsOffset, IntPtr phraseBuffer, bool isSapi53Header) { IntPtr propertyBuffer = new IntPtr ((long) phraseBuffer + semanticsOffset); SPSERIALIZEDPHRASEPROPERTY property = (SPSERIALIZEDPHRASEPROPERTY) Marshal.PtrToStructure (propertyBuffer, typeof (SPSERIALIZEDPHRASEPROPERTY)); StringBuilder sb = new StringBuilder (); for (int i = 0; i < depth; i++) { sb.Append ("----"); } string propertyName; SemanticValue thisSemanticValue = ExtractSemanticValueInformation (semanticsOffset, property, phraseBuffer, isSapi53Header, out propertyName); Console.WriteLine (sb.ToString () + " " + propertyName + "[" + property.ulFirstElement + "," + property.ulCountOfElements + "," + property.ulId + "]"); if (property.pNextSiblingOffset > 0) { // add siblings to parent node DumpSemantics (depth, (int) property.pNextSiblingOffset, phraseBuffer, isSapi53Header); } if (property.pFirstChildOffset > 0) { // add children to the new node DumpSemantics (depth + 1, (int) property.pFirstChildOffset, phraseBuffer, isSapi53Header); } } #endif #endregion //******************************************************************** // // Private Types // //******************************************************************* #region Private Types #if VSCOMPILE [DebuggerDisplay ("{DisplayDebugInfo ()}")] #endif private class RuleNode { internal RuleNode (Grammar grammar, string rule, float confidence, uint first, uint count) { _rule = _name = rule; _firstElement = first; _count = count; _confidence = confidence; _grammar = grammar; //_ruleId = id; } /// /// Find the rule enclosing a property. /// /// First word mathcing the property /// Count of words ///internal RuleNode Find (uint firstElement, uint count) { // If the count of word is set to zero. It means that the tag is located just before a word. // The trick here is to use 1/2 position to locate tags in this case. float firstWord, lastWord; if (count == 0) { firstWord = lastWord = firstElement - 0.5f; } else { firstWord = (float) firstElement; lastWord = firstWord + (count - 1); } for (RuleNode child = _child; child != null; child = child._next) { float ruleFirstWord, ruleLastWord; if (child._count == 0) { ruleFirstWord = ruleLastWord = child._firstElement - 0.5f; } else { ruleFirstWord = (float) child._firstElement; ruleLastWord = ruleFirstWord + (child._count - 1); } if (ruleFirstWord <= firstElement && ruleLastWord >= lastWord) { return child.Find (firstElement, count); } } return this; } #if VSCOMPILE private string DisplayDebugInfo () { return string.Format ("'rule={0}", _rule); } #endif internal Grammar _grammar; internal string _rule; internal string _name; internal uint _firstElement; internal uint _count; //internal int _ruleId; internal float _confidence; internal bool _hasName; internal RuleNode _next; internal RuleNode _child; } #if VSCOMPILE [DebuggerDisplay ("Name={_name} node={_ruleNode._rule} value={_value != null && _value.Value != null ? _value.Value.ToString() : \"\"}")] #endif private struct ResultPropertiesRef { internal string _name; internal SemanticValue _value; internal RuleNode _ruleNode; internal ResultPropertiesRef (string name, SemanticValue value, RuleNode ruleNode) { _name = name; _value = value; _ruleNode = ruleNode; } } #endregion //******************************************************************** // // Private Fields // //******************************************************************* #region Private Fields private RecognitionResult _recoResult; private GrammarOptions _grammarOptions; private string _text; private float _confidence; private SemanticValue _semantics; private ReadOnlyCollection _words; private Collection _replacementText; [NonSerializedAttribute] private UInt64 _grammarId = unchecked ((UInt64) (-1)); #pragma warning disable 6524 [NonSerializedAttribute] private Grammar _grammar; #pragma warning restore 6524 private int _homophoneGroupId; private ReadOnlyCollection _homophones; private Collection _dupItems; private string _smlContent; private const int SpVariantSubsetOffset = 16; #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------- using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; using System.Speech.Internal.SapiInterop; using System.Speech.Internal.SrgsCompiler; using System.Speech.Internal.SrgsParser; using System.Text; using System.Xml; using System.Xml.XPath; #pragma warning disable 1634, 1691 // Allows suppression of certain PreSharp messages. #pragma warning disable 56500 // Remove all the catch all statements warnings used by the interop layer namespace System.Speech.Recognition { /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognizedPhrase"]/*' /> [Serializable] [DebuggerDisplay ("{Text}")] public class RecognizedPhrase { //******************************************************************* // // Constructors // //******************************************************************* #region Constructors internal RecognizedPhrase () { } #endregion //******************************************************************** // // Public Methods // //******************************************************************* #region Public Methods /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.ConstructSMLFromSemantics"]/*' /> public IXPathNavigable ConstructSmlFromSemantics () { if (!string.IsNullOrEmpty (_smlContent)) { XmlDocument smlDocument = new XmlDocument (); smlDocument.LoadXml (_smlContent); return smlDocument; } if (_serializedPhrase.SemanticErrorInfoOffset != 0) { ThrowInvalidSemanticInterpretationError (); } XmlDocument document = new XmlDocument (); XmlElement root = document.CreateElement ("SML"); NumberFormatInfo nfo = new NumberFormatInfo (); nfo.NumberDecimalDigits = 3; document.AppendChild (root); root.SetAttribute ("text", Text); root.SetAttribute ("utteranceConfidence", Confidence.ToString ("f", nfo)); root.SetAttribute ("confidence", Confidence.ToString ("f", nfo)); if (Semantics.Count > 0) { AppendPropertiesSML (document, root, Semantics, nfo); } else if (Semantics.Value != null) { XmlText valueText = document.CreateTextNode (Semantics.Value.ToString ()); root.AppendChild (valueText); } // now append the alternates for (int i = 0; i < _recoResult.Alternates.Count; i++) { RecognizedPhrase alternate = _recoResult.Alternates [i]; alternate.AppendSml (document, i + 1, nfo); } _smlContent = document.OuterXml; return document; } #endregion //******************************************************************** // // Public Properties // //******************************************************************** #region Public Properties /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Text"]/*' /> public string Text { get { if (_text == null) { Collectionreplacements = ReplacementWordUnits; ReplacementText replacement; int iCurReplacementIndex = 0; int iWordReplacement = NextReplacementWord (replacements, out replacement, ref iCurReplacementIndex); StringBuilder sb = new StringBuilder (); for (int i = 0; i < Words.Count; i++) { DisplayAttributes displayAttribute; string text; if (i == iWordReplacement) { displayAttribute = replacement.DisplayAttributes; text = replacement.Text; i += replacement.CountOfWords - 1; iWordReplacement = NextReplacementWord (replacements, out replacement, ref iCurReplacementIndex); } else { displayAttribute = Words [i].DisplayAttributes; text = Words [i].Text; } // Remove leading spaces if ((displayAttribute & DisplayAttributes.ConsumeLeadingSpaces) != 0) { while (sb.Length > 0 && sb [sb.Length - 1] == ' ') { sb.Remove (sb.Length - 1, 1); } } // Append text sb.Append (text); // Add trailing spaces if ((displayAttribute & DisplayAttributes.ZeroTrailingSpaces) != 0) { // no action } else if ((displayAttribute & DisplayAttributes.OneTrailingSpace) != 0) { sb.Append (" "); } else if ((displayAttribute & DisplayAttributes.TwoTrailingSpaces) != 0) { sb.Append (" "); } } _text = sb.ToString ().Trim (' '); } return _text; } } /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Confidence"]/*' /> public float Confidence { get { return _confidence; } } /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Words"]/*' /> public ReadOnlyCollection Words { get { if (_words == null) { int countOfElements = (int) _serializedPhrase.Rule.ulCountOfElements; int elementsOffset = (int) _serializedPhrase.ElementsOffset; List wordList = new List (countOfElements); int sizeofPhraseElement = Marshal.SizeOf (typeof (SPSERIALIZEDPHRASEELEMENT)); GCHandle gc = GCHandle.Alloc (_phraseBuffer, GCHandleType.Pinned); try { IntPtr buffer = gc.AddrOfPinnedObject (); for (int i = 0; i < countOfElements; i++) { IntPtr elementBuffer = new IntPtr ((long) buffer + elementsOffset + i * sizeofPhraseElement); SPSERIALIZEDPHRASEELEMENT element = (SPSERIALIZEDPHRASEELEMENT) Marshal.PtrToStructure (elementBuffer, typeof (SPSERIALIZEDPHRASEELEMENT)); string displayForm = null, lexicalForm = null, pronunciation = null; if (element.pszDisplayTextOffset != 0) { IntPtr displayFormBuffer = new IntPtr ((long) buffer + (int) element.pszDisplayTextOffset); displayForm = Marshal.PtrToStringUni (displayFormBuffer); } if (element.pszLexicalFormOffset != 0) { IntPtr lexicalFormBuffer = new IntPtr ((long) buffer + (int) element.pszLexicalFormOffset); lexicalForm = Marshal.PtrToStringUni (lexicalFormBuffer); } if (element.pszPronunciationOffset != 0) { IntPtr pronunciationBuffer = new IntPtr ((long) buffer + (int) element.pszPronunciationOffset); pronunciation = Marshal.PtrToStringUni (pronunciationBuffer); if (!_hasIPAPronunciation) { pronunciation = _recoResult.ConvertPronunciation (pronunciation, _serializedPhrase.LangID); } } DisplayAttributes displayAttributes = RecognizedWordUnit.SapiAttributesToDisplayAttributes (element.bDisplayAttributes); // On SAPI 5.1, the engine confidence is not set. Force a value in this case if (!_isSapi53Header) { element.SREngineConfidence = 1.0f; } wordList.Add (new RecognizedWordUnit (displayForm, element.SREngineConfidence, pronunciation, lexicalForm, displayAttributes, new TimeSpan (element.ulAudioTimeOffset * TimeSpan.TicksPerMillisecond / 10000), new TimeSpan (element.ulAudioSizeTime * TimeSpan.TicksPerMillisecond / 10000))); } _words = new ReadOnlyCollection (wordList); } finally { gc.Free (); } } return _words; } } // Semantic data about result: /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Semantics"]/*' /> public SemanticValue Semantics { get { if (_serializedPhrase.SemanticErrorInfoOffset != 0) { ThrowInvalidSemanticInterpretationError (); } if (_phraseBuffer == null) { throw new NotSupportedException (); } if (_semantics == null) { CalcSemantics (Grammar); } return _semantics; } } // Homophonic alternates for this phrase /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Homophones"]/*' /> public ReadOnlyCollection Homophones { get { if (_phraseBuffer == null) { throw new NotSupportedException (); } if (_homophones == null) { // Walks the list of alternates and collects all phrases that have the same // homophoneGroupId at the phrase List homophones = new List (_recoResult.Alternates.Count); for (int i = 0; i < _recoResult.Alternates.Count; i++) { if ((_recoResult.Alternates [i]._homophoneGroupId == _homophoneGroupId) && (_recoResult.Alternates [i].Text != this.Text)) { homophones.Add (_recoResult.Alternates [i]); } } _homophones = new ReadOnlyCollection (homophones); } return _homophones; } } /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Grammar"]/*' /> public Grammar Grammar { get { // If this phrase comes from a deserialize, then throw if (_grammarId == unchecked ((UInt64) (-1))) { throw new NotSupportedException (SR.Get (SRID.CantGetPropertyFromSerializedInfo, "Grammar")); } if (_grammar == null && _recoResult.Recognizer != null) { _grammar = _recoResult.Recognizer.GetGrammarFromId (_grammarId); } return _grammar; } } /// TODOC public Collection ReplacementWordUnits { get { if (_replacementText == null) { _replacementText = new Collection (); GCHandle gc = GCHandle.Alloc (_phraseBuffer, GCHandleType.Pinned); try { IntPtr buffer = gc.AddrOfPinnedObject (); // Get the ITN and Look for replacement phrase/ IntPtr itnBuffer = new IntPtr ((long) buffer + _serializedPhrase.ReplacementsOffset); for (int i = 0; i < _serializedPhrase.cReplacements; i++, itnBuffer = (IntPtr) ((long) itnBuffer + Marshal.SizeOf (typeof (SPPHRASEREPLACEMENT)))) { SPPHRASEREPLACEMENT replacement = (SPPHRASEREPLACEMENT) Marshal.PtrToStructure (itnBuffer, typeof (SPPHRASEREPLACEMENT)); string text = Marshal.PtrToStringUni (new IntPtr ((long) buffer + replacement.pszReplacementText)); DisplayAttributes displayAttributes = RecognizedWordUnit.SapiAttributesToDisplayAttributes (replacement.bDisplayAttributes); _replacementText.Add (new ReplacementText (displayAttributes, text, (int) replacement.ulFirstElement, (int) replacement.ulCountOfElements)); } } finally { gc.Free (); } } return _replacementText; } } /// /// TODOC /// public int HomophoneGroupId { get { return _homophoneGroupId; } } #endregion //******************************************************************* // // Internal Methods // //******************************************************************** #region Internal Methods static internal SPSERIALIZEDPHRASE GetPhraseHeader (IntPtr phraseBuffer, uint expectedPhraseSize, bool isSapi53Header) { SPSERIALIZEDPHRASE serializedPhrase; if (isSapi53Header) { serializedPhrase = (SPSERIALIZEDPHRASE) Marshal.PtrToStructure (phraseBuffer, typeof (SPSERIALIZEDPHRASE)); } else { SPSERIALIZEDPHRASE_Sapi51 legacyPhrase = (SPSERIALIZEDPHRASE_Sapi51) Marshal.PtrToStructure (phraseBuffer, typeof (SPSERIALIZEDPHRASE_Sapi51)); serializedPhrase = new SPSERIALIZEDPHRASE (legacyPhrase); } if (serializedPhrase.ulSerializedSize > expectedPhraseSize) { throw new FormatException (SR.Get (SRID.ResultInvalidFormat)); } return serializedPhrase; } internal void InitializeFromSerializedBuffer (RecognitionResult recoResult, SPSERIALIZEDPHRASE serializedPhrase, IntPtr phraseBuffer, int phraseLength, bool isSapi53Header, bool hasIPAPronunciation) { _recoResult = recoResult; _isSapi53Header = isSapi53Header; _serializedPhrase = serializedPhrase; _confidence = _serializedPhrase.Rule.SREngineConfidence; _grammarId = _serializedPhrase.ullGrammarID; _homophoneGroupId = _serializedPhrase.wHomophoneGroupId; _hasIPAPronunciation = hasIPAPronunciation; // Save the phrase blob _phraseBuffer = new byte [phraseLength]; Marshal.Copy (phraseBuffer, _phraseBuffer, 0, phraseLength); // Get the grammar options _grammarOptions = recoResult.Grammar != null ? recoResult.Grammar._semanticTag : GrammarOptions.KeyValuePairSrgs; // This triggers the semantic processing if any CalcSemantics (recoResult.Grammar); } #endregion //******************************************************************* // // Internal Properties // //******************************************************************* #region Internal Properties internal ulong GrammarId { get { return _grammarId; } } internal string SmlContent { #if SPEECHSERVER set { _smlContent = value; } #endif get { if (_smlContent == null) { // this method already sets _smlContent ConstructSmlFromSemantics (); } return _smlContent; } } #endregion //******************************************************************* // // Internal Properties // //******************************************************************** #region Internal fields internal SPSERIALIZEDPHRASE _serializedPhrase; internal byte [] _phraseBuffer; internal bool _isSapi53Header; internal bool _hasIPAPronunciation; #endregion //******************************************************************* // // Private Methods // //******************************************************************** #region Private Methods // Semantic data about result: /// TODOC <_include file='doc\RecognitionResult.uex' path='docs/doc[@for="RecognitionResult.Semantics"]/*' /> private void CalcSemantics (Grammar grammar) { if (_semantics == null && _serializedPhrase.SemanticErrorInfoOffset == 0) { GCHandle gc = GCHandle.Alloc (_phraseBuffer, GCHandleType.Pinned); try { IntPtr buffer = gc.AddrOfPinnedObject (); if (!CalcILSemantics (buffer)) { // List of recognized words IListwords = Words; // Build the list of rules and property values RuleNode ruleTree = ExtractRules (grammar, _serializedPhrase.Rule, buffer); List propertyList = BuildRecoPropertyTree (_serializedPhrase, buffer, ruleTree, words, _isSapi53Header); // Recursively build the dictionary of properties _semantics = RecursiveBuildSemanticProperties (words, propertyList, ruleTree, _grammarOptions & GrammarOptions.TagFormat, ref _dupItems); #if !NO_STG // Delay the call to TryExecuteOnRecognition until the _semantics has been set _semantics.Value = TryExecuteOnRecognition (grammar, _recoResult, ruleTree._rule); #endif } } finally { gc.Free (); } } } private bool CalcILSemantics (IntPtr phraseBuffer) { if ((_grammarOptions & (GrammarOptions.MssV1 | GrammarOptions.W3cV1)) != 0 || _grammarOptions == GrammarOptions.KeyValuePairs) { IList words = Words; _semantics = new SemanticValue (" ", null, _confidence); if (_serializedPhrase.PropertiesOffset != 0) { RecursivelyExtractSemanticValue (phraseBuffer, (int) _serializedPhrase.PropertiesOffset, _semantics, words, _isSapi53Header, _grammarOptions & GrammarOptions.TagFormat); } return true; } return false; } static private List BuildRecoPropertyTree (SPSERIALIZEDPHRASE serializedPhrase, IntPtr phraseBuffer, RuleNode ruleTree, IList words, bool isSapi53Header) { List propertyList = new List (); // Array of string containing the rule names. if ((int) serializedPhrase.PropertiesOffset > 0) { RecursivelyExtractSemanticProperties (propertyList, (int) serializedPhrase.PropertiesOffset, phraseBuffer, ruleTree, words, isSapi53Header); } return propertyList; } static private SemanticValue RecursiveBuildSemanticProperties (IList words, List properties, RuleNode ruleTree, GrammarOptions semanticTag, ref Collection dupItems) { SemanticValue semanticValue = new SemanticValue (ruleTree._name, null, ruleTree._confidence); // Add the semantic values from the child rules for (RuleNode children = ruleTree._child; children != null; children = children._next) { // Propagate up the semantic values calculated at the children level SemanticValue childrenSemantics = RecursiveBuildSemanticProperties (words, properties, children, semanticTag, ref dupItems); if (!children._hasName) { foreach (KeyValuePair kv in childrenSemantics._dictionary) { InsertSemanticValueToDictionary (semanticValue, kv.Key, kv.Value, semanticTag, ref dupItems); } if (childrenSemantics.Value != null) { if ((semanticTag & (GrammarOptions.MssV1 | GrammarOptions.W3cV1)) == 0 && semanticValue._valueFieldSet && !semanticValue.Value.Equals (childrenSemantics.Value)) { throw new InvalidOperationException (SR.Get (SRID.DupSemanticValue, ruleTree._name)); } semanticValue.Value = childrenSemantics.Value; semanticValue._valueFieldSet = true; } } else { // If no value has been set then the recognized text is returned as the value if (!childrenSemantics._valueFieldSet && childrenSemantics.Count == 0) { StringBuilder sb = new StringBuilder (); for (int i = 0; i < children._count; i++) { if (sb.Length > 0) { sb.Append (" "); } sb.Append (words [(int) children._firstElement + i].Text); } childrenSemantics._valueFieldSet = true; childrenSemantics.Value = sb.ToString (); } semanticValue._dictionary.Add (children._name, childrenSemantics); } } // Add the semantic value from the properties foreach (ResultPropertiesRef property in properties) { if (property._ruleNode == ruleTree) { InsertSemanticValueToDictionary (semanticValue, property._name, property._value, semanticTag, ref dupItems); } } #if !NO_STG Exception exceptionThrown = null; // Try to execute the semantic value if OnParse is defined object newValue; bool doneOnParse = TryExecuteOnParse (ruleTree, semanticValue, words, out newValue, ref exceptionThrown); if (exceptionThrown != null) { throw exceptionThrown; } // if (doneOnParse) { semanticValue._dictionary.Clear (); semanticValue.Value = newValue; semanticValue._valueFieldSet = true; } #endif return semanticValue; } static private void RecursivelyExtractSemanticProperties (List propertyList, int semanticsOffset, IntPtr phraseBuffer, RuleNode ruleTree, IList words, bool isSapi53Header) { IntPtr propertyBuffer = new IntPtr ((long) phraseBuffer + semanticsOffset); SPSERIALIZEDPHRASEPROPERTY property = (SPSERIALIZEDPHRASEPROPERTY) Marshal.PtrToStructure (propertyBuffer, typeof (SPSERIALIZEDPHRASEPROPERTY)); string propertyName; SemanticValue thisSemanticValue = ExtractSemanticValueInformation (semanticsOffset, property, phraseBuffer, isSapi53Header, out propertyName); RuleNode node = ruleTree.Find (property.ulFirstElement, property.ulCountOfElements); if (propertyName == "SemanticKey") { node._name = (string) thisSemanticValue.Value; node._hasName = true; } else { propertyList.Add (new ResultPropertiesRef (propertyName, thisSemanticValue, node)); } if (property.pFirstChildOffset > 0) { // add children to the new node RecursivelyExtractSemanticProperties (propertyList, (int) property.pFirstChildOffset, phraseBuffer, ruleTree, words, isSapi53Header); } if (property.pNextSiblingOffset > 0) { // add siblings to parent node RecursivelyExtractSemanticProperties (propertyList, (int) property.pNextSiblingOffset, phraseBuffer, ruleTree, words, isSapi53Header); } } private void RecursivelyExtractSemanticValue (IntPtr phraseBuffer, int semanticsOffset, SemanticValue semanticValue, IList words, bool isSapi53Header, GrammarOptions semanticTag) { IntPtr propertyBuffer = new IntPtr ((long) phraseBuffer + semanticsOffset); SPSERIALIZEDPHRASEPROPERTY property = (SPSERIALIZEDPHRASEPROPERTY) Marshal.PtrToStructure (propertyBuffer, typeof (SPSERIALIZEDPHRASEPROPERTY)); string propertyName; SemanticValue thisSemanticValue = ExtractSemanticValueInformation (semanticsOffset, property, phraseBuffer, isSapi53Header, out propertyName); if (propertyName == "_value" && semanticValue != null) { // 'remove' the _value node from the tree by setting its value to the parent's value // and use the parent as the node to add children (if present) semanticValue.Value = thisSemanticValue.Value; if (property.pFirstChildOffset > 0) { thisSemanticValue = semanticValue; } } else { InsertSemanticValueToDictionary (semanticValue, propertyName, thisSemanticValue, semanticTag, ref _dupItems); } if (property.pFirstChildOffset > 0) { // add children to the new node RecursivelyExtractSemanticValue (phraseBuffer, (int) property.pFirstChildOffset, thisSemanticValue, words, isSapi53Header, semanticTag); } if (property.pNextSiblingOffset > 0) { // add siblings to parent node RecursivelyExtractSemanticValue (phraseBuffer, (int) property.pNextSiblingOffset, semanticValue, words, isSapi53Header, semanticTag); } } static private void InsertSemanticValueToDictionary (SemanticValue semanticValue, string propertyName, SemanticValue thisSemanticValue, GrammarOptions semanticTag, ref Collection dupItems) { string key = propertyName; if ((key == "$" && semanticTag == GrammarOptions.MssV1) || (key == "=" && (semanticTag == GrammarOptions.KeyValuePairSrgs || semanticTag == GrammarOptions.KeyValuePairs)) || (thisSemanticValue.Count == -1 && semanticTag == GrammarOptions.W3cV1)) { if ((semanticTag & (GrammarOptions.MssV1 | GrammarOptions.W3cV1)) == 0 && semanticValue._valueFieldSet && !semanticValue.Value.Equals (thisSemanticValue.Value)) { throw new InvalidOperationException (SR.Get (SRID.DupSemanticValue, semanticValue.KeyName)); } semanticValue.Value = thisSemanticValue.Value; semanticValue._valueFieldSet = true; } else { bool containsKey = semanticValue._dictionary.ContainsKey (key); if (!containsKey) { semanticValue._dictionary.Add (key, thisSemanticValue); } else { if (!semanticValue._dictionary [key].Equals (thisSemanticValue)) { // Error out for Srgs grammars if (semanticTag == GrammarOptions.KeyValuePairSrgs) { throw new InvalidOperationException (SR.Get (SRID.DupSemanticKey, propertyName, semanticValue.KeyName)); } // Append a _* on the key name for none SAPI grammars int count = 0; do { key = propertyName + string.Format (CultureInfo.InvariantCulture, "_{0}", count++); } while (semanticValue._dictionary.ContainsKey (key)); semanticValue._dictionary.Add (key, thisSemanticValue); if (dupItems == null) { dupItems = new Collection (); } SemanticValue s = semanticValue._dictionary [key]; dupItems.Add (s); } } } } static private SemanticValue ExtractSemanticValueInformation (int semanticsOffset, SPSERIALIZEDPHRASEPROPERTY property, IntPtr phraseBuffer, bool isSapi53Header, out string propertyName) { object propertyValue; bool isIdName = false; if (property.pszNameOffset > 0) { IntPtr nameBuffer = new IntPtr ((long) phraseBuffer + (int) property.pszNameOffset); propertyName = Marshal.PtrToStringUni (nameBuffer); } else { propertyName = property.ulId.ToString (CultureInfo.InvariantCulture); isIdName = true; } if (property.pszValueOffset > 0) { IntPtr valueStringBuffer = new IntPtr ((long) phraseBuffer + (int) property.pszValueOffset); propertyValue = Marshal.PtrToStringUni (valueStringBuffer); if (!isSapi53Header && isIdName && ((string) propertyValue).Contains ("$")) { // SAPI 5.1 result that contains script fragments rather than output of executing script. // Strip this information as script-based grammars aren't supported on 5.1. throw new NotSupportedException (SR.Get (SRID.NotSupportedWithThisVersionOfSAPI)); } } else { if (property.SpVariantSubset >= 0) { IntPtr valueBuffer = new IntPtr ((long) phraseBuffer + +semanticsOffset + SpVariantSubsetOffset); switch ((VarEnum) property.vValue) { case VarEnum.VT_I4: propertyValue = Marshal.ReadInt32 (valueBuffer); break; case VarEnum.VT_UI4: propertyValue = Marshal.PtrToStructure (valueBuffer, typeof (UInt32)); break; case VarEnum.VT_I8: propertyValue = Marshal.ReadInt64 (valueBuffer); break; case VarEnum.VT_UI8: propertyValue = Marshal.PtrToStructure (valueBuffer, typeof (UInt64)); break; case VarEnum.VT_R4: propertyValue = Marshal.PtrToStructure (valueBuffer, typeof (float)); break; case VarEnum.VT_R8: propertyValue = Marshal.PtrToStructure (valueBuffer, typeof (double)); break; case VarEnum.VT_BOOL: propertyValue = (Marshal.ReadByte (valueBuffer) != 0); break; case VarEnum.VT_EMPTY: propertyValue = null; break; default: throw new NotSupportedException (SR.Get (SRID.UnhandledVariant)); } } else { propertyValue = String.Empty; } } return new SemanticValue (propertyName, propertyValue, property.SREngineConfidence); } static private RuleNode ExtractRules (Grammar grammar, SPSERIALIZEDPHRASERULE rule, IntPtr phraseBuffer) { // Get the rule name IntPtr nameBuffer = new IntPtr ((long) phraseBuffer + (int) rule.pszNameOffset); // Add the rule name to the proper element index string name = Marshal.PtrToStringUni (nameBuffer); // find the grammar for this rule. If the grammar does not belong to any existing ruleref then // it must be local. #if !NO_STG Grammar ruleRef = grammar != null ? grammar.Find (name) : null; if (ruleRef != null) { grammar = ruleRef; } #endif RuleNode node = new RuleNode (grammar, name, rule.SREngineConfidence, rule.ulFirstElement,rule.ulCountOfElements); if (rule.NextSiblingOffset > 0) { IntPtr elementBuffer = new IntPtr ((long) phraseBuffer + rule.NextSiblingOffset); SPSERIALIZEDPHRASERULE ruleNext = (SPSERIALIZEDPHRASERULE) Marshal.PtrToStructure (elementBuffer, typeof (SPSERIALIZEDPHRASERULE)); node._next = ExtractRules (grammar, ruleNext, phraseBuffer); } if (rule.FirstChildOffset > 0) { IntPtr elementBuffer = new IntPtr ((long) phraseBuffer + rule.FirstChildOffset); SPSERIALIZEDPHRASERULE ruleFirst = (SPSERIALIZEDPHRASERULE) Marshal.PtrToStructure (elementBuffer, typeof (SPSERIALIZEDPHRASERULE)); node._child = ExtractRules (grammar, ruleFirst, phraseBuffer); } return node; } private void ThrowInvalidSemanticInterpretationError () { //string error; if (!_isSapi53Header) { throw new NotSupportedException (SR.Get (SRID.NotSupportedWithThisVersionOfSAPI)); } GCHandle gc = GCHandle.Alloc (_phraseBuffer, GCHandleType.Pinned); try { IntPtr smlBuffer = gc.AddrOfPinnedObject (); SPSEMANTICERRORINFO semanticError = (SPSEMANTICERRORINFO) Marshal.PtrToStructure ((IntPtr) ((long) smlBuffer + (int) _serializedPhrase.SemanticErrorInfoOffset), typeof (SPSEMANTICERRORINFO)); string source = Marshal.PtrToStringUni (new IntPtr ((long) smlBuffer + semanticError.pszSourceOffset)); string description = Marshal.PtrToStringUni (new IntPtr ((long) smlBuffer + semanticError.pszDescriptionOffset)); string script = Marshal.PtrToStringUni (new IntPtr ((long) smlBuffer + semanticError.pszScriptLineOffset)); string error = string.Format (CultureInfo.InvariantCulture, "Error while evaluating semantic interpretation:\n" + " HRESULT: {0:x}\n" + " Line: {1}\n" + " Source: {2}\n" + " Description: {3}\n" + " Script: {4}\n", semanticError.hrResultCode, semanticError.ulLineNumber, source, description, script); throw new InvalidOperationException (error); } finally { gc.Free (); } } #if !NO_STG static private bool TryExecuteOnParse (RuleNode ruleRef, SemanticValue value, IList words, out object newValue, ref Exception exceptionThrown) { newValue = null; bool doneOnParse = false; Grammar grammar = ruleRef._grammar; if (grammar != null && grammar._scripts != null) { // Check if the Inner try { if (exceptionThrown == null) { doneOnParse = ExecuteOnParse (grammar, ruleRef, value, words, out newValue); } else { if (ExecuteOnError (grammar, ruleRef, exceptionThrown)) { exceptionThrown = null; } } } catch (Exception e) { if (exceptionThrown == null) { exceptionThrown = e; // Try to execute on Error on this thread try { if (ExecuteOnError (grammar, ruleRef, exceptionThrown)) { exceptionThrown = null; } } catch (Exception e2) { exceptionThrown = e2; } } } } return doneOnParse; } private static bool ExecuteOnParse (Grammar grammar, RuleNode ruleRef, SemanticValue value, IList words, out object newValue) { // Get the rule list ScriptRef [] scripts = grammar._scripts; bool doneOnParse = false; newValue = null; // Look if an OnParse exist for this method for (int iScript = 0; iScript < scripts.Length; iScript++) { ScriptRef script = scripts [iScript]; if (ruleRef._rule == script._rule) { if (script._method == RuleMethodScript.onParse) { // Get the method to invoke RecognizedWordUnit [] recoUnits = new RecognizedWordUnit [ruleRef._count]; for (int i = 0; i < ruleRef._count; i++) { recoUnits [i] = words [i]; } object [] parameters = new object [2] { value, recoUnits }; if (grammar._proxy != null) { Exception appDomainException; newValue = grammar._proxy.OnParse (script._rule, script._sMethod, parameters, out appDomainException); if (appDomainException != null) { throw appDomainException; } } else { MethodInfo onParse; System.Speech.Recognition.Grammar rule; GetRuleInstance (grammar, script._rule, script._sMethod, out onParse, out rule); // Execute the parse routine newValue = onParse.Invoke (rule, parameters); } doneOnParse = true; } } } return doneOnParse; } private static bool ExecuteOnError (Grammar grammar, RuleNode ruleRef, Exception e) { // Get the rule list ScriptRef [] scripts = grammar._scripts; bool invoked = false; // Look if an OnParse exist for this method for (int iScript = 0; iScript < scripts.Length; iScript++) { ScriptRef script = scripts [iScript]; if (ruleRef._rule == script._rule) { if (script._method == RuleMethodScript.onError) { // Get the method to invoke object [] parameters = new object [] { e }; if (grammar._proxy != null) { Exception appDomainException; grammar._proxy.OnError (script._rule, script._sMethod, parameters, out appDomainException); if (appDomainException != null) { throw appDomainException; } } else { MethodInfo onError; System.Speech.Recognition.Grammar rule; GetRuleInstance (grammar, script._rule, script._sMethod, out onError, out rule); // Execute the parse routine onError.Invoke (rule, parameters); } invoked = true; } } } return invoked; } private static object TryExecuteOnRecognition (Grammar grammar, RecognitionResult result, string rootRule) { object resultValue = result.Semantics.Value; if (grammar != null && grammar._scripts != null) { // Get the rule list ScriptRef [] scripts = grammar._scripts; // Look if an OnRecognition exist for this method for (int iScript = 0; iScript < scripts.Length; iScript++) { ScriptRef script = scripts [iScript]; if (rootRule == script._rule) { if (script._method == RuleMethodScript.onRecognition) { // Get the method to invoke object [] parameters = new object [1] { result }; if (grammar._proxy != null) { Exception appDomainException; resultValue = grammar._proxy.OnRecognition (script._sMethod, parameters, out appDomainException); if (appDomainException != null) { throw appDomainException; } } else { Type grammarType = grammar.GetType (); MethodInfo onRecognition = grammarType.GetMethod (script._sMethod, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); // Execute the parse routine resultValue = onRecognition.Invoke (grammar, parameters); } } } } } return resultValue; } #endif #if !SPEECHSERVER static private void GetRuleInstance (Grammar grammar, string rule, string method, out MethodInfo onParse, out Grammar ruleInstance) { Type grammarType = grammar.GetType (); Assembly assembly = grammarType.Assembly; Type ruleClass = rule == grammarType.Name ? grammarType : GetTypeForRule (assembly, rule); if (ruleClass == null || !ruleClass.IsSubclassOf (typeof (System.Speech.Recognition.Grammar))) { throw new FormatException (SR.Get (SRID.RecognizerInvalidBinaryGrammar)); } ruleInstance = ruleClass == grammarType ? grammar : (System.Speech.Recognition.Grammar) assembly.CreateInstance (ruleClass.FullName); onParse = ruleInstance.MethodInfo (method); } static private Type GetTypeForRule (Assembly assembly, string rule) { Type [] types = assembly.GetTypes (); for (int iType = 0; iType < types.Length; iType++) { Type type = types [iType]; if (type.Name == rule && type.IsPublic && type.IsSubclassOf (typeof (System.Speech.Recognition.Grammar))) { return type; } } return null; } #endif static private int NextReplacementWord (Collection replacements, out ReplacementText replacement, ref int posInCollection) { if (posInCollection < replacements.Count) { replacement = replacements [posInCollection++]; return replacement.FirstWordIndex; } else { replacement = null; return -1; } } private void AppendSml (XmlDocument document, int i, NumberFormatInfo nfo) { XmlNode root = document.DocumentElement; XmlElement alternateNode = document.CreateElement ("alternate"); root.AppendChild (alternateNode); alternateNode.SetAttribute ("Rank", i.ToString (CultureInfo.CurrentUICulture)); alternateNode.SetAttribute ("text", Text); alternateNode.SetAttribute ("utteranceConfidence", Confidence.ToString ("f", nfo)); alternateNode.SetAttribute ("confidence", Confidence.ToString ("f", nfo)); if (_semantics.Value != null) { XmlText valueText = document.CreateTextNode (_semantics.Value.ToString ()); alternateNode.AppendChild (valueText); } // recursively add the properties now AppendPropertiesSML (document, alternateNode, _semantics, nfo); } private void AppendPropertiesSML (XmlDocument document, XmlElement alternateNode, SemanticValue semanticsNode, NumberFormatInfo nfo) { if (semanticsNode != null) { foreach (KeyValuePair kv in semanticsNode) { if (kv.Key == "_attributes") { // all the attributes are located under the attribute property. AppendAttributes (alternateNode, kv.Value); if (string.IsNullOrEmpty (alternateNode.InnerText) && semanticsNode.Value != null) { XmlText valueText = document.CreateTextNode (semanticsNode.Value.ToString ()); alternateNode.AppendChild (valueText); } } else { string keyName = kv.Key; if (_dupItems != null && _dupItems.Contains (kv.Value)) { keyName = RemoveTrailingNumber (kv.Key); } XmlElement propertyNode = document.CreateElement (keyName); propertyNode.SetAttribute ("confidence", semanticsNode [kv.Key].Confidence.ToString ("f", nfo)); alternateNode.AppendChild (propertyNode); if (kv.Value.Count > 0) { if (kv.Value.Value != null) { XmlText valueText = document.CreateTextNode (kv.Value.Value.ToString ()); propertyNode.AppendChild (valueText); } AppendPropertiesSML (document, propertyNode, kv.Value, nfo); } else if (kv.Value.Value != null) { XmlText valueText = document.CreateTextNode (kv.Value.Value.ToString ()); propertyNode.AppendChild (valueText); } } } } } private string RemoveTrailingNumber (string name) { return name.Substring (0, name.LastIndexOf ('_')); } private void AppendAttributes (XmlElement propertyNode, SemanticValue semanticValue) { foreach (KeyValuePair kv in semanticValue) { if (propertyNode.Attributes [kv.Key] == null) { propertyNode.SetAttribute (kv.Key, kv.Value.Value.ToString ()); } } } #if VSCOMPILE static private void DumpAll (RuleNode ruleTree, IList words, SPSERIALIZEDPHRASE serializedPhrase, IntPtr phraseBuffer, bool isSapi53Header) { DumpWords (words); Console.WriteLine ("Rules"); DumpRules (0, ruleTree); if (serializedPhrase.PropertiesOffset != 0) { Console.WriteLine ("Semantics"); DumpSemantics (0, (int) serializedPhrase.PropertiesOffset, phraseBuffer, isSapi53Header); } else { Console.WriteLine ("No Semantics"); } } static private void DumpWords (IList words) { StringBuilder sb = new StringBuilder (); foreach (RecognizedWordUnit word in words) { sb.Append (word.Text + " "); } Console.WriteLine (sb.ToString ()); } static private void DumpRules (int depth, RuleNode node) { StringBuilder sb = new StringBuilder (); for (int i = 0; i < depth; i++) { sb.Append ("----"); } Console.WriteLine (sb.ToString () + " " + node._rule + "[" + node._firstElement + "," + node._firstElement + node._count + "," + "]"); if (node._next != null) { DumpRules (depth, node._next); } if (node._child != null) { DumpRules (depth + 1, node._child); } } static private void DumpSemantics (int depth, int semanticsOffset, IntPtr phraseBuffer, bool isSapi53Header) { IntPtr propertyBuffer = new IntPtr ((long) phraseBuffer + semanticsOffset); SPSERIALIZEDPHRASEPROPERTY property = (SPSERIALIZEDPHRASEPROPERTY) Marshal.PtrToStructure (propertyBuffer, typeof (SPSERIALIZEDPHRASEPROPERTY)); StringBuilder sb = new StringBuilder (); for (int i = 0; i < depth; i++) { sb.Append ("----"); } string propertyName; SemanticValue thisSemanticValue = ExtractSemanticValueInformation (semanticsOffset, property, phraseBuffer, isSapi53Header, out propertyName); Console.WriteLine (sb.ToString () + " " + propertyName + "[" + property.ulFirstElement + "," + property.ulCountOfElements + "," + property.ulId + "]"); if (property.pNextSiblingOffset > 0) { // add siblings to parent node DumpSemantics (depth, (int) property.pNextSiblingOffset, phraseBuffer, isSapi53Header); } if (property.pFirstChildOffset > 0) { // add children to the new node DumpSemantics (depth + 1, (int) property.pFirstChildOffset, phraseBuffer, isSapi53Header); } } #endif #endregion //******************************************************************** // // Private Types // //******************************************************************* #region Private Types #if VSCOMPILE [DebuggerDisplay ("{DisplayDebugInfo ()}")] #endif private class RuleNode { internal RuleNode (Grammar grammar, string rule, float confidence, uint first, uint count) { _rule = _name = rule; _firstElement = first; _count = count; _confidence = confidence; _grammar = grammar; //_ruleId = id; } /// /// Find the rule enclosing a property. /// /// First word mathcing the property /// Count of words ///internal RuleNode Find (uint firstElement, uint count) { // If the count of word is set to zero. It means that the tag is located just before a word. // The trick here is to use 1/2 position to locate tags in this case. float firstWord, lastWord; if (count == 0) { firstWord = lastWord = firstElement - 0.5f; } else { firstWord = (float) firstElement; lastWord = firstWord + (count - 1); } for (RuleNode child = _child; child != null; child = child._next) { float ruleFirstWord, ruleLastWord; if (child._count == 0) { ruleFirstWord = ruleLastWord = child._firstElement - 0.5f; } else { ruleFirstWord = (float) child._firstElement; ruleLastWord = ruleFirstWord + (child._count - 1); } if (ruleFirstWord <= firstElement && ruleLastWord >= lastWord) { return child.Find (firstElement, count); } } return this; } #if VSCOMPILE private string DisplayDebugInfo () { return string.Format ("'rule={0}", _rule); } #endif internal Grammar _grammar; internal string _rule; internal string _name; internal uint _firstElement; internal uint _count; //internal int _ruleId; internal float _confidence; internal bool _hasName; internal RuleNode _next; internal RuleNode _child; } #if VSCOMPILE [DebuggerDisplay ("Name={_name} node={_ruleNode._rule} value={_value != null && _value.Value != null ? _value.Value.ToString() : \"\"}")] #endif private struct ResultPropertiesRef { internal string _name; internal SemanticValue _value; internal RuleNode _ruleNode; internal ResultPropertiesRef (string name, SemanticValue value, RuleNode ruleNode) { _name = name; _value = value; _ruleNode = ruleNode; } } #endregion //******************************************************************** // // Private Fields // //******************************************************************* #region Private Fields private RecognitionResult _recoResult; private GrammarOptions _grammarOptions; private string _text; private float _confidence; private SemanticValue _semantics; private ReadOnlyCollection _words; private Collection _replacementText; [NonSerializedAttribute] private UInt64 _grammarId = unchecked ((UInt64) (-1)); #pragma warning disable 6524 [NonSerializedAttribute] private Grammar _grammar; #pragma warning restore 6524 private int _homophoneGroupId; private ReadOnlyCollection _homophones; private Collection _dupItems; private string _smlContent; private const int SpVariantSubsetOffset = 16; #endregion } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- Parser.cs
- TextDecorationCollection.cs
- ExtentCqlBlock.cs
- EncoderNLS.cs
- BinarySerializer.cs
- ContextMenuAutomationPeer.cs
- TextSpanModifier.cs
- AxImporter.cs
- SqlTypeSystemProvider.cs
- MissingMemberException.cs
- IdentitySection.cs
- DuplexChannelBinder.cs
- FixedSOMTextRun.cs
- AcceptorSessionSymmetricTransportSecurityProtocol.cs
- AnonymousIdentificationModule.cs
- FileDialogCustomPlacesCollection.cs
- GenericXmlSecurityToken.cs
- HelpEvent.cs
- EntityContainerAssociationSetEnd.cs
- ZipIOZip64EndOfCentralDirectoryBlock.cs
- Utils.cs
- NonceToken.cs
- ConfigurationSettings.cs
- SplitterPanel.cs
- InputProcessorProfiles.cs
- DrawingGroupDrawingContext.cs
- Utilities.cs
- LinqDataSourceContextEventArgs.cs
- IRCollection.cs
- UIElementParaClient.cs
- assemblycache.cs
- EmptyImpersonationContext.cs
- PublisherIdentityPermission.cs
- StrongNameUtility.cs
- ConfigXmlElement.cs
- AsyncPostBackErrorEventArgs.cs
- Property.cs
- ItemCheckEvent.cs
- StringPropertyBuilder.cs
- IdentityHolder.cs
- OdbcErrorCollection.cs
- PageCatalogPart.cs
- XmlArrayItemAttributes.cs
- XpsManager.cs
- StyleBamlTreeBuilder.cs
- CodeSubDirectory.cs
- EntityCommand.cs
- SqlBooleanMismatchVisitor.cs
- DesignerProperties.cs
- ToolboxBitmapAttribute.cs
- HttpApplicationFactory.cs
- counter.cs
- RequestNavigateEventArgs.cs
- SingletonChannelAcceptor.cs
- Transform3D.cs
- BamlTreeMap.cs
- ProxyGenerationError.cs
- UrlEncodedParameterWriter.cs
- Color.cs
- securitycriticaldataformultiplegetandset.cs
- Main.cs
- ColorMatrix.cs
- Int32.cs
- PropertyGridView.cs
- SchemaImporter.cs
- PointCollection.cs
- XMLDiffLoader.cs
- FontUnitConverter.cs
- ListControlConvertEventArgs.cs
- FlowLayoutPanel.cs
- TransformConverter.cs
- SymbolType.cs
- MachineKeyConverter.cs
- EntityTypeEmitter.cs
- BrushMappingModeValidation.cs
- AnalyzedTree.cs
- ZipIOExtraFieldPaddingElement.cs
- HGlobalSafeHandle.cs
- StateValidator.cs
- Vector3DAnimationBase.cs
- SmiXetterAccessMap.cs
- TypeConverterValueSerializer.cs
- LiteralControl.cs
- AsymmetricKeyExchangeFormatter.cs
- TimerElapsedEvenArgs.cs
- DecimalConverter.cs
- SqlServices.cs
- IntellisenseTextBox.designer.cs
- DbConnectionStringCommon.cs
- BamlRecordWriter.cs
- TileModeValidation.cs
- Addressing.cs
- HttpModuleAction.cs
- ExtensionDataObject.cs
- RequestBringIntoViewEventArgs.cs
- FormParameter.cs
- HotSpotCollection.cs
- PolyBezierSegment.cs
- BoolExpr.cs
- BinaryReader.cs