| File: Internal\StringBlob.cs | Web Access |
| Project: 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.Collections.Generic; namespace System.Speech.Internal { internal class StringBlob { #region Constructors internal StringBlob() { } internal StringBlob(char[] pszStringArray) { int cch = pszStringArray.Length; if (cch > 0) { // First string is always empty. if (pszStringArray[0] != 0) { throw new FormatException(SR.Get(SRID.RecognizerInvalidBinaryGrammar)); } // First pass to copy data and count strings. for (int iPos = 1, iEnd = cch, iStart = 1; iPos < iEnd; iPos++) { if (pszStringArray[iPos] == '\0') { string sWord = new(pszStringArray, iStart, iPos - iStart); _refStrings.Add(sWord); _offsetStrings.Add(_totalStringSizes); _strings.Add(sWord, ++_cWords); _totalStringSizes += sWord.Length + 1; iStart = iPos + 1; } } } } #endregion #region internal Methods // // The ID for a null string is always 0, the ID for subsequent strings is the // index of the string + 1; // internal int Add(string? psz, out int idWord) { int offset = 0; idWord = 0; if (!string.IsNullOrEmpty(psz)) { // Check if the string is already in the table if (!_strings.TryGetValue(psz, out idWord)) { System.Diagnostics.Debug.Assert(_strings.Count == _refStrings.Count); // No add it to the string table idWord = ++_cWords; offset = _totalStringSizes; _refStrings.Add(psz); _offsetStrings.Add(offset); _strings.Add(psz, _cWords); _totalStringSizes += psz.Length + 1; } else { offset = OffsetFromId(idWord); } } return offset; } // Returns idWord; use IndexFromId to recover string offset internal int Find(string? psz) { // Compatibility the SAPI version if (string.IsNullOrEmpty(psz) || _cWords == 0) { return 0; } // Use the dictionary to find the value int iWord; return _strings.TryGetValue(psz, out iWord) ? iWord : -1; } internal string this[int index] { get { if ((index < 1) || index > _cWords) { throw new InvalidOperationException(); } return _refStrings[index - 1]; } } /// <summary> /// Only DEBUG code should use this /// </summary> internal string? FromOffset(int offset) { int iPos = 1; int iWord = 1; System.Diagnostics.Debug.Assert(offset > 0); if (offset == 1 && _cWords >= 1) { return this[iWord]; } foreach (string s in _refStrings) { iWord++; iPos += s.Length + 1; if (offset == iPos) { return this[iWord]; } } return null; } internal int StringSize() { return _cWords > 0 ? _totalStringSizes : 0; } internal int SerializeSize() { return ((StringSize() * _sizeOfChar + 3) & ~3) / 2; } internal char[] SerializeData() { // force a 0xcccc at the end of the buffer if the length is odd int iEnd = SerializeSize(); char[] aData = new char[iEnd]; // aData [0] is set by the framework to zero int iPos = 1; foreach (string s in _refStrings) { for (int i = 0; i < s.Length; i++) { aData[iPos++] = s[i]; } aData[iPos++] = '\0'; } if (StringSize() % 2 == 1) { aData[iPos++] = (char)0xCCCC; } System.Diagnostics.Debug.Assert(iEnd == 0 || iPos == SerializeSize()); return aData; } internal int OffsetFromId(int index) { System.Diagnostics.Debug.Assert(index <= _cWords); if (index > 0) { return _offsetStrings[index - 1]; } return 0; } #endregion #region internal Properties internal int Count { get { return _cWords; } } #endregion #region Private Fields // List of words, end-to-end private Dictionary<string, int> _strings = new(); // List of indices in the dictionary of words private List<string> _refStrings = new(); // List of indices in the dictionary of words private List<int> _offsetStrings = new(); // Number of words private int _cWords; // Cached value for the total string sizes - The first digit is always zero. private int _totalStringSizes = 1; // .NET is Unicode so 2 bytes per characters private const int _sizeOfChar = 2; #endregion } }