1 //------------------------------------------------------------------------------
2 // <copyright file="XmlException.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
11 using System.Resources;
13 using System.Diagnostics;
14 using System.Security.Permissions;
15 using System.Globalization;
16 using System.Threading;
18 using System.Runtime.Serialization;
22 /// <para>Returns detailed information about the last parse error, including the error
23 /// number, line number, character position, and a text description.</para>
28 public class XmlException : SystemException {
30 string[] args; // this field is not used, it's here just V1.1 serialization compatibility
39 // message != null for V1 exceptions deserialized in Whidbey
40 // message == null for V2 or higher exceptions; the exception message is stored on the base class (Exception._message)
44 protected XmlException(SerializationInfo info, StreamingContext context) : base(info, context) {
45 res = (string) info.GetValue("res" , typeof(string));
46 args = (string[])info.GetValue("args", typeof(string[]));
47 lineNumber = (int) info.GetValue("lineNumber", typeof(int));
48 linePosition = (int) info.GetValue("linePosition", typeof(int));
50 // deserialize optional members
51 sourceUri = string.Empty;
52 string version = null;
53 foreach ( SerializationEntry e in info ) {
56 sourceUri = (string)e.Value;
59 version = (string)e.Value;
64 if ( version == null ) {
65 // deserializing V1 exception
66 message = CreateMessage( res, args, lineNumber, linePosition );
69 // deserializing V2 or higher exception -> exception message is serialized by the base class (Exception._message)
74 [SecurityPermissionAttribute(SecurityAction.LinkDemand,SerializationFormatter=true)]
75 public override void GetObjectData(SerializationInfo info, StreamingContext context) {
76 base.GetObjectData(info, context);
77 info.AddValue("res", res);
78 info.AddValue("args", args);
79 info.AddValue("lineNumber", lineNumber);
80 info.AddValue("linePosition", linePosition);
81 info.AddValue("sourceUri", sourceUri);
82 info.AddValue("version", "2.0");
86 //provided to meet the ECMA standards
87 public XmlException() : this(null) {
90 //provided to meet the ECMA standards
91 public XmlException(String message) : this (message, ((Exception)null), 0, 0) {
93 Debug.Assert(message == null || !message.StartsWith("Xml_", StringComparison.Ordinal), "Do not pass a resource here!");
97 //provided to meet ECMA standards
98 public XmlException(String message, Exception innerException) : this (message, innerException, 0, 0) {
101 //provided to meet ECMA standards
102 public XmlException(String message, Exception innerException, int lineNumber, int linePosition) :
103 this( message, innerException, lineNumber, linePosition, null ) {
106 internal XmlException(String message, Exception innerException, int lineNumber, int linePosition, string sourceUri) :
107 base(FormatUserMessage(message, lineNumber, linePosition), innerException) {
109 HResult = HResults.Xml;
110 this.res = (message == null ? Res.Xml_DefaultException : Res.Xml_UserException);
111 this.args = new string[] { message };
112 this.sourceUri = sourceUri;
113 this.lineNumber = lineNumber;
114 this.linePosition = linePosition;
117 internal XmlException(string res, string[] args) :
118 this(res, args, null, 0, 0, null) {}
120 internal XmlException(string res, string[] args, string sourceUri) :
121 this(res, args, null, 0, 0, sourceUri) {}
123 internal XmlException(string res, string arg) :
124 this(res, new string[] { arg }, null, 0, 0, null) {}
126 internal XmlException(string res, string arg, string sourceUri) :
127 this(res, new string[] { arg }, null, 0, 0, sourceUri) {}
129 internal XmlException(string res, String arg, IXmlLineInfo lineInfo) :
130 this(res, new string[] { arg }, lineInfo, null) {}
132 internal XmlException(string res, String arg, Exception innerException, IXmlLineInfo lineInfo) :
133 this(res, new string[] { arg }, innerException, (lineInfo == null ? 0 : lineInfo.LineNumber), (lineInfo == null ? 0 : lineInfo.LinePosition), null) {}
135 internal XmlException(string res, String arg, IXmlLineInfo lineInfo, string sourceUri) :
136 this(res, new string[] { arg }, lineInfo, sourceUri) {}
138 internal XmlException(string res, string[] args, IXmlLineInfo lineInfo) :
139 this(res, args, lineInfo, null) {}
141 internal XmlException(string res, string[] args, IXmlLineInfo lineInfo, string sourceUri) :
142 this (res, args, null, (lineInfo == null ? 0 : lineInfo.LineNumber), (lineInfo == null ? 0 : lineInfo.LinePosition), sourceUri) {
145 internal XmlException(string res, int lineNumber, int linePosition) :
146 this(res, (string[])null, null, lineNumber, linePosition) {}
148 internal XmlException(string res, string arg, int lineNumber, int linePosition) :
149 this(res, new string[] { arg }, null, lineNumber, linePosition, null) {}
151 internal XmlException(string res, string arg, int lineNumber, int linePosition, string sourceUri) :
152 this(res, new string[] { arg }, null, lineNumber, linePosition, sourceUri) {}
154 internal XmlException(string res, string[] args, int lineNumber, int linePosition) :
155 this( res, args, null, lineNumber, linePosition, null ) {}
157 internal XmlException(string res, string[] args, int lineNumber, int linePosition, string sourceUri) :
158 this( res, args, null, lineNumber, linePosition, sourceUri ) {}
160 internal XmlException(string res, string[] args, Exception innerException, int lineNumber, int linePosition) :
161 this( res, args, innerException, lineNumber, linePosition, null ) {}
163 internal XmlException(string res, string[] args, Exception innerException, int lineNumber, int linePosition, string sourceUri) :
164 base( CreateMessage(res, args, lineNumber, linePosition), innerException ) {
165 HResult = HResults.Xml;
168 this.sourceUri = sourceUri;
169 this.lineNumber = lineNumber;
170 this.linePosition = linePosition;
173 private static string FormatUserMessage(string message, int lineNumber, int linePosition) {
174 if (message == null) {
175 return CreateMessage(Res.Xml_DefaultException, null, lineNumber, linePosition);
178 if (lineNumber == 0 && linePosition == 0) {
179 // do not reformat the message when not needed
183 // add line information
184 return CreateMessage(Res.Xml_UserException, new string[] { message }, lineNumber, linePosition);
189 private static string CreateMessage(string res, string[] args, int lineNumber, int linePosition) {
193 // No line information -> get resource string and return
194 if (lineNumber == 0) {
195 message = Res.GetString(res, args);
197 // Line information is available -> we need to append it to the error message
199 string lineNumberStr = lineNumber.ToString(CultureInfo.InvariantCulture);
200 string linePositionStr = linePosition.ToString(CultureInfo.InvariantCulture);
203 // get the error message from resources
205 message = Res.GetString(res, out fallbackUsed, args);
207 // If debug resources are available, append the line information
209 message = Res.GetString(Res.Xml_MessageWithErrorPosition, new string[] { message, lineNumberStr, linePositionStr } );
211 // Debug resources are not available -> add line information to the args and call the GetString to get the default
212 // fallback message with the updated arguments. We need to handle the the case when the debug resources are not
213 // available like this; otherwise we would end up with two fallback messages in the final string.
215 int origArgCount = args.Length;
216 Array.Resize<string>(ref args, origArgCount + 2);
218 args[origArgCount] = lineNumberStr;
219 args[origArgCount + 1] = linePositionStr;
221 message = Res.GetString(res, args);
224 message = Res.GetString(res, args);
225 message = Res.GetString(Res.Xml_MessageWithErrorPosition, new string[] { message, lineNumberStr, linePositionStr });
230 catch ( MissingManifestResourceException ) {
231 return "UNKNOWN("+res+")";
235 internal static string[] BuildCharExceptionArgs(string data, int invCharIndex) {
236 return BuildCharExceptionArgs(data[invCharIndex], invCharIndex + 1 < data.Length ? data[invCharIndex + 1] : '\0');
239 internal static string[] BuildCharExceptionArgs(char[] data, int invCharIndex) {
240 return BuildCharExceptionArgs(data, data.Length, invCharIndex);
243 internal static string[] BuildCharExceptionArgs(char[] data, int length, int invCharIndex) {
244 Debug.Assert(invCharIndex < data.Length);
245 Debug.Assert(invCharIndex < length);
246 Debug.Assert(length <= data.Length);
248 return BuildCharExceptionArgs(data[invCharIndex], invCharIndex + 1 < length ? data[invCharIndex + 1] : '\0');
251 internal static string[] BuildCharExceptionArgs(char invChar, char nextChar) {
252 string[] aStringList = new string[2];
254 // for surrogate characters include both high and low char in the message so that a full character is displayed
255 if (XmlCharType.IsHighSurrogate(invChar) && nextChar != 0) {
256 int combinedChar = XmlCharType.CombineSurrogateChar(nextChar, invChar);
257 aStringList[0] = new string(new char[] { invChar, nextChar } );
258 aStringList[1] = string.Format(CultureInfo.InvariantCulture, "0x{0:X2}", combinedChar);
261 // don't include 0 character in the string - in means eof-of-string in native code, where this may bubble up to
262 if ((int)invChar == 0) {
263 aStringList[0] = ".";
266 aStringList[0] = invChar.ToString(CultureInfo.InvariantCulture);
268 aStringList[1] = string.Format(CultureInfo.InvariantCulture, "0x{0:X2}", (int)invChar);
273 public int LineNumber {
274 get { return this.lineNumber; }
277 public int LinePosition {
278 get { return this.linePosition; }
281 public string SourceUri {
282 get { return this.sourceUri; }
285 public override string Message {
287 return ( message == null ) ? base.Message : message;
291 internal string ResString {
298 internal static bool IsCatchableException(Exception e) {
299 Debug.Assert(e != null, "Unexpected null exception");
301 e is StackOverflowException ||
302 e is OutOfMemoryException ||
303 e is ThreadAbortException ||
304 e is ThreadInterruptedException ||
305 e is NullReferenceException ||
306 e is AccessViolationException
311 } // namespace System.Xml