1 #region Copyright & License
2 //
3 // Copyright 2006 The Apache Software Foundation
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 #endregion
18 
19 using System;
20 using System.Text;
21 using System.Xml;
22 using System.Text.RegularExpressions;
23 
24 namespace log4net.Util
25 {
26 	/// <summary>
27 	/// Utility class that represents a format string.
28 	/// </summary>
29 	/// <remarks>
30 	/// <para>
31 	/// Utility class that represents a format string.
32 	/// </para>
33 	/// </remarks>
34 	/// <author>Nicko Cadell</author>
35 	public sealed class SystemStringFormat
36 	{
37 		private readonly IFormatProvider m_provider;
38 		private readonly string m_format;
39 		private readonly object[] m_args;
40 
41 		#region Constructor
42 
43 		/// <summary>
44 		/// Initialise the <see cref="SystemStringFormat"/>
45 		/// </summary>
46 		/// <param name="provider">An <see cref="System.IFormatProvider"/> that supplies culture-specific formatting information.</param>
47 		/// <param name="format">A <see cref="System.String"/> containing zero or more format items.</param>
48 		/// <param name="args">An <see cref="System.Object"/> array containing zero or more objects to format.</param>
SystemStringFormat(IFormatProvider provider, string format, params object[] args)49 		public SystemStringFormat(IFormatProvider provider, string format, params object[] args)
50 		{
51 			m_provider = provider;
52 			m_format = format;
53 			m_args = args;
54 		}
55 
56 		#endregion Constructor
57 
58 		/// <summary>
59 		/// Format the string and arguments
60 		/// </summary>
61 		/// <returns>the formatted string</returns>
ToString()62 		public override string ToString()
63 		{
64 			return StringFormat(m_provider, m_format, m_args);
65 		}
66 
67 		#region StringFormat
68 
69 		/// <summary>
70 		/// Replaces the format item in a specified <see cref="System.String"/> with the text equivalent
71 		/// of the value of a corresponding <see cref="System.Object"/> instance in a specified array.
72 		/// A specified parameter supplies culture-specific formatting information.
73 		/// </summary>
74 		/// <param name="provider">An <see cref="System.IFormatProvider"/> that supplies culture-specific formatting information.</param>
75 		/// <param name="format">A <see cref="System.String"/> containing zero or more format items.</param>
76 		/// <param name="args">An <see cref="System.Object"/> array containing zero or more objects to format.</param>
77 		/// <returns>
78 		/// A copy of format in which the format items have been replaced by the <see cref="System.String"/>
79 		/// equivalent of the corresponding instances of <see cref="System.Object"/> in args.
80 		/// </returns>
81 		/// <remarks>
82 		/// <para>
83 		/// This method does not throw exceptions. If an exception thrown while formatting the result the
84 		/// exception and arguments are returned in the result string.
85 		/// </para>
86 		/// </remarks>
StringFormat(IFormatProvider provider, string format, params object[] args)87 		private static string StringFormat(IFormatProvider provider, string format, params object[] args)
88 		{
89 			try
90 			{
91 				// The format is missing, log null value
92 				if (format == null)
93 				{
94 					return null;
95 				}
96 
97 				// The args are missing - should not happen unless we are called explicitly with a null array
98 				if (args == null)
99 				{
100 					return format;
101 				}
102 
103 				// Try to format the string
104 				return String.Format(provider, format, args);
105 			}
106 			catch(Exception ex)
107 			{
108 				log4net.Util.LogLog.Warn("StringFormat: Exception while rendering format ["+format+"]", ex);
109 				return StringFormatError(ex, format, args);
110 			}
111 			catch
112 			{
113 				log4net.Util.LogLog.Warn("StringFormat: Exception while rendering format ["+format+"]");
114 				return StringFormatError(null, format, args);
115 			}
116 		}
117 
118 		/// <summary>
119 		/// Process an error during StringFormat
120 		/// </summary>
StringFormatError(Exception formatException, string format, object[] args)121 		private static string StringFormatError(Exception formatException, string format, object[] args)
122 		{
123 			try
124 			{
125 				StringBuilder buf = new StringBuilder("<log4net.Error>");
126 
127 				if (formatException != null)
128 				{
129 					buf.Append("Exception during StringFormat: ").Append(formatException.Message);
130 				}
131 				else
132 				{
133 					buf.Append("Exception during StringFormat");
134 				}
135 				buf.Append(" <format>").Append(format).Append("</format>");
136 				buf.Append("<args>");
137 				RenderArray(args, buf);
138 				buf.Append("</args>");
139 				buf.Append("</log4net.Error>");
140 
141 				return buf.ToString();
142 			}
143 			catch(Exception ex)
144 			{
145 				log4net.Util.LogLog.Error("StringFormat: INTERNAL ERROR during StringFormat error handling", ex);
146 				return "<log4net.Error>Exception during StringFormat. See Internal Log.</log4net.Error>";
147 			}
148 			catch
149 			{
150 				log4net.Util.LogLog.Error("StringFormat: INTERNAL ERROR during StringFormat error handling");
151 				return "<log4net.Error>Exception during StringFormat. See Internal Log.</log4net.Error>";
152 			}
153 		}
154 
155 		/// <summary>
156 		/// Dump the contents of an array into a string builder
157 		/// </summary>
RenderArray(Array array, StringBuilder buffer)158 		private static void RenderArray(Array array, StringBuilder buffer)
159 		{
160 			if (array == null)
161 			{
162 				buffer.Append(SystemInfo.NullText);
163 			}
164 			else
165 			{
166 				if (array.Rank != 1)
167 				{
168 					buffer.Append(array.ToString());
169 				}
170 				else
171 				{
172 					buffer.Append("{");
173 					int len = array.Length;
174 
175 					if (len > 0)
176 					{
177 						RenderObject(array.GetValue(0), buffer);
178 						for (int i = 1; i < len; i++)
179 						{
180 							buffer.Append(", ");
181 							RenderObject(array.GetValue(i), buffer);
182 						}
183 					}
184 					buffer.Append("}");
185 				}
186 			}
187 		}
188 
189 		/// <summary>
190 		/// Dump an object to a string
191 		/// </summary>
RenderObject(Object obj, StringBuilder buffer)192 		private static void RenderObject(Object obj, StringBuilder buffer)
193 		{
194 			if (obj == null)
195 			{
196 				buffer.Append(SystemInfo.NullText);
197 			}
198 			else
199 			{
200 				try
201 				{
202 					buffer.Append(obj);
203 				}
204 				catch(Exception ex)
205 				{
206 					buffer.Append("<Exception: ").Append(ex.Message).Append(">");
207 				}
208 				catch
209 				{
210 					buffer.Append("<Exception>");
211 				}
212 			}
213 		}
214 
215 		#endregion StringFormat
216 	}
217 }
218