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