// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #nullable disable // Description: Data model for the Bracket characters specified on a Markup Extension property. using System; using System.Collections.Generic; using System.ComponentModel; using System.Text; namespace MS.Internal.Xaml.Parser { /// <summary> /// Class that provides helper functions for the parser/Xaml Reader /// to process Bracket Characters specified on a Markup Extension Property /// </summary> internal class SpecialBracketCharacters : ISupportInitialize { private string _startChars; private string _endChars; private static readonly ISet<char> _restrictedCharSet = new SortedSet<char>((new char[] { '=', ',', '\'', '"', '{', '}', '\\' })); private bool _initializing; private StringBuilder _startCharactersStringBuilder; private StringBuilder _endCharactersStringBuilder; internal SpecialBracketCharacters() { BeginInit(); } internal SpecialBracketCharacters(IReadOnlyDictionary<char, char> attributeList) { BeginInit(); if (attributeList is not null && attributeList.Count > 0) { Tokenize(attributeList); } } internal void AddBracketCharacters(char openingBracket, char closingBracket) { if (_initializing) { _startCharactersStringBuilder.Append(openingBracket); _endCharactersStringBuilder.Append(closingBracket); } else { throw new InvalidOperationException(); } } private void Tokenize(IReadOnlyDictionary<char, char> attributeList) { if (_initializing) { foreach (char openingBracket in attributeList.Keys) { char closingBracket = attributeList[openingBracket]; string errorMessage = string.Empty; if (IsValidBracketCharacter(openingBracket, closingBracket)) { _startCharactersStringBuilder.Append(openingBracket); _endCharactersStringBuilder.Append(closingBracket); } } } } private bool IsValidBracketCharacter(char openingBracket, char closingBracket) { if (openingBracket == closingBracket) { throw new InvalidOperationException("Opening bracket character cannot be the same as closing bracket character."); } else if (char.IsLetterOrDigit(openingBracket) || char.IsLetterOrDigit(closingBracket) || char.IsWhiteSpace(openingBracket) || char.IsWhiteSpace(closingBracket)) { throw new InvalidOperationException("Bracket characters cannot be alpha-numeric or whitespace."); } else if (_restrictedCharSet.Contains(openingBracket) || _restrictedCharSet.Contains(closingBracket)) { throw new InvalidOperationException("Bracket characters cannot be one of the following: '=' , ',', '\'', '\"', '{ ', ' }', '\\'"); } else { return true; } } internal bool IsSpecialCharacter(char ch) { return _startChars.Contains(ch.ToString()) || _endChars.Contains(ch.ToString()); } internal bool StartsEscapeSequence(char ch) { return _startChars.Contains(ch.ToString()); } internal bool EndsEscapeSequence(char ch) { return _endChars.Contains(ch.ToString()); } internal bool Match(char start, char end) { return _endChars.IndexOf(end.ToString(), StringComparison.Ordinal) == _startChars.IndexOf(start.ToString(), StringComparison.Ordinal); } internal string StartBracketCharacters { get { return _startChars; } } internal string EndBracketCharacters { get { return _endChars; } } public void BeginInit() { _initializing = true; _startCharactersStringBuilder = new StringBuilder(); _endCharactersStringBuilder = new StringBuilder(); } public void EndInit() { _startChars = _startCharactersStringBuilder.ToString(); _endChars = _endCharactersStringBuilder.ToString(); _initializing = false; } } } |