File: Recognition\SrgsGrammar\SrgsToken.cs
Web Access
Project: src\src\runtime\src\libraries\System.Speech\src\System.Speech.csproj (System.Speech)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Speech.Internal;
using System.Speech.Internal.SrgsParser;
using System.Text;
using System.Xml;

namespace System.Speech.Recognition.SrgsGrammar
{
    // Note that currently if multiple words are stored in a Token they are treated internally
    // and in the result as multiple tokens.
    [Serializable]
    [DebuggerDisplay("{DebuggerDisplayString()}")]
    public class SrgsToken : SrgsElement, IToken
    {
        #region Constructors
        public SrgsToken(string text)
        {
            Helpers.ThrowIfEmptyOrNull(text, nameof(text));
            Text = text;
        }

        #endregion

        #region public Properties
        public string Text
        {
            get
            {
                return _text;
            }
            set
            {
                Helpers.ThrowIfEmptyOrNull(value, nameof(value));

                // remove all spaces if any
                string text = value.Trim(Helpers._achTrimChars);
                if (string.IsNullOrEmpty(text) || text.Contains('\"'))
                {
                    throw new ArgumentException(SR.Get(SRID.InvalidTokenString), nameof(value));
                }
                _text = text;
            }
        }

        [DisallowNull]
        public string? Pronunciation
        {
            get
            {
                return _pronunciation;
            }
            set
            {
                Helpers.ThrowIfEmptyOrNull(value, nameof(value));
                _pronunciation = value;
            }
        }

        [DisallowNull]
        public string? Display
        {
            get
            {
                return _display;
            }
            set
            {
                Helpers.ThrowIfEmptyOrNull(value, nameof(value));
                _display = value;
            }
        }

        #endregion

        #region Internal methods

        internal override void WriteSrgs(XmlWriter writer)
        {
            // Write <token sapi:pron="_pronunciation">_text</token>
            writer.WriteStartElement("token");

            if (_display != null)
            {
                writer.WriteAttributeString("sapi", "display", XmlParser.sapiNamespace, _display);
            }

            if (_pronunciation != null)
            {
                writer.WriteAttributeString("sapi", "pron", XmlParser.sapiNamespace, _pronunciation);
            }

            // If an empty string is provided, skip the WriteString
            // to have the XmlWrite to put <token/> rather than <token></token>
            if (_text != null && _text.Length > 0)
            {
                writer.WriteString(_text);
            }
            writer.WriteEndElement();
        }

        internal override void Validate(SrgsGrammar grammar)
        {
            if (_pronunciation != null || _display != null)
            {
                grammar.HasPronunciation = true;
            }

            // Validate the pronunciation if any
            if (_pronunciation != null)
            {
                for (int iCurPron = 0, iDeliminator = 0; iCurPron < _pronunciation.Length; iCurPron = iDeliminator + 1)
                {
                    // Find semi-colon delimiter and replace with null
                    iDeliminator = _pronunciation.IndexOf(';', iCurPron);
                    if (iDeliminator == -1)
                    {
                        iDeliminator = _pronunciation.Length;
                    }

                    string subPronunciation = _pronunciation.Substring(iCurPron, iDeliminator - iCurPron);

                    // Convert the pronunciation, will throw if error
                    switch (grammar.PhoneticAlphabet)
                    {
                        case AlphabetType.Sapi:
                            PhonemeConverter.ConvertPronToId(subPronunciation, grammar.Culture.LCID);
                            break;

                        case AlphabetType.Ups:
                            PhonemeConverter.UpsConverter.ConvertPronToId(subPronunciation);
                            break;

                        case AlphabetType.Ipa:
                            PhonemeConverter.ValidateUpsIds(subPronunciation.ToCharArray());
                            break;
                    }
                }
            }

            base.Validate(grammar);
        }

        internal override string DebuggerDisplayString()
        {
            StringBuilder sb = new("Token = '");
            sb.Append(_text);
            sb.Append('\'');

            if (_pronunciation != null)
            {
                sb.Append(", Pronunciation = '");
                sb.Append(_pronunciation);
                sb.Append('\'');
            }
            return sb.ToString();
        }

        #endregion

        #region Private Fields

        private string _text = string.Empty;

        private string? _pronunciation;

        private string? _display;

        #endregion
    }
}