2002-11-17 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)(((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),
236                 (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),
237                 (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),
238                 (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),
239                 (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),
240                 (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),
241                 (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),
242                 (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),
243                 (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),
244                 (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),
245                 (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),
246                 (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),
247                 (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),
248                 (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),
249                 (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),
250                 (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),
251                 (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),
252                 (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),
253                 (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),
254                 (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),
255                 (ushort)(((ushort)CharKind.CHARS << 12) | ((ushort)ActionCode.UNKNOWN << 8) | 255),
256                 0xFFFF
257         };
258
259         protected static string[] errors = {
260                 /* 0 */ "Expected element",
261                 /* 1 */ "Invalid character in tag",
262                 /* 2 */ "No '='",
263                 /* 3 */ "Invalid character entity",
264                 /* 4 */ "Invalid attr value",
265                 /* 5 */ "Empty tag",
266                 /* 6 */ "No end tag",
267                 /* 7 */ "Bad entity ref"
268         };
269
270         protected int line;
271         protected int col;
272         protected int[] twoCharBuff;
273         protected bool splitCData;
274
275         public MiniParser() {
276                 twoCharBuff = new int[2];
277                 splitCData = false;
278                 Reset();
279         }
280
281         public void Reset() {
282                 line = 0;
283                 col = 0;
284         }
285
286         protected static bool StrEquals(string str, StringBuilder sb, int sbStart, int len) {
287                 if (len != str.Length) return false;
288                 for (int i = 0; i < len; i++) {
289                         if (str[i] != sb[sbStart + i]) return false;
290                 }
291                 return true;
292         }
293
294         protected void FatalErr(string descr) {
295                 throw new XMLError(descr, this.line, this.col);
296         }
297
298         protected static int Xlat(int charCode, int state) {
299                 int p = state * INPUT_RANGE;
300                 int n = Math.Min(tbl.Length - p, INPUT_RANGE);
301                 for (;--n >= 0;) {
302                         ushort code = tbl[p];
303                         if (charCode == (code >> 12)) return (code & 0xFFF);
304                         p++;
305                 }
306                 return 0xFFF;
307         }
308
309         public void Parse(IReader reader, IHandler handler) {
310                 if (reader == null) throw new ArgumentNullException("reader");
311                 if (handler == null) handler = new HandlerAdapter();
312
313                 AttrListImpl attrList = new AttrListImpl();
314                 string lastAttrName = null;
315                 Stack tagStack = new Stack();
316                 string elementName = null;
317                 line = 1;
318                 col = 0;
319                 int currCh = 0;
320                 int stateCode = 0;
321                 StringBuilder sbChars = new StringBuilder();
322                 bool seenCData = false;
323                 bool isComment = false;
324                 bool isDTD = false;
325                 int bracketSwitch = 0;
326
327                 handler.OnStartParsing(this);
328
329                 while (true) {
330                         ++this.col;
331                         int prevCh = currCh;
332
333                         currCh = reader.Read();
334
335                         if (currCh == -1) {
336                                 if (stateCode != 0) {
337                                         FatalErr("Unexpected EOF");
338                                 }
339                                 break;
340                         }
341
342                         int charCode = "<>/?=&'\"![ ]\t\r\n".IndexOf((char)currCh) & 0xF;
343                         if (charCode == (int)CharKind.CR) continue; // ignore
344                         // whitepace ::= (#x20 | #x9 | #xd | #xa)+
345                         if (charCode == (int)CharKind.TAB) charCode = (int)CharKind.SPACE; // tab == space
346                         if (charCode == (int)CharKind.EOL) {
347                                 this.col = 0;
348                                 this.line++;
349                                 charCode = (int)CharKind.SPACE;
350                         }
351
352                         int actionCode = MiniParser.Xlat(charCode, stateCode);
353                         stateCode = actionCode & 0xFF;
354                         // Ignore newline inside attribute value.
355                         if (currCh == '\n' && (stateCode == 0xE || stateCode == 0xF)) continue;
356                         actionCode >>= 8;
357
358                         if (stateCode >= 0x80) {
359                                 if (stateCode == 0xFF) {
360                                         FatalErr("State dispatch error.");
361                                 } else {
362                                         FatalErr(errors[stateCode ^ 0x80]);
363                                 }
364                         }
365
366                         switch (actionCode) {
367                                 case (int)ActionCode.START_ELEM:
368                                         handler.OnStartElement(elementName, attrList);
369                                         if (currCh != '/') {
370                                                 tagStack.Push(elementName);
371                                         } else {
372                                                 handler.OnEndElement(elementName);
373                                         }
374                                         attrList.Clear();
375                                         break;
376
377                                 case (int)ActionCode.END_ELEM:
378                                         elementName = sbChars.ToString();
379                                         sbChars = new StringBuilder();
380                                         string endName = null;
381                                         if (tagStack.Count == 0 ||
382                                                 elementName != (endName = tagStack.Pop() as string)) {
383                                                 if (endName == null) {
384                                                         FatalErr("Tag stack underflow");
385                                                 } else {
386                                                         FatalErr(String.Format("Expected end tag '{0}' but found '{1}'", elementName, endName));
387                                                 }
388                                         }
389                                         handler.OnEndElement(elementName);
390                                         break;
391
392                                 case (int)ActionCode.END_NAME:
393                                         elementName = sbChars.ToString();
394                                         sbChars = new StringBuilder();
395                                         if (currCh != '/' && currCh != '>') break;
396                                         goto case (int)ActionCode.START_ELEM;
397
398                                 case (int)ActionCode.SET_ATTR_NAME:
399                                         lastAttrName = sbChars.ToString();
400                                         sbChars = new StringBuilder();
401                                         break;
402
403                                 case (int)ActionCode.SET_ATTR_VAL:
404                                         if (lastAttrName == null) FatalErr("Internal error.");
405                                         attrList.Add(lastAttrName, sbChars.ToString());
406                                         sbChars = new StringBuilder();
407                                         lastAttrName = null;
408                                         break;
409
410                                 case (int)ActionCode.SEND_CHARS:
411                                         handler.OnChars(sbChars.ToString());
412                                         sbChars = new StringBuilder();
413                                         break;
414
415                                 case (int)ActionCode.START_CDATA:
416                                         string cdata = "CDATA[";
417                                         isComment = false;
418                                         isDTD = false;
419
420                                         if (currCh == '-') {
421                                                 currCh = reader.Read();
422
423                                                 if (currCh != '-') FatalErr("Invalid comment");
424
425                                                 this.col++;
426                                                 isComment = true;
427                                                 twoCharBuff[0] = -1;
428                                                 twoCharBuff[1] = -1;
429                                         } else {
430                                                 if (currCh != '[') {
431                                                         isDTD = true;
432                                                         bracketSwitch = 0;
433                                                         break;
434                                                 }
435
436                                                 for (int i = 0; i < cdata.Length; i++) {
437                                                         if (reader.Read() != cdata[i]) {
438                                                                 this.col += i+1;
439                                                                 break;
440                                                         }
441                                                 }
442                                                 this.col += cdata.Length;
443                                                 seenCData = true;
444                                         }
445                                         break;
446
447                                 case (int)ActionCode.END_CDATA:
448                                         int n = 0;
449                                         currCh = ']';
450
451                                         while (currCh == ']') {
452                                                 currCh = reader.Read();
453                                                 n++;
454                                         }
455
456                                         if (currCh != '>') {
457                                                 for (int i = 0; i < n; i++) sbChars.Append(']');
458                                                 sbChars.Append((char)currCh);
459                                                 stateCode = 0x12;
460                                         } else {
461                                                 for (int i = 0; i < n-2; i++) sbChars.Append(']');
462                                                 seenCData = false;
463                                         }
464
465                                         this.col += n;
466                                         break;
467
468                                 case (int)ActionCode.ERROR:
469                                         FatalErr(String.Format("Error {0}", stateCode));
470                                         break;
471
472                                 case (int)ActionCode.STATE_CHANGE:
473                                         break;
474
475                                 case (int)ActionCode.FLUSH_CHARS_STATE_CHANGE:
476                                         sbChars = new StringBuilder();
477                                         if (currCh != '<') goto case (int)ActionCode.ACC_CHARS_STATE_CHANGE;
478                                         break;
479
480                                 case (int)ActionCode.ACC_CHARS_STATE_CHANGE:
481                                         sbChars.Append((char)currCh);
482                                         break;
483
484                                 case (int)ActionCode.ACC_CDATA:
485                                         if (isComment) {
486                                                 if (currCh == '>'
487                                                         && twoCharBuff[0] == '-'
488                                                         && twoCharBuff[1] == '-') {
489                                                         isComment = false;
490                                                         stateCode = 0;
491                                                 } else {
492                                                         twoCharBuff[0] = twoCharBuff[1];
493                                                         twoCharBuff[1] = currCh;
494                                                 }
495                                         } else if (isDTD) {
496                                                 if (currCh == '<' || currCh == '>') bracketSwitch ^= 1;
497                                                 if (currCh == '>' && bracketSwitch != 0) {
498                                                         isDTD = false;
499                                                         stateCode = 0;
500                                                 }
501                                         } else {
502                                                 if (this.splitCData
503                                                         && sbChars.Length > 0
504                                                         && seenCData) {
505                                                         handler.OnChars(sbChars.ToString());
506                                                         sbChars = new StringBuilder();
507                                                 }
508                                                 seenCData = false;
509                                                 sbChars.Append((char)currCh);
510                                         }
511                                         break;
512
513                                 case (int)ActionCode.PROC_CHAR_REF:
514                                         currCh = reader.Read();
515                                         int cl = this.col + 1;
516                                         if (currCh == '#') {    // character reference
517                                                 int r = 10;
518                                                 int chCode = 0;
519                                                 int nDigits = 0;
520                                                 currCh = reader.Read();
521                                                 cl++;
522
523                                                 if (currCh == 'x') {
524                                                         currCh = reader.Read();
525                                                         cl++;
526                                                         r=16;
527                                                 }
528
529                                                 NumberStyles style = r == 16 ? NumberStyles.HexNumber : NumberStyles.Integer;
530
531                                                 while (true) {
532                                                         int x = -1;
533                                                         if (Char.IsNumber((char)currCh) || "abcdef".IndexOf(Char.ToLower((char)currCh)) != -1) {
534                                                                 try {
535                                                                         x = Int32.Parse(new string((char)currCh, 1), style);
536                                                                 } catch (FormatException) {x = -1;}
537                                                         }
538                                                         if (x == -1) break;
539                                                         chCode *= r;
540                                                         chCode += x;
541                                                         nDigits++;
542                                                         currCh = reader.Read();
543                                                         cl++;
544                                                 }
545
546                                                 if (currCh == ';' && nDigits > 0) {
547                                                         sbChars.Append((char)chCode);
548                                                 } else {
549                                                         FatalErr("Bad char ref");
550                                                 }
551                                         } else {
552                                                 // entity reference
553                                                 string entityRefChars = "aglmopqstu"; // amp | apos | quot | gt | lt
554                                                 string entities = "&'\"><";
555
556                                                 int pos = 0;
557                                                 int entIdx = 0xF;
558                                                 int pred = 0;
559                                                 int predShift = 0;
560
561                                                 int sbLen = sbChars.Length;
562
563                                                 while (true) {
564                                                         if (pos != 0xF) pos = entityRefChars.IndexOf((char)currCh) & 0xF;
565                                                         if (pos == 0xF) FatalErr(errors[7]);
566                                                         sbChars.Append((char)currCh);
567
568                                                         int path = "\uFF35\u3F8F\u4F8F\u0F5F\uFF78\uE1F4\u2299\uEEFF\uEEFF\uFF4F"[pos];
569                                                         int lBr = (path >> 4) & 0xF;
570                                                         int rBr = path & 0xF;
571                                                         int lPred = path >> 12;
572                                                         int rPred = (path >> 8) & 0xF;
573                                                         currCh = reader.Read();
574                                                         cl++;
575                                                         pos = 0xF;
576                                                         if (lBr != 0xF && currCh == entityRefChars[lBr]) {
577                                                                 if (lPred < 0xE) entIdx = lPred;
578                                                                 pred = lPred;
579                                                                 predShift = 12; // left
580                                                         } else if (rBr != 0xF && currCh == entityRefChars[rBr]) {
581                                                                 if (rPred < 0xE) entIdx = rPred;
582                                                                 pred = rPred;
583                                                                 predShift = 8; // right
584                                                         } else if (currCh == ';') {
585                                                                 if (entIdx != 0xF
586                                                                         && predShift != 0
587                                                                         && ((path >> predShift) & 0xF) == 0xE) break;
588                                                                 continue; // pos == 0xF
589                                                         }
590
591                                                         pos=0;
592
593                                                 }
594
595                                                 int l = cl - this.col - 1;
596
597                                                 if ((l > 0 && l < 5)
598                                                         &&(StrEquals("amp", sbChars, sbLen, l)
599                                                         || StrEquals("apos", sbChars, sbLen, l)
600                                                         || StrEquals("quot", sbChars, sbLen, l)
601                                                         || StrEquals("lt", sbChars, sbLen, l)
602                                                         || StrEquals("gt", sbChars, sbLen, l))
603                                                         ) {
604                                                                 sbChars.Length = sbLen;
605                                                                 sbChars.Append(entities[entIdx]);
606                                                 } else FatalErr(errors[7]);
607                                         }
608
609                                         this.col = cl;
610                                         break;
611
612                                 default:
613                                         FatalErr(String.Format("Unexpected action code - {0}.", actionCode));
614                                         break;
615                         }
616                 } // while (true)
617
618                 handler.OnEndParsing(this);
619
620         } // Parse
621
622 }
623
624 }