#region Apache License // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to you under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #endregion using System; using System.Text; using System.Xml; using System.Text.RegularExpressions; namespace log4net.Util { /// /// Utility class for transforming strings. /// /// /// /// Utility class for transforming strings. /// /// /// Nicko Cadell /// Gert Driesen public sealed class Transform { #region Private Instance Constructors /// /// Initializes a new instance of the class. /// /// /// /// Uses a private access modifier to prevent instantiation of this class. /// /// private Transform() { } #endregion Private Instance Constructors #region XML String Methods /// /// Write a string to an /// /// the writer to write to /// the string to write /// The string to replace non XML compliant chars with /// /// /// The test is escaped either using XML escape entities /// or using CDATA sections. /// /// public static void WriteEscapedXmlString(XmlWriter writer, string textData, string invalidCharReplacement) { string stringData = MaskXmlInvalidCharacters(textData, invalidCharReplacement); // Write either escaped text or CDATA sections int weightCData = 12 * (1 + CountSubstrings(stringData, CDATA_END)); int weightStringEscapes = 3*(CountSubstrings(stringData, "<") + CountSubstrings(stringData, ">")) + 4*CountSubstrings(stringData, "&"); if (weightStringEscapes <= weightCData) { // Write string using string escapes writer.WriteString(stringData); } else { // Write string using CDATA section int end = stringData.IndexOf(CDATA_END); if (end < 0) { writer.WriteCData(stringData); } else { int start = 0; while (end > -1) { writer.WriteCData(stringData.Substring(start, end - start)); if (end == stringData.Length - 3) { start = stringData.Length; writer.WriteString(CDATA_END); break; } else { writer.WriteString(CDATA_UNESCAPABLE_TOKEN); start = end + 2; end = stringData.IndexOf(CDATA_END, start); } } if (start < stringData.Length) { writer.WriteCData(stringData.Substring(start)); } } } } /// /// Replace invalid XML characters in text string /// /// the XML text input string /// the string to use in place of invalid characters /// A string that does not contain invalid XML characters. /// /// /// Certain Unicode code points are not allowed in the XML InfoSet, for /// details see: http://www.w3.org/TR/REC-xml/#charsets. /// /// /// This method replaces any illegal characters in the input string /// with the mask string specified. /// /// public static string MaskXmlInvalidCharacters(string textData, string mask) { return INVALIDCHARS.Replace(textData, mask); } #endregion XML String Methods #region Private Helper Methods /// /// Count the number of times that the substring occurs in the text /// /// the text to search /// the substring to find /// the number of times the substring occurs in the text /// /// /// The substring is assumed to be non repeating within itself. /// /// private static int CountSubstrings(string text, string substring) { int count = 0; int offset = 0; int length = text.Length; int substringLength = substring.Length; if (length == 0) { return 0; } if (substringLength == 0) { return 0; } while(offset < length) { int index = text.IndexOf(substring, offset); if (index == -1) { break; } count++; offset = index + substringLength; } return count; } #endregion #region Private Static Fields private const string CDATA_END = "]]>"; private const string CDATA_UNESCAPABLE_TOKEN = "]]"; /// /// Characters illegal in XML 1.0 /// private static Regex INVALIDCHARS=new Regex(@"[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD]",RegexOptions.Compiled); #endregion Private Static Fields } }