天天看點

dotnet(C#/mono)輕量級XML解析庫Mono.Xml源碼

unity3d減少播放器包含的 dll 檔案

       unity3d在建構播放器時(桌上型電腦、Android 或 iOS)有一點非常重要,也就是不要依賴 System.dll 或 System.Xml.dll。Unity 的播放器安裝中不包含 System.dll 或 System.Xml.dll。這意味着,如果想要使用 Xml 或 System.dll 中的通用容器,那麼必要的 dll 檔案将包含在播放器中。這通常使得下載下傳檔案大小增加 1mb,這顯然無益于播放器的分發,因而應該避免使用。如需解析一些 Xml 檔案,可以使用更小的 xml 庫,如 Mono.Xml.zip。大多數通用容器都包含在 mscorlib 中,Stack<> 和其他一小部分位于 System.dll。是以,應該盡量避免。

以下為源碼

MiniParse.cs

//
// System.Security.Cryptography.MiniParser: Internal XML parser implementation
//
// Authors:
//	Sergey Chaban
//
// Copyright (c) 2001, 2002 Wild West Software
// Copyright (c) 2002 Sergey Chaban
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.Text;
using System.Collections;
using System.Globalization;

namespace Mono.Xml {

	internal class MiniParser {

		public interface IReader {
			int Read();
		}

		public interface IAttrList {
			int Length {get;}
			bool IsEmpty {get;}
			string GetName(int i);
			string GetValue(int i);
			string GetValue(string name);
			void ChangeValue(string name, string newValue);
			string[] Names {get;}
			string[] Values {get;}
		}

		public interface IMutableAttrList : IAttrList {
			void Clear();
			void Add(string name, string value);
			void CopyFrom(IAttrList attrs);
			void Remove(int i);
			void Remove(string name);
		}

		public interface IHandler {
			void OnStartParsing(MiniParser parser);
			void OnStartElement(string name, IAttrList attrs);
			void OnEndElement(string name);
			void OnChars(string ch);
			void OnEndParsing(MiniParser parser);
		}

		public class HandlerAdapter : IHandler {
			public HandlerAdapter() {}
			public void OnStartParsing(MiniParser parser) {}
			public void OnStartElement(string name, IAttrList attrs) {}
			public void OnEndElement(string name) {}
			public void OnChars(string ch) {}
			public void OnEndParsing(MiniParser parser) {}
		}

		private enum CharKind : byte {
			LEFT_BR     = 0,
			RIGHT_BR    = 1,
			SLASH       = 2,
			PI_MARK     = 3,
			EQ          = 4,
			AMP         = 5,
			SQUOTE      = 6,
			DQUOTE      = 7,
			BANG        = 8,
			LEFT_SQBR   = 9,
			SPACE       = 0xA,
			RIGHT_SQBR  = 0xB,
			TAB         = 0xC,
			CR          = 0xD,
			EOL         = 0xE,
			CHARS       = 0xF,
			UNKNOWN = 0x1F
		}

		private enum ActionCode : byte {
			START_ELEM               = 0,
			END_ELEM                 = 1,
			END_NAME                 = 2,
			SET_ATTR_NAME            = 3,
			SET_ATTR_VAL             = 4,
			SEND_CHARS               = 5,
			START_CDATA              = 6,
			END_CDATA                = 7,
			ERROR                    = 8,
			STATE_CHANGE             = 9,
			FLUSH_CHARS_STATE_CHANGE = 0xA,
			ACC_CHARS_STATE_CHANGE   = 0xB,
			ACC_CDATA                = 0xC,
			PROC_CHAR_REF            = 0xD,
			UNKNOWN = 0xF
		}

		public class AttrListImpl : IMutableAttrList {
			protected ArrayList names;
			protected ArrayList values;

			public AttrListImpl() : this(0) {}

			public AttrListImpl(int initialCapacity) {
				if (initialCapacity <= 0) {
					names = new ArrayList();
					values = new ArrayList();
				} else {
					names = new ArrayList(initialCapacity);
					values = new ArrayList(initialCapacity);
				}
			}

			public AttrListImpl(IAttrList attrs)
			: this(attrs != null ? attrs.Length : 0) {
				if (attrs != null) this.CopyFrom(attrs);
			}

			public int Length {
				get {return names.Count;}
			}

			public bool IsEmpty {
				get {return this.Length != 0;}
			}

			public string GetName(int i) {
				string res = null;
				if (i >= 0 && i < this.Length) {
					res = names[i] as string;
				}
				return res;
			}

			public string GetValue(int i) {
				string res = null;
				if (i >= 0 && i < this.Length) {
					res = values[i] as string;
				}
				return res;
			}

			public string GetValue(string name) {
				return this.GetValue(names.IndexOf(name));
			}

			public void ChangeValue(string name, string newValue) {
				int i = names.IndexOf(name);
				if (i >= 0 && i < this.Length) {
					values[i] = newValue;
				}
			}

			public string[] Names {
				get {return names.ToArray(typeof(string)) as string[];}
			}

			public string[] Values {
				get {return values.ToArray(typeof(string)) as string[];}
			}

			public void Clear() {
				names.Clear();
				values.Clear();
			}

			public void Add(string name, string value) {
				names.Add(name);
				values.Add(value);
			}

			public void Remove(int i) {
				if (i >= 0) {
					names.RemoveAt(i);
					values.RemoveAt(i);
				}
			}

			public void Remove(string name) {
				this.Remove(names.IndexOf(name));
			}

			public void CopyFrom(IAttrList attrs) {
				if (attrs != null && ((object)this == (object)attrs)) {
					this.Clear();
					int n = attrs.Length;
					for (int i = 0; i < n; i++) {
						this.Add(attrs.GetName(i), attrs.GetValue(i));
					}
				}
			}
		}

		public class XMLError : Exception {
			protected string descr;
			protected int line, column;
			public XMLError() : this("Unknown") {}
			public XMLError(string descr) : this(descr, -1, -1) {}
			public XMLError(string descr, int line, int column)
			: base(descr) {
				this.descr = descr;
				this.line = line;
				this.column = column;
			}
			public int Line {get {return line;}}
			public int Column {get {return column;}}
			public override string ToString() {
				return (String.Format("{0} @ (line = {1}, col = {2})", descr, line, column));
			}
		}

		private static readonly int INPUT_RANGE = 13;
		private static readonly ushort[] tbl = {
			(ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 1), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 128), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 128),
			(ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 2), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 133), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 16), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.FLUSH_CHARS_STATE_CHANGE << 8) | 4),
			(ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.END_ELEM << 8) | 0), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 2), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 2), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129),
			(ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 5), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3),
			(ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 4), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.END_NAME << 8) | 6), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.END_NAME << 8) | 7), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.END_NAME << 8) | 8), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129),
			(ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3),
			(ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 129),
			(ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.FLUSH_CHARS_STATE_CHANGE << 8) | 1), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 10), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 7), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10),
			(ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_ELEM << 8) | 6), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.START_ELEM << 8) | 7), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 8), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129),
			(ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.SET_ATTR_NAME << 8) | 11), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 12), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130),
			(ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 13), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 10), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10),
			(ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 11), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 132), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 132),
			(ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.SET_ATTR_NAME << 8) | 11), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 12), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 130),
			(ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.SEND_CHARS << 8) | 2), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 16), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 134), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 134),
			(ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.SET_ATTR_VAL << 8) | 17), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 14), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14),
			(ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.SET_ATTR_VAL << 8) | 17), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 15), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15),
			(ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 18), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19),
			(ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_ELEM << 8) | 6), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.START_ELEM << 8) | 7), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 17), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129),
			(ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.END_CDATA << 8) | 10), (ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18),
			(ushort)(((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19), (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19),
			(ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.UNKNOWN << 8) | 255),
			0xFFFF
		};

		protected static string[] errors = {
			/* 0 */ "Expected element",
			/* 1 */ "Invalid character in tag",
			/* 2 */ "No '='",
			/* 3 */ "Invalid character entity",
			/* 4 */ "Invalid attr value",
			/* 5 */ "Empty tag",
			/* 6 */ "No end tag",
			/* 7 */ "Bad entity ref"
		};

		protected int line;
		protected int col;
		protected int[] twoCharBuff;
		protected bool splitCData;

		public MiniParser() {
			twoCharBuff = new int[2];
			splitCData = false;
			Reset();
		}

		public void Reset() {
			line = 0;
			col = 0;
		}

		protected static bool StrEquals(string str, StringBuilder sb, int sbStart, int len) {
			if (len != str.Length) return false;
			for (int i = 0; i < len; i++) {
				if (str[i] != sb[sbStart + i]) return false;
			}
			return true;
		}

		protected void FatalErr(string descr) {
			throw new XMLError(descr, this.line, this.col);
		}

		protected static int Xlat(int charCode, int state) {
			int p = state * INPUT_RANGE;
			int n = System.Math.Min(tbl.Length - p, INPUT_RANGE);
			for (;--n >= 0;) {
				ushort code = tbl[p];
				if (charCode == (code >> 12)) return (code & 0xFFF);
				p++;
			}
			return 0xFFF;
		}

		public void Parse(IReader reader, IHandler handler) {
			if (reader == null) throw new ArgumentNullException("reader");
			if (handler == null) handler = new HandlerAdapter();

			AttrListImpl attrList = new AttrListImpl();
			string lastAttrName = null;
			Stack tagStack = new Stack();
			string elementName = null;
			line = 1;
			col = 0;
			int currCh = 0;
			int stateCode = 0;
			StringBuilder sbChars = new StringBuilder();
			bool seenCData = false;
			bool isComment = false;
			bool isDTD = false;
			int bracketSwitch = 0;

			handler.OnStartParsing(this);

			while (true) {
				++this.col;

				currCh = reader.Read();

				if (currCh == -1) {
					if (stateCode != 0) {
						FatalErr("Unexpected EOF");
					}
					break;
				}

				int charCode = "<>/?=&'\"![ ]\t\r\n".IndexOf((char)currCh) & 0xF;
				if (charCode == (int)CharKind.CR) continue; // ignore
				// whitepace ::= (#x20 | #x9 | #xd | #xa)+
				if (charCode == (int)CharKind.TAB) charCode = (int)CharKind.SPACE; // tab == space
				if (charCode == (int)CharKind.EOL) {
					this.col = 0;
					this.line++;
					charCode = (int)CharKind.SPACE;
				}

				int actionCode = MiniParser.Xlat(charCode, stateCode);
				stateCode = actionCode & 0xFF;
				// Ignore newline inside attribute value.
				if (currCh == '\n' && (stateCode == 0xE || stateCode == 0xF)) continue;
				actionCode >>= 8;

				if (stateCode >= 0x80) {
					if (stateCode == 0xFF) {
						FatalErr("State dispatch error.");
					} else {
						FatalErr(errors[stateCode ^ 0x80]);
					}
				}

				switch (actionCode) {
				case (int)ActionCode.START_ELEM:
					handler.OnStartElement(elementName, attrList);
					if (currCh != '/') {
						tagStack.Push(elementName);
					} else {
						handler.OnEndElement(elementName);
					}
					attrList.Clear();
					break;

				case (int)ActionCode.END_ELEM:
					elementName = sbChars.ToString();
					sbChars = new StringBuilder();
					string endName = null;
					if (tagStack.Count == 0 ||
						elementName != (endName = tagStack.Pop() as string)) {
						if (endName == null) {
							FatalErr("Tag stack underflow");
						} else {
							FatalErr(String.Format("Expected end tag '{0}' but found '{1}'", elementName, endName));
						}
					}
					handler.OnEndElement(elementName);
					break;

				case (int)ActionCode.END_NAME:
					elementName = sbChars.ToString();
					sbChars = new StringBuilder();
					if (currCh != '/' && currCh != '>') break;
					goto case (int)ActionCode.START_ELEM;

				case (int)ActionCode.SET_ATTR_NAME:
					lastAttrName = sbChars.ToString();
					sbChars = new StringBuilder();
					break;

				case (int)ActionCode.SET_ATTR_VAL:
					if (lastAttrName == null) FatalErr("Internal error.");
					attrList.Add(lastAttrName, sbChars.ToString());
					sbChars = new StringBuilder();
					lastAttrName = null;
					break;

				case (int)ActionCode.SEND_CHARS:
					handler.OnChars(sbChars.ToString());
					sbChars = new StringBuilder();
					break;

				case (int)ActionCode.START_CDATA:
					string cdata = "CDATA[";
					isComment = false;
					isDTD = false;

					if (currCh == '-') {
						currCh = reader.Read();

						if (currCh != '-') FatalErr("Invalid comment");

						this.col++;
						isComment = true;
						twoCharBuff[0] = -1;
						twoCharBuff[1] = -1;
					} else {
						if (currCh != '[') {
							isDTD = true;
							bracketSwitch = 0;
							break;
						}

						for (int i = 0; i < cdata.Length; i++) {
							if (reader.Read() != cdata[i]) {
								this.col += i+1;
								break;
							}
						}
						this.col += cdata.Length;
						seenCData = true;
					}
					break;

				case (int)ActionCode.END_CDATA:
					int n = 0;
					currCh = ']';

					while (currCh == ']') {
						currCh = reader.Read();
						n++;
					}

					if (currCh != '>') {
						for (int i = 0; i < n; i++) sbChars.Append(']');
						sbChars.Append((char)currCh);
						stateCode = 0x12;
					} else {
						for (int i = 0; i < n-2; i++) sbChars.Append(']');
						seenCData = false;
					}

					this.col += n;
					break;

				case (int)ActionCode.ERROR:
					FatalErr(String.Format("Error {0}", stateCode));
					break;

				case (int)ActionCode.STATE_CHANGE:
					break;

				case (int)ActionCode.FLUSH_CHARS_STATE_CHANGE:
					sbChars = new StringBuilder();
					if (currCh != '<') goto case (int)ActionCode.ACC_CHARS_STATE_CHANGE;
					break;

				case (int)ActionCode.ACC_CHARS_STATE_CHANGE:
					sbChars.Append((char)currCh);
					break;

				case (int)ActionCode.ACC_CDATA:
					if (isComment) {
						if (currCh == '>'
							&& twoCharBuff[0] == '-'
							&& twoCharBuff[1] == '-') {
							isComment = false;
							stateCode = 0;
						} else {
							twoCharBuff[0] = twoCharBuff[1];
							twoCharBuff[1] = currCh;
						}
					} else if (isDTD) {
						if (currCh == '<' || currCh == '>') bracketSwitch ^= 1;
						if (currCh == '>' && bracketSwitch != 0) {
							isDTD = false;
							stateCode = 0;
						}
					} else {
						if (this.splitCData
							&& sbChars.Length > 0
							&& seenCData) {
							handler.OnChars(sbChars.ToString());
							sbChars = new StringBuilder();
						}
						seenCData = false;
						sbChars.Append((char)currCh);
					}
					break;

				case (int)ActionCode.PROC_CHAR_REF:
					currCh = reader.Read();
					int cl = this.col + 1;
					if (currCh == '#') {    // character reference
						int r = 10;
						int chCode = 0;
						int nDigits = 0;
						currCh = reader.Read();
						cl++;

						if (currCh == 'x') {
							currCh = reader.Read();
							cl++;
							r=16;
						}

						NumberStyles style = r == 16 ? NumberStyles.HexNumber : NumberStyles.Integer;

						while (true) {
							int x = -1;
							if (Char.IsNumber((char)currCh) || "abcdef".IndexOf(Char.ToLower((char)currCh)) != -1) {
								try {
									x = Int32.Parse(new string((char)currCh, 1), style);
								} catch (FormatException) {x = -1;}
							}
							if (x == -1) break;
							chCode *= r;
							chCode += x;
							nDigits++;
							currCh = reader.Read();
							cl++;
						}

						if (currCh == ';' && nDigits > 0) {
							sbChars.Append((char)chCode);
						} else {
							FatalErr("Bad char ref");
						}
					} else {
						// entity reference
						string entityRefChars = "aglmopqstu"; // amp | apos | quot | gt | lt
						string entities = "&'\"><";

						int pos = 0;
						int entIdx = 0xF;
						int predShift = 0;

						int sbLen = sbChars.Length;

						while (true) {
							if (pos != 0xF) pos = entityRefChars.IndexOf((char)currCh) & 0xF;
							if (pos == 0xF) FatalErr(errors[7]);
							sbChars.Append((char)currCh);

							int path = "\uFF35\u3F8F\u4F8F\u0F5F\uFF78\uE1F4\u2299\uEEFF\uEEFF\uFF4F"[pos];
							int lBr = (path >> 4) & 0xF;
							int rBr = path & 0xF;
							int lPred = path >> 12;
							int rPred = (path >> 8) & 0xF;
							currCh = reader.Read();
							cl++;
							pos = 0xF;
							if (lBr != 0xF && currCh == entityRefChars[lBr]) {
								if (lPred < 0xE) entIdx = lPred;
//								pred = lPred;
								predShift = 12; // left
							} else if (rBr != 0xF && currCh == entityRefChars[rBr]) {
								if (rPred < 0xE) entIdx = rPred;
//								pred = rPred;
								predShift = 8; // right
							} else if (currCh == ';') {
								if (entIdx != 0xF
									&& predShift != 0
									&& ((path >> predShift) & 0xF) == 0xE) break;
								continue; // pos == 0xF
							}

							pos=0;

						}

						int l = cl - this.col - 1;

						if ((l > 0 && l < 5)
							&&(StrEquals("amp", sbChars, sbLen, l)
							|| StrEquals("apos", sbChars, sbLen, l)
							|| StrEquals("quot", sbChars, sbLen, l)
							|| StrEquals("lt", sbChars, sbLen, l)
							|| StrEquals("gt", sbChars, sbLen, l))
							) {
							sbChars.Length = sbLen;
							sbChars.Append(entities[entIdx]);
						} else FatalErr(errors[7]);
					}

					this.col = cl;
					break;

				default:
					FatalErr(String.Format("Unexpected action code - {0}.", actionCode));
					break;
				}
			} // while (true)

			handler.OnEndParsing(this);

		} // Parse

	}

}
           

SecurityParser .cs

//
// Mono.Xml.SecurityParser.cs class implementation
//
// Author:
//	Sebastien Pouliot ([email protected])
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
//

//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.Collections;
using System.IO;
using System.Security;

namespace Mono.Xml {

	// convert an XML document into SecurityElement objects
	internal class SecurityParser : SmallXmlParser, SmallXmlParser.IContentHandler {

		private SecurityElement root;

		public SecurityParser () : base ()
		{
			stack = new Stack ();
		}

		public void LoadXml (string xml)
		{
			root = null;
#if CF_1_0
			stack = new Stack ();
#else
			stack.Clear ();
#endif
			Parse (new StringReader (xml), this);
		}

		public SecurityElement ToXml ()
		{
			return root;
		}

		// IContentHandler

		private SecurityElement current;
		private Stack stack;

		public void OnStartParsing (SmallXmlParser parser) {}

		public void OnProcessingInstruction (string name, string text) {}

		public void OnIgnorableWhitespace (string s) {}

		public void OnStartElement (string name, SmallXmlParser.IAttrList attrs)
		{
			SecurityElement newel = new SecurityElement (name);
			if (root == null) {
				root = newel;
				current = newel;
			}
			else {
				SecurityElement parent = (SecurityElement) stack.Peek ();
				parent.AddChild (newel);
			}
			stack.Push (newel);
			current = newel;
			// attributes
			int n = attrs.Length;
			for (int i=0; i < n; i++)
				current.AddAttribute (attrs.GetName (i), attrs.GetValue (i));
		}

		public void OnEndElement (string name)
		{
			current = (SecurityElement) stack.Pop ();
		}

		public void OnChars (string ch)
		{
			current.Text = ch;
		}

		public void OnEndParsing (SmallXmlParser parser) {}
	}
}

           

SmallXmlParser.cs

//
// SmallXmlParser.cs
//
// Author:
//	Atsushi Enomoto  <[email protected]>
//
// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

//
// small xml parser that is mostly compatible with
//

using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Text;

namespace Mono.Xml
{
	internal class DefaultHandler : SmallXmlParser.IContentHandler
	{
		public void OnStartParsing (SmallXmlParser parser)
		{
		}

		public void OnEndParsing (SmallXmlParser parser)
		{
		}

		public void OnStartElement (string name, SmallXmlParser.IAttrList attrs)
		{
		}

		public void OnEndElement (string name)
		{
		}

		public void OnChars (string s)
		{
		}

		public void OnIgnorableWhitespace (string s)
		{
		}

		public void OnProcessingInstruction (string name, string text)
		{
		}
	}

	internal class SmallXmlParser
	{
		public interface IContentHandler
		{
			void OnStartParsing (SmallXmlParser parser);
			void OnEndParsing (SmallXmlParser parser);
			void OnStartElement (string name, IAttrList attrs);
			void OnEndElement (string name);
			void OnProcessingInstruction (string name, string text);
			void OnChars (string text);
			void OnIgnorableWhitespace (string text);
		}

		public interface IAttrList
		{
			int Length { get; }
			bool IsEmpty { get; }
			string GetName (int i);
			string GetValue (int i);
			string GetValue (string name);
			string [] Names { get; }
			string [] Values { get; }
		}

		class AttrListImpl : IAttrList
		{
			public int Length {
				get { return attrNames.Count; }
			}
			public bool IsEmpty {
				get { return attrNames.Count == 0; }
			}
			public string GetName (int i)
			{
				return (string) attrNames [i];
			}
			public string GetValue (int i)
			{
				return (string) attrValues [i];
			}
			public string GetValue (string name)
			{
				for (int i = 0; i < attrNames.Count; i++)
					if ((string) attrNames [i] == name)
						return (string) attrValues [i];
				return null;
			}
			public string [] Names {
				get { return (string []) attrNames.ToArray (typeof (string)); }
			}
			public string [] Values {
				get { return (string []) attrValues.ToArray (typeof (string)); }
			}

			ArrayList attrNames = new ArrayList ();
			ArrayList attrValues = new ArrayList ();

			internal void Clear ()
			{
				attrNames.Clear ();
				attrValues.Clear ();
			}

			internal void Add (string name, string value)
			{
				attrNames.Add (name);
				attrValues.Add (value);
			}
		}

		IContentHandler handler;
		TextReader reader;
		Stack elementNames = new Stack ();
		Stack xmlSpaces = new Stack ();
		string xmlSpace;
		StringBuilder buffer = new StringBuilder (200);
		char [] nameBuffer = new char [30];
		bool isWhitespace;

		AttrListImpl attributes = new AttrListImpl ();
		int line = 1, column;
		bool resetColumn;

		public SmallXmlParser ()
		{
		}

		private Exception Error (string msg)
		{
			return new SmallXmlParserException (msg, line, column);
		}

		private Exception UnexpectedEndError ()
		{
			string [] arr = new string [elementNames.Count];
			// COMPACT FRAMEWORK NOTE: CopyTo is not visible through the Stack class
			(elementNames as ICollection).CopyTo (arr, 0);
			return Error (String.Format (
							  "Unexpected end of stream. Element stack content is {0}", String.Join (",", arr)));
		}


		private bool IsNameChar (char c, bool start)
		{
			switch (c) {
			case ':':
			case '_':
				return true;
			case '-':
			case '.':
				return !start;
			}
			if (c > 0x100) { // optional condition for optimization
				switch (c) {
				case '\u0559':
				case '\u06E5':
				case '\u06E6':
					return true;
				}
				if ('\u02BB' <= c && c <= '\u02C1')
					return true;
			}
			switch (Char.GetUnicodeCategory (c)) {
			case UnicodeCategory.LowercaseLetter:
			case UnicodeCategory.UppercaseLetter:
			case UnicodeCategory.OtherLetter:
			case UnicodeCategory.TitlecaseLetter:
			case UnicodeCategory.LetterNumber:
				return true;
			case UnicodeCategory.SpacingCombiningMark:
			case UnicodeCategory.EnclosingMark:
			case UnicodeCategory.NonSpacingMark:
			case UnicodeCategory.ModifierLetter:
			case UnicodeCategory.DecimalDigitNumber:
				return !start;
			default:
				return false;
			}
		}

		private bool IsWhitespace (int c)
		{
			switch (c) {
			case ' ':
			case '\r':
			case '\t':
			case '\n':
				return true;
			default:
				return false;
			}
		}


		public void SkipWhitespaces ()
		{
			SkipWhitespaces (false);
		}

		private void HandleWhitespaces ()
		{
			while (IsWhitespace (Peek ()))
				buffer.Append ((char) Read ());
			if (Peek () != '<' && Peek () >= 0)
				isWhitespace = false;
		}

		public void SkipWhitespaces (bool expected)
		{
			while (true) {
				switch (Peek ()) {
				case ' ':
				case '\r':
				case '\t':
				case '\n':
					Read ();
					if (expected)
						expected = false;
					continue;
				}
				if (expected)
					throw Error ("Whitespace is expected.");
				return;
			}
		}


		private int Peek ()
		{
			return reader.Peek ();
		}

		private int Read ()
		{
			int i = reader.Read ();
			if (i == '\n')
				resetColumn = true;
			if (resetColumn) {
				line++;
				resetColumn = false;
				column = 1;
			}
			else
				column++;
			return i;
		}

		public void Expect (int c)
		{
			int p = Read ();
			if (p < 0)
				throw UnexpectedEndError ();
			else if (p != c)
				throw Error (String.Format ("Expected '{0}' but got {1}", (char) c, (char) p));
		}

		private string ReadUntil (char until, bool handleReferences)
		{
			while (true) {
				if (Peek () < 0)
					throw UnexpectedEndError ();
				char c = (char) Read ();
				if (c == until)
					break;
				else if (handleReferences && c == '&')
					ReadReference ();
				else
					buffer.Append (c);
			}
			string ret = buffer.ToString ();
			buffer.Length = 0;
			return ret;
		}

		public string ReadName ()
		{
			int idx = 0;
			if (Peek () < 0 || !IsNameChar ((char) Peek (), true))
				throw Error ("XML name start character is expected.");
			for (int i = Peek (); i >= 0; i = Peek ()) {
				char c = (char) i;
				if (!IsNameChar (c, false))
					break;
				if (idx == nameBuffer.Length) {
					char [] tmp = new char [idx * 2];
					// COMPACT FRAMEWORK NOTE: Array.Copy(sourceArray, destinationArray, count) is not available.
					Array.Copy (nameBuffer, 0, tmp, 0, idx);
					nameBuffer = tmp;
				}
				nameBuffer [idx++] = c;
				Read ();
			}
			if (idx == 0)
				throw Error ("Valid XML name is expected.");
			return new string (nameBuffer, 0, idx);
		}


		public void Parse (TextReader input, IContentHandler handler)
		{
			this.reader = input;
			this.handler = handler;

			handler.OnStartParsing (this);

			while (Peek () >= 0)
				ReadContent ();
			HandleBufferedContent ();
			if (elementNames.Count > 0)
				throw Error (String.Format ("Insufficient close tag: {0}", elementNames.Peek ()));

			handler.OnEndParsing (this);

			Cleanup ();
		}

		private void Cleanup ()
		{
			line = 1;
			column = 0;
			handler = null;
			reader = null;
#if CF_1_0
			elementNames = new Stack ();
			xmlSpaces = new Stack ();
#else
			elementNames.Clear ();
			xmlSpaces.Clear ();
#endif
			attributes.Clear ();
			buffer.Length = 0;
			xmlSpace = null;
			isWhitespace = false;
		}

		public void ReadContent ()
		{
			string name;
			if (IsWhitespace (Peek ())) {
				if (buffer.Length == 0)
					isWhitespace = true;
				HandleWhitespaces ();
			}
			if (Peek () == '<') {
				Read ();
				switch (Peek ()) {
				case '!': // declarations
					Read ();
					if (Peek () == '[') {
						Read ();
						if (ReadName () != "CDATA")
							throw Error ("Invalid declaration markup");
						Expect ('[');
						ReadCDATASection ();
						return;
					}
					else if (Peek () == '-') {
						ReadComment ();
						return;
					}
					else if (ReadName () != "DOCTYPE")
						throw Error ("Invalid declaration markup.");
					else
						throw Error ("This parser does not support document type.");
				case '?': // PIs
					HandleBufferedContent ();
					Read ();
					name = ReadName ();
					SkipWhitespaces ();
					string text = String.Empty;
					if (Peek () != '?') {
						while (true) {
							text += ReadUntil ('?', false);
							if (Peek () == '>')
								break;
							text += "?";
						}
					}
					handler.OnProcessingInstruction (
						name, text);
					Expect ('>');
					return;
				case '/': // end tags
					HandleBufferedContent ();
					if (elementNames.Count == 0)
						throw UnexpectedEndError ();
					Read ();
					name = ReadName ();
					SkipWhitespaces ();
					string expected = (string) elementNames.Pop ();
					xmlSpaces.Pop ();
					if (xmlSpaces.Count > 0)
						xmlSpace = (string) xmlSpaces.Peek ();
					else
						xmlSpace = null;
					if (name != expected)
						throw Error (String.Format ("End tag mismatch: expected {0} but found {1}", expected, name));
					handler.OnEndElement (name);
					Expect ('>');
					return;
				default: // start tags (including empty tags)
					HandleBufferedContent ();
					name = ReadName ();
					while (Peek () != '>' && Peek () != '/')
						ReadAttribute (attributes);
					handler.OnStartElement (name, attributes);
					attributes.Clear ();
					SkipWhitespaces ();
					if (Peek () == '/') {
						Read ();
						handler.OnEndElement (name);
					}
					else {
						elementNames.Push (name);
						xmlSpaces.Push (xmlSpace);
					}
					Expect ('>');
					return;
				}
			}
			else
				ReadCharacters ();
		}

		private void HandleBufferedContent ()
		{
			if (buffer.Length == 0)
				return;
			if (isWhitespace)
				handler.OnIgnorableWhitespace (buffer.ToString ());
			else
				handler.OnChars (buffer.ToString ());
			buffer.Length = 0;
			isWhitespace = false;
		}

		private void ReadCharacters ()
		{
			isWhitespace = false;
			while (true) {
				int i = Peek ();
				switch (i) {
				case -1:
					return;
				case '<':
					return;
				case '&':
					Read ();
					ReadReference ();
					continue;
				default:
					buffer.Append ((char) Read ());
					continue;
				}
			}
		}

		private void ReadReference ()
		{
			if (Peek () == '#') {
				// character reference
				Read ();
				ReadCharacterReference ();
			} else {
				string name = ReadName ();
				Expect (';');
				switch (name) {
				case "amp":
					buffer.Append ('&');
					break;
				case "quot":
					buffer.Append ('"');
					break;
				case "apos":
					buffer.Append ('\'');
					break;
				case "lt":
					buffer.Append ('<');
					break;
				case "gt":
					buffer.Append ('>');
					break;
				default:
					throw Error ("General non-predefined entity reference is not supported in this parser.");
				}
			}
		}

		private int ReadCharacterReference ()
		{
			int n = 0;
			if (Peek () == 'x') { // hex
				Read ();
				for (int i = Peek (); i >= 0; i = Peek ()) {
					if ('0' <= i && i <= '9')
						n = n << 4 + i - '0';
					else if ('A' <= i && i <='F')
						n = n << 4 + i - 'A' + 10;
					else if ('a' <= i && i <='f')
						n = n << 4 + i - 'a' + 10;
					else
						break;
					Read ();
				}
			} else {
				for (int i = Peek (); i >= 0; i = Peek ()) {
					if ('0' <= i && i <= '9')
						n = n << 4 + i - '0';
					else
						break;
					Read ();
				}
			}
			return n;
		}

		private void ReadAttribute (AttrListImpl a)
		{
			SkipWhitespaces (true);
			if (Peek () == '/' || Peek () == '>')
			// came here just to spend trailing whitespaces
				return;

			string name = ReadName ();
			string value;
			SkipWhitespaces ();
			Expect ('=');
			SkipWhitespaces ();
			switch (Read ()) {
			case '\'':
				value = ReadUntil ('\'', true);
				break;
			case '"':
				value = ReadUntil ('"', true);
				break;
			default:
				throw Error ("Invalid attribute value markup.");
			}
			if (name == "xml:space")
				xmlSpace = value;
			a.Add (name, value);
		}

		private void ReadCDATASection ()
		{
			int nBracket = 0;
			while (true) {
				if (Peek () < 0)
					throw UnexpectedEndError ();
				char c = (char) Read ();
				if (c == ']')
					nBracket++;
				else if (c == '>' && nBracket > 1) {
					for (int i = nBracket; i > 2; i--)
						buffer.Append (']');
					break;
				}
				else {
					for (int i = 0; i < nBracket; i++)
						buffer.Append (']');
					nBracket = 0;
					buffer.Append (c);
				}
			}
		}

		private void ReadComment ()
		{
			Expect ('-');
			Expect ('-');
			while (true) {
				if (Read () != '-')
					continue;
				if (Read () != '-')
					continue;
				if (Read () != '>')
					throw Error ("'--' is not allowed inside comment markup.");
				break;
			}
		}
	}

	internal class SmallXmlParserException : SystemException
	{
		int line;
		int column;

		public SmallXmlParserException (string msg, int line, int column)
		: base (String.Format ("{0}. At ({1},{2})", msg, line, column))
		{
			this.line = line;
			this.column = column;
		}

		public int Line {
			get { return line; }
		}

		public int Column {
			get { return column; }
		}
	}
}