2002-11-16 Sebastien Pouliot <spouliot@videotron.ca>
[mono.git] / mcs / class / corlib / Mono.Xml / MiniParser.cs
1 //
2 // System.Security.Cryptography.MiniParser: Internal XML parser implementation
3 //
4 // Authors:
5 //      Sergey Chaban
6 //
7
8 /*
9  * Copyright (c) 2001, 2002 Wild West Software
10  * Copyright (c) 2002 Sergey Chaban
11  * 
12  * Permission is hereby granted, free of charge, to any person
13  * obtaining a copy of this software and associated documentation
14  * files (the "Software"), to deal in the Software without restriction,
15  * including without limitation the rights to use, copy, modify, merge,
16  * publish, distribute, sublicense, and/or sell copies of the Software,
17  * and to permit persons to whom the Software is furnished to do so,
18  * subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included
21  * in all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
25  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
26  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
27  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
28  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
29  * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30  */
31
32 using System;
33 using System.Text;
34 using System.Collections;
35 using System.Globalization;
36
37 namespace System.Security.Cryptography {
38
39 internal class MiniParser {
40
41         public interface IReader {
42                 int Read();
43         }
44
45         public interface IAttrList {
46                 int Length {get;}
47                 bool IsEmpty {get;}
48                 string GetName(int i);
49                 string GetValue(int i);
50                 string GetValue(string name);
51                 void ChangeValue(string name, string newValue);
52                 string[] Names {get;}
53                 string[] Values {get;}
54         }
55
56         public interface IMutableAttrList : IAttrList {
57                 void Clear();
58                 void Add(string name, string value);
59                 void CopyFrom(IAttrList attrs);
60                 void Remove(int i);
61                 void Remove(string name);
62         }
63
64         public interface IHandler {
65                 void OnStartParsing(MiniParser parser);
66                 void OnStartElement(string name, IAttrList attrs);
67                 void OnEndElement(string name);
68                 void OnChars(string ch);
69                 void OnEndParsing(MiniParser parser);
70         }
71
72         public class HandlerAdapter : IHandler {
73                 public HandlerAdapter() {}
74                 public void OnStartParsing(MiniParser parser) {}
75                 public void OnStartElement(string name, IAttrList attrs) {}
76                 public void OnEndElement(string name) {}
77                 public void OnChars(string ch) {}
78                 public void OnEndParsing(MiniParser parser) {}
79         }
80
81         private enum CharKind : byte {
82                 LEFT_BR     = 0,
83                 RIGHT_BR    = 1,
84                 SLASH       = 2,
85                 PI_MARK     = 3,
86                 EQ          = 4,
87                 AMP         = 5,
88                 SQUOTE      = 6,
89                 DQUOTE      = 7,
90                 BANG        = 8,
91                 LEFT_SQBR   = 9,
92                 SPACE       = 0xA,
93                 RIGHT_SQBR  = 0xB,
94                 TAB         = 0xC,
95                 CR          = 0xD,
96                 EOL         = 0xE,
97                 CHARS       = 0xF,
98                 UNKNOWN = 0x1F
99         }
100
101         private enum ActionCode : byte {
102                 START_ELEM               = 0,
103                 END_ELEM                 = 1,
104                 END_NAME                 = 2,
105                 SET_ATTR_NAME            = 3,
106                 SET_ATTR_VAL             = 4,
107                 SEND_CHARS               = 5,
108                 START_CDATA              = 6,
109                 END_CDATA                = 7,
110                 ERROR                    = 8,
111                 STATE_CHANGE             = 9,
112                 FLUSH_CHARS_STATE_CHANGE = 0xA,
113                 ACC_CHARS_STATE_CHANGE   = 0xB,
114                 ACC_CDATA                = 0xC,
115                 PROC_CHAR_REF            = 0xD,
116                 UNKNOWN = 0xF
117         }
118
119         public class AttrListImpl : IMutableAttrList {
120                 protected ArrayList names;
121                 protected ArrayList values;
122
123                 public AttrListImpl() : this(0) {}
124
125                 public AttrListImpl(int initialCapacity) {
126                         if (initialCapacity <= 0) {
127                                 names = new ArrayList();
128                                 values = new ArrayList();
129                         } else {
130                                 names = new ArrayList(initialCapacity);
131                                 values = new ArrayList(initialCapacity);
132                         }
133                 }
134
135                 public AttrListImpl(IAttrList attrs)
136                 : this(attrs != null ? attrs.Length : 0) {
137                         if (attrs != null) this.CopyFrom(attrs);
138                 }
139
140                 public int Length {
141                         get {return names.Count;}
142                 }
143
144                 public bool IsEmpty {
145                         get {return this.Length != 0;}
146                 }
147
148                 public string GetName(int i) {
149                         string res = null;
150                         if (i >= 0 && i < this.Length) {
151                                 res = names[i] as string;
152                         }
153                         return res;
154                 }
155
156                 public string GetValue(int i) {
157                         string res = null;
158                         if (i >= 0 && i < this.Length) {
159                                 res = values[i] as string;
160                         }
161                         return res;
162                 }
163
164                 public string GetValue(string name) {
165                         return this.GetValue(names.IndexOf(name));
166                 }
167
168                 public void ChangeValue(string name, string newValue) {
169                         int i = names.IndexOf(name);
170                         if (i >= 0 && i < this.Length) {
171                                 values[i] = newValue;
172                         }
173                 }
174
175                 public string[] Names {
176                         get {return names.ToArray(typeof(string)) as string[];}
177                 }
178
179                 public string[] Values {
180                         get {return values.ToArray(typeof(string)) as string[];}
181                 }
182
183                 public void Clear() {
184                         names.Clear();
185                         values.Clear();
186                 }
187
188                 public void Add(string name, string value) {
189                         names.Add(name);
190                         values.Add(value);
191                 }
192
193                 public void Remove(int i) {
194                         if (i >= 0) {
195                                 names.RemoveAt(i);
196                                 values.RemoveAt(i);
197                         }
198                 }
199
200                 public void Remove(string name) {
201                         this.Remove(names.IndexOf(name));
202                 }
203
204                 public void CopyFrom(IAttrList attrs) {
205                         if (attrs != null && ((object)this == (object)attrs)) {
206                                 this.Clear();
207                                 int n = attrs.Length;
208                                 for (int i = 0; i < n; i++) {
209                                         this.Add(attrs.GetName(i), attrs.GetValue(i));
210                                 }
211                         }
212                 }
213         }
214
215         public class XMLError : Exception {
216                 protected string descr;
217                 protected int line, column;
218                 public XMLError() : this("Unknown") {}
219                 public XMLError(string descr) : this(descr, -1, -1) {}
220                 public XMLError(string descr, int line, int column)
221                 : base(descr) {
222                         this.descr = descr;
223                         this.line = line;
224                         this.column = column;
225                 }
226                 public int Line {get {return line;}}
227                 public int Column {get {return column;}}
228                 public override string ToString() {
229                         return (String.Format("{0} @ (line = {1}, col = {2})", descr, line, column));
230                 }
231         }
232
233         private static readonly int INPUT_RANGE = 13;
234         private static readonly ushort[] tbl = {
235                 ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 1, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 128, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 128,
236                 ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 2, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 133, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 16, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.FLUSH_CHARS_STATE_CHANGE << 8) | 4,
237                 ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.END_ELEM << 8) | 0, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 2, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 2, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
238                 ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 5, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3,
239                 ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 4, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.END_NAME << 8) | 6, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.END_NAME << 8) | 7, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.END_NAME << 8) | 8, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
240                 ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 3,
241                 ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
242                 ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.FLUSH_CHARS_STATE_CHANGE << 8) | 1, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 10, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 7, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10,
243                 ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_ELEM << 8) | 6, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.START_ELEM << 8) | 7, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 8, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
244                 ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.SET_ATTR_NAME << 8) | 11, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 12, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130,
245                 ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 13, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 10, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 10,
246                 ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 14, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 15, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 11, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 132, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 132,
247                 ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.SET_ATTR_NAME << 8) | 11, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 12, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 130, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 130,
248                 ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.SEND_CHARS << 8) | 2, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 16, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 134, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ERROR << 8) | 134,
249                 ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.SET_ATTR_VAL << 8) | 17, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 14, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 14,
250                 ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.SET_ATTR_VAL << 8) | 17, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.PROC_CHAR_REF << 8) | 15, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 15,
251                 ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 18, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 0, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.START_CDATA << 8) | 19,
252                 ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.START_ELEM << 8) | 6, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.START_ELEM << 8) | 7, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.STATE_CHANGE << 8) | 17, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CHARS_STATE_CHANGE << 8) | 9, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ERROR << 8) | 129, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ERROR << 8) | 129,
253                 ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.END_CDATA << 8) | 10, ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 18,
254                 ((ushort)CharKind.LEFT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.SLASH << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.RIGHT_BR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.PI_MARK << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.EQ << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.AMP << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.SQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.BANG << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.LEFT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.SPACE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.RIGHT_SQBR << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.DQUOTE << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19, ((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.ACC_CDATA << 8) | 19,
255                 0xFFFF
256         };
257
258         protected static string[] errors = {
259                 /* 0 */ "Expected element",
260                 /* 1 */ "Invalid character in tag",
261                 /* 2 */ "No '='",
262                 /* 3 */ "Invalid character entity",
263                 /* 4 */ "Invalid attr value",
264                 /* 5 */ "Empty tag",
265                 /* 6 */ "No end tag",
266                 /* 7 */ "Bad entity ref"
267         };
268
269         protected int line;
270         protected int col;
271         protected int[] twoCharBuff;
272         protected bool splitCData;
273
274         public MiniParser() {
275                 twoCharBuff = new int[2];
276                 splitCData = false;
277                 Reset();
278         }
279
280         public void Reset() {
281                 line = 0;
282                 col = 0;
283         }
284
285         protected static bool StrEquals(string str, StringBuilder sb, int sbStart, int len) {
286                 if (len != str.Length) return false;
287                 for (int i = 0; i < len; i++) {
288                         if (str[i] != sb[sbStart + i]) return false;
289                 }
290                 return true;
291         }
292
293         protected void FatalErr(string descr) {
294                 throw new XMLError(descr, this.line, this.col);
295         }
296
297         protected static int Xlat(int charCode, int state) {
298                 int p = state * INPUT_RANGE;
299                 int n = Math.Min(tbl.Length - p, INPUT_RANGE);
300                 for (;--n >= 0;) {
301                         ushort code = tbl[p];
302                         if (charCode == (code >> 12)) return (code & 0xFFF);
303                         p++;
304                 }
305                 return 0xFFF;
306         }
307
308         public void Parse(IReader reader, IHandler handler) {
309                 if (reader == null) throw new ArgumentNullException("reader");
310                 if (handler == null) handler = new HandlerAdapter();
311
312                 AttrListImpl attrList = new AttrListImpl();
313                 string lastAttrName = null;
314                 Stack tagStack = new Stack();
315                 string elementName = null;
316                 line = 1;
317                 col = 0;
318                 int currCh = 0;
319                 int stateCode = 0;
320                 StringBuilder sbChars = new StringBuilder();
321                 bool seenCData = false;
322                 bool isComment = false;
323                 bool isDTD = false;
324                 int bracketSwitch = 0;
325
326                 handler.OnStartParsing(this);
327
328                 while (true) {
329                         ++this.col;
330                         int prevCh = currCh;
331
332                         currCh = reader.Read();
333
334                         if (currCh == -1) {
335                                 if (stateCode != 0) {
336                                         FatalErr("Unexpected EOF");
337                                 }
338                                 break;
339                         }
340
341                         int charCode = "<>/?=&'\"![ ]\t\r\n".IndexOf((char)currCh) & 0xF;
342                         if (charCode == (int)CharKind.CR) continue; // ignore
343                         // whitepace ::= (#x20 | #x9 | #xd | #xa)+
344                         if (charCode == (int)CharKind.TAB) charCode = (int)CharKind.SPACE; // tab == space
345                         if (charCode == (int)CharKind.EOL) {
346                                 this.col = 0;
347                                 this.line++;
348                                 charCode = (int)CharKind.SPACE;
349                         }
350
351                         int actionCode = MiniParser.Xlat(charCode, stateCode);
352                         stateCode = actionCode & 0xFF;
353                         // Ignore newline inside attribute value.
354                         if (currCh == '\n' && (stateCode == 0xE || stateCode == 0xF)) continue;
355                         actionCode >>= 8;
356
357                         if (stateCode >= 0x80) {
358                                 if (stateCode == 0xFF) {
359                                         FatalErr("State dispatch error.");
360                                 } else {
361                                         FatalErr(errors[stateCode ^ 0x80]);
362                                 }
363                         }
364
365                         switch (actionCode) {
366                                 case (int)ActionCode.START_ELEM:
367                                         handler.OnStartElement(elementName, attrList);
368                                         if (currCh != '/') {
369                                                 tagStack.Push(elementName);
370                                         } else {
371                                                 handler.OnEndElement(elementName);
372                                         }
373                                         attrList.Clear();
374                                         break;
375
376                                 case (int)ActionCode.END_ELEM:
377                                         elementName = sbChars.ToString();
378                                         sbChars = new StringBuilder();
379                                         string endName = null;
380                                         if (tagStack.Count == 0 ||
381                                                 elementName != (endName = tagStack.Pop() as string)) {
382                                                 if (endName == null) {
383                                                         FatalErr("Tag stack underflow");
384                                                 } else {
385                                                         FatalErr(String.Format("Expected end tag '{0}' but found '{1}'", elementName, endName));
386                                                 }
387                                         }
388                                         handler.OnEndElement(elementName);
389                                         break;
390
391                                 case (int)ActionCode.END_NAME:
392                                         elementName = sbChars.ToString();
393                                         sbChars = new StringBuilder();
394                                         if (currCh != '/' && currCh != '>') break;
395                                         goto case (int)ActionCode.START_ELEM;
396
397                                 case (int)ActionCode.SET_ATTR_NAME:
398                                         lastAttrName = sbChars.ToString();
399                                         sbChars = new StringBuilder();
400                                         break;
401
402                                 case (int)ActionCode.SET_ATTR_VAL:
403                                         if (lastAttrName == null) FatalErr("Internal error.");
404                                         attrList.Add(lastAttrName, sbChars.ToString());
405                                         sbChars = new StringBuilder();
406                                         lastAttrName = null;
407                                         break;
408
409                                 case (int)ActionCode.SEND_CHARS:
410                                         handler.OnChars(sbChars.ToString());
411                                         sbChars = new StringBuilder();
412                                         break;
413
414                                 case (int)ActionCode.START_CDATA:
415                                         string cdata = "CDATA[";
416                                         isComment = false;
417                                         isDTD = false;
418
419                                         if (currCh == '-') {
420                                                 currCh = reader.Read();
421
422                                                 if (currCh != '-') FatalErr("Invalid comment");
423
424                                                 this.col++;
425                                                 isComment = true;
426                                                 twoCharBuff[0] = -1;
427                                                 twoCharBuff[1] = -1;
428                                         } else {
429                                                 if (currCh != '[') {
430                                                         isDTD = true;
431                                                         bracketSwitch = 0;
432                                                         break;
433                                                 }
434
435                                                 for (int i = 0; i < cdata.Length; i++) {
436                                                         if (reader.Read() != cdata[i]) {
437                                                                 this.col += i+1;
438                                                                 break;
439                                                         }
440                                                 }
441                                                 this.col += cdata.Length;
442                                                 seenCData = true;
443                                         }
444                                         break;
445
446                                 case (int)ActionCode.END_CDATA:
447                                         int n = 0;
448                                         currCh = ']';
449
450                                         while (currCh == ']') {
451                                                 currCh = reader.Read();
452                                                 n++;
453                                         }
454
455                                         if (currCh != '>') {
456                                                 for (int i = 0; i < n; i++) sbChars.Append(']');
457                                                 sbChars.Append((char)currCh);
458                                                 stateCode = 0x12;
459                                         } else {
460                                                 for (int i = 0; i < n-2; i++) sbChars.Append(']');
461                                                 seenCData = false;
462                                         }
463
464                                         this.col += n;
465                                         break;
466
467                                 case (int)ActionCode.ERROR:
468                                         FatalErr(String.Format("Error {0}", stateCode));
469                                         break;
470
471                                 case (int)ActionCode.STATE_CHANGE:
472                                         break;
473
474                                 case (int)ActionCode.FLUSH_CHARS_STATE_CHANGE:
475                                         sbChars = new StringBuilder();
476                                         if (currCh != '<') goto case (int)ActionCode.ACC_CHARS_STATE_CHANGE;
477                                         break;
478
479                                 case (int)ActionCode.ACC_CHARS_STATE_CHANGE:
480                                         sbChars.Append((char)currCh);
481                                         break;
482
483                                 case (int)ActionCode.ACC_CDATA:
484                                         if (isComment) {
485                                                 if (currCh == '>'
486                                                         && twoCharBuff[0] == '-'
487                                                         && twoCharBuff[1] == '-') {
488                                                         isComment = false;
489                                                         stateCode = 0;
490                                                 } else {
491                                                         twoCharBuff[0] = twoCharBuff[1];
492                                                         twoCharBuff[1] = currCh;
493                                                 }
494                                         } else if (isDTD) {
495                                                 if (currCh == '<' || currCh == '>') bracketSwitch ^= 1;
496                                                 if (currCh == '>' && bracketSwitch != 0) {
497                                                         isDTD = false;
498                                                         stateCode = 0;
499                                                 }
500                                         } else {
501                                                 if (this.splitCData
502                                                         && sbChars.Length > 0
503                                                         && seenCData) {
504                                                         handler.OnChars(sbChars.ToString());
505                                                         sbChars = new StringBuilder();
506                                                 }
507                                                 seenCData = false;
508                                                 sbChars.Append((char)currCh);
509                                         }
510                                         break;
511
512                                 case (int)ActionCode.PROC_CHAR_REF:
513                                         currCh = reader.Read();
514                                         int cl = this.col + 1;
515                                         if (currCh == '#') {    // character reference
516                                                 int r = 10;
517                                                 int chCode = 0;
518                                                 int nDigits = 0;
519                                                 currCh = reader.Read();
520                                                 cl++;
521
522                                                 if (currCh == 'x') {
523                                                         currCh = reader.Read();
524                                                         cl++;
525                                                         r=16;
526                                                 }
527
528                                                 NumberStyles style = r == 16 ? NumberStyles.HexNumber : NumberStyles.Integer;
529
530                                                 while (true) {
531                                                         int x = -1;
532                                                         if (Char.IsNumber((char)currCh) || "abcdef".IndexOf(Char.ToLower((char)currCh)) != -1) {
533                                                                 try {
534                                                                         x = Int32.Parse(new string((char)currCh, 1), style);
535                                                                 } catch (FormatException) {x = -1;}
536                                                         }
537                                                         if (x == -1) break;
538                                                         chCode *= r;
539                                                         chCode += x;
540                                                         nDigits++;
541                                                         currCh = reader.Read();
542                                                         cl++;
543                                                 }
544
545                                                 if (currCh == ';' && nDigits > 0) {
546                                                         sbChars.Append((char)chCode);
547                                                 } else {
548                                                         FatalErr("Bad char ref");
549                                                 }
550                                         } else {
551                                                 // entity reference
552                                                 string entityRefChars = "aglmopqstu"; // amp | apos | quot | gt | lt
553                                                 string entities = "&'\"><";
554
555                                                 int pos = 0;
556                                                 int entIdx = 0xF;
557                                                 int pred = 0;
558                                                 int predShift = 0;
559
560                                                 int sbLen = sbChars.Length;
561
562                                                 while (true) {
563                                                         if (pos != 0xF) pos = entityRefChars.IndexOf((char)currCh) & 0xF;
564                                                         if (pos == 0xF) FatalErr(errors[7]);
565                                                         sbChars.Append((char)currCh);
566
567                                                         int path = "\uFF35\u3F8F\u4F8F\u0F5F\uFF78\uE1F4\u2299\uEEFF\uEEFF\uFF4F"[pos];
568                                                         int lBr = (path >> 4) & 0xF;
569                                                         int rBr = path & 0xF;
570                                                         int lPred = path >> 12;
571                                                         int rPred = (path >> 8) & 0xF;
572                                                         currCh = reader.Read();
573                                                         cl++;
574                                                         pos = 0xF;
575                                                         if (lBr != 0xF && currCh == entityRefChars[lBr]) {
576                                                                 if (lPred < 0xE) entIdx = lPred;
577                                                                 pred = lPred;
578                                                                 predShift = 12; // left
579                                                         } else if (rBr != 0xF && currCh == entityRefChars[rBr]) {
580                                                                 if (rPred < 0xE) entIdx = rPred;
581                                                                 pred = rPred;
582                                                                 predShift = 8; // right
583                                                         } else if (currCh == ';') {
584                                                                 if (entIdx != 0xF
585                                                                         && predShift != 0
586                                                                         && ((path >> predShift) & 0xF) == 0xE) break;
587                                                                 continue; // pos == 0xF
588                                                         }
589
590                                                         pos=0;
591
592                                                 }
593
594                                                 int l = cl - this.col - 1;
595
596                                                 if ((l > 0 && l < 5)
597                                                         &&(StrEquals("amp", sbChars, sbLen, l)
598                                                         || StrEquals("apos", sbChars, sbLen, l)
599                                                         || StrEquals("quot", sbChars, sbLen, l)
600                                                         || StrEquals("lt", sbChars, sbLen, l)
601                                                         || StrEquals("gt", sbChars, sbLen, l))
602                                                         ) {
603                                                                 sbChars.Length = sbLen;
604                                                                 sbChars.Append(entities[entIdx]);
605                                                 } else FatalErr(errors[7]);
606                                         }
607
608                                         this.col = cl;
609                                         break;
610
611                                 default:
612                                         FatalErr(String.Format("Unexpected action code - {0}.", actionCode));
613                                         break;
614                         }
615                 } // while (true)
616
617                 handler.OnEndParsing(this);
618
619         } // Parse
620
621 }
622
623 }