1 /*
2  * Hunt - A xml library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.xml.Internal;
13 
14 import hunt.xml.Common;
15 
16 import hunt.logging.ConsoleLogger;
17 
18 // dfmt off
19 
20 ubyte[256] lookup_whitespace = [
21  // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
22     0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  0,  0,  1,  0,  0,  // 0
23     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 1
24     1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 2
25     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 3
26     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 4
27     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 5
28     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 6
29     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 7
30     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 8
31     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // 9
32     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // A
33     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // B
34     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // C
35     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // D
36     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  // E
37     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0   // F
38 ];              // Whitespace table
39 
40 ubyte[256] lookup_node_name = [
41 // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
42     0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
43     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
44     0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  // 2
45     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  // 3
46     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
47     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
48     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
49     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
50     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
51     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
52     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
53     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
54     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
55     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
56     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
57     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
58 ];           // Node name table
59 
60 ubyte[256] lookup_element_name = [
61 // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
62     0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
63     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
64     0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  // 2
65     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  0,  0,  // 3
66     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
67     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
68     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
69     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
70     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
71     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
72     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
73     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
74     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
75     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
76     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
77     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
78 ];          // Element name table
79 
80 ubyte[256] lookup_text =  [
81 // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
82     0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
83     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
84     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
85     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
86     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
87     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
88     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
89     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
90     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
91     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
92     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
93     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
94     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
95     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
96     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
97     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
98 ];
99                     // Text table
100 ubyte[256] lookup_text_pure_no_ws =  [
101 // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
102     0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
103     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
104     1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
105     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
106     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
107     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
108     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
109     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
110     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
111     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
112     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
113     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
114     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
115     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
116     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
117     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
118 ];
119          // Text table
120 ubyte[256] lookup_text_pure_with_ws =  [
121 // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
122     0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
123     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
124     0,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
125     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  // 3
126     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
127     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
128     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
129     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
130     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
131     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
132     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
133     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
134     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
135     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
136     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
137     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
138 ];
139 
140 // Text table
141 ubyte[256] lookup_attribute_name  = [
142   // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
143     0,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  0,  1,  1,  // 0
144     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
145     0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  // 2
146     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  // 3
147     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
148     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
149     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
150     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
151     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
152     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
153     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
154     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
155     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
156     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
157     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
158     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
159 ];
160 
161 // Attribute name table
162 ubyte[256] lookup_attribute_data_1 = [
163 // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
164     0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
165     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
166     1,  1,  1,  1,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
167     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
168     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
169     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
170     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
171     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
172     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
173     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
174     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
175     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
176     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
177     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
178     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
179     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
180 ];
181 
182 // Attribute data table with single quote
183 ubyte[256] lookup_attribute_data_1_pure =  [
184  // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
185     0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
186     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
187     1,  1,  1,  1,  1,  1,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
188     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
189     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
190     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
191     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
192     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
193     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
194     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
195     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
196     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
197     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
198     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
199     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
200     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
201 ];
202 
203 // Attribute data table with single quote
204 ubyte[256] lookup_attribute_data_2 =  [
205  // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
206     0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
207     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
208     1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
209     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
210     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
211     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
212     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
213     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
214     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
215     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
216     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
217     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
218     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
219     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
220     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
221     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
222 ];
223 
224 // Attribute data table with double quotes
225 ubyte[256] lookup_attribute_data_2_pure = [
226  // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
227     0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0
228     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 1
229     1,  1,  0,  1,  1,  1,  0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 2
230     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 3
231     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 4
232     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 5
233     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 6
234     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 7
235     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 8
236     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 9
237     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // A
238     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // B
239     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // C
240     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // D
241     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // E
242     1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // F
243 ];
244 
245 // Attribute data table with double quotes
246 
247 ubyte[256] lookup_digits =  [
248  // 0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
249     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 0
250     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 1
251     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 2
252     0,  1,  2,  3,  4,  5,  6,  7,  8,  9,255,255,255,255,255,255,    // 3
253     255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255,  // 4
254     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 5
255     255, 10, 11, 12, 13, 14, 15,255,255,255,255,255,255,255,255,255,  // 6
256     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 7
257     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 8
258     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // 9
259     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // A
260     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // B
261     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // C
262     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // D
263     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,  // E
264     255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255   // F
265 ];
266 
267 // Digits
268 
269 ubyte[256] lookup_upcase =  [
270  // 0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  A   B   C   D   E   F
271     0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15,   // 0
272     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,   // 1
273     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,   // 2
274     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,   // 3
275     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,   // 4
276     80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,   // 5
277     96, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,   // 6
278     80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 123,124,125,126,127,  // 7
279     128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,  // 8
280     144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,  // 9
281     160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,  // A
282     176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,  // B
283     192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,  // C
284     208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,  // D
285     224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,  // E
286     240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255   // F
287 ]; 
288 
289 // dfmt on
290 
291 void insertCodedCharacter(int Flags)(ref char[] text,  ulong code)
292 {
293     if (Flags & ParsingFlags.NoUtf8)
294     {
295         // Insert 8-bit ASCII character
296         // Todo: possibly verify that code is less than 256 and use replacement char otherwise?
297         text[0] = cast(char)(code);
298         text = text[ 1 .. $];
299     }
300     else
301     {
302         // Insert UTF8 sequence
303         if (code < 0x80)    // 1 byte sequence
304         {
305             text[0] = cast(char)(code);
306             text = text[1 .. $];
307         }
308         else if (code < 0x800)  // 2 byte sequence
309         {
310             text[1] = cast(char)((code | 0x80) & 0xBF); code >>= 6;
311             text[0] = cast(char)(code | 0xC0);
312             text = text[ 2 .. $];
313         }
314         else if (code < 0x10000)    // 3 byte sequence
315         {
316             text[2] = cast(char)((code | 0x80) & 0xBF); code >>= 6;
317             text[1] = cast(char)((code | 0x80) & 0xBF); code >>= 6;
318             text[0] = cast(char)(code | 0xE0);
319             text = text[3 .. $];
320         }
321         else if (code < 0x110000)   // 4 byte sequence
322         {
323             text[3] = cast(char)((code | 0x80) & 0xBF); code >>= 6;
324             text[2] = cast(char)((code | 0x80) & 0xBF); code >>= 6;
325             text[1] = cast(char)((code | 0x80) & 0xBF); code >>= 6;
326             text[0] = cast(char)(code | 0xF0);
327             text = text[4 .. $];
328         }
329         else    // Invalid, only codes up to 0x10FFFF are allowed in Unicode
330         {
331             throw new XmlParsingException("invalid numeric character entity", text);
332         }
333     }
334 }
335 
336 // Skip characters until predicate evaluates to true while doing the following:
337 // - replacing XML character entity references with proper characters (&apos; &amp; &quot; &lt; &gt; &#...;)
338 // - condensing whitespace sequences to single space character
339 
340 static  char[] skipAndExpandCharacterRefs(T , TP , int Flags)(ref char[] text)
341 {
342     // If entity translation, whitespace condense and whitespace trimming is disabled, use plain skip
343     if (Flags & ParsingFlags.EntityTranslation &&
344         !(Flags & ParsingFlags.NormalizeWhitespace) &&
345         !(Flags & ParsingFlags.TrimWhitespace))
346     {
347         skip!(T)(text);
348         return text;
349     }
350 
351     // Use simple skip until first modification is detected
352     skip!(TP)(text);
353     // Use translation skip
354     char[] src = text;
355     char[] dest = src;
356     long index = 0;
357     while (T.test(src[0]))
358     {
359         // If entity translation is enabled
360         if (!(Flags & ParsingFlags.EntityTranslation))
361         {
362             // Test if replacement is needed
363             if (src[0] == ('&'))
364             {
365                 switch (src[1])
366                 {
367 
368                 // &amp; &apos;
369                 case ('a'):
370                     if (src[2] == ('m') && src[3] == ('p') && src[4] == (';'))
371                     {
372                         dest[index] = ('&');
373                         ++index;
374                         src=src[5..$];
375                         
376                         continue;
377                     }
378                     if (src[2] == ('p') && src[3] == ('o') && src[4] == ('s') && src[5] == (';'))
379                     {
380                         dest[index] = ('\'');
381                         ++index;
382                         src = src[6 .. $];
383                         continue;
384                     }
385                     break;
386 
387                 // &quot;
388                 case ('q'):
389                     if (src[2] == ('u') && src[3] == ('o') && src[4] == ('t') && src[5] == (';'))
390                     {
391                         dest[index] = ('"');
392                         ++index;
393                         src = src[6 .. $];
394                         continue;
395                     }
396                     break;
397 
398                 // &gt;
399                 case ('g'):
400                     if (src[2] == ('t') && src[3] == (';'))
401                     {
402                         dest[index] = ('>');
403                         ++index;
404                         src = src[4 .. $];
405                         continue;
406                     }
407                     break;
408 
409                 // &lt;
410                 case ('l'):
411                     if (src[2] == ('t') && src[3] == (';'))
412                     {
413                         dest[index] = ('<');
414                         ++index;
415                         src = src[ 4 .. $];
416                         continue;
417                     }
418                     break;
419 
420                 // &#...; - assumes ASCII
421                 case ('#'):
422                     if (src[2] == ('x'))
423                     {
424                         ulong code = 0;
425                         src = src[3 .. $];   // Skip &#x
426                         while (1)
427                         {
428                             ubyte digit = lookup_digits[src[0]];
429                             if (digit == 0xFF)
430                                 break;
431                             code = code * 16 + digit;
432                             src = src[1 .. $];
433                         }
434                         
435                         insertCodedCharacter!Flags(dest, code);    // Put character in output
436                     }
437                     else
438                     {
439                         ulong code = 0;
440                         src = src[2 .. $];   // Skip &#
441                         while (1)
442                         {
443                             ubyte digit = lookup_digits[src[0]];
444                             if (digit == 0xFF)
445                                 break;
446                             code = code * 10 + digit;
447                             src=src[1 .. $];
448                         }
449                          insertCodedCharacter!Flags(dest, code);    // Put character in output
450                     }
451                     if (src[0] == (';'))
452                         src=src[1..$];
453                     else
454                         throw new XmlParsingException("expected ;", src);
455                     continue;
456 
457                 // Something else
458                 default:
459                     // Ignore, just copy '&' verbatim
460                     break;
461 
462                 }
463             }
464         }
465 
466         // If whitespace condensing is enabled
467         if (Flags & ParsingFlags.NormalizeWhitespace)
468         {
469             // Test if condensing is needed
470             if (WhitespacePred.test(src[0]))
471             {
472                 dest[index] = (' '); ++index;    // Put single space in dest
473                 src = src[1 .. $];                      // Skip first whitespace char
474                 // Skip remaining whitespace chars
475                 while (WhitespacePred.test(src[0]))
476                     src = src[1 .. $];
477                 continue;
478             }
479         }
480 
481         // No replacement, only copy character
482         dest[index] = src[0];
483         ++index;
484         src = src[1 .. $];
485 
486     }
487 
488     // Return new end
489     text = src;
490     dest = dest[index..$];
491     return dest;
492 
493 }
494 
495     // private static void skip(T )(ref char[] text)
496     // {
497 
498     //     char[] tmp = text;
499     //     while(tmp.length > 0 && T.test(tmp[0]))
500     //     {
501     //         tmp = tmp[1 .. $];    
502     //     }
503     //     text = tmp;
504     // }
505 
506 
507 void skip(T)(ref char[] text)
508 {
509     int index = 0;
510     int length = cast(int)text.length;
511     while(index < text.length && T.test(text[index]))
512         index++;
513     text = text[index .. $];
514 }
515 
516 struct WhitespacePred
517 {
518     static ubyte test(ubyte ch)
519     {
520         return lookup_whitespace[ch];
521     }
522 }
523 
524 // Detect node name character
525 struct NodeNamePred
526 {
527     static ubyte test(ubyte ch)
528     {
529         return lookup_node_name[ch];
530     }
531 }
532 
533 // Detect element name character
534 struct ElementNamePred
535 {
536     static ubyte test(ubyte ch)
537     {
538         return lookup_element_name[ch];
539     }
540 }
541 
542 // Detect attribute name character
543 struct AttributeNamePred
544 {
545     static ubyte test(ubyte ch)
546     {
547         return lookup_attribute_name[ch];
548     }
549 }
550 
551 // Detect text character (PCDATA)
552 struct TextPred
553 {
554     static ubyte test(ubyte ch)
555     {
556         return lookup_text[ch];
557     }
558 }
559 
560 // Detect text character (PCDATA) that does not require processing
561 struct TextPureNoWsPred
562 {
563     static ubyte test(ubyte ch)
564     {
565         return lookup_text_pure_no_ws[ch];
566     }
567 }
568 
569 // Detect text character (PCDATA) that does not require processing
570 struct TextPureWithWsPred
571 {
572     static  ubyte test(ubyte ch)
573     {
574         return lookup_text_pure_with_ws[ch];
575     }
576 }
577 
578 // Detect attribute value character
579 
580 struct AttributeValuePred(alias Quote)
581 {
582     static ubyte test(ubyte ch)
583     {
584         if (Quote == '\'')
585             return lookup_attribute_data_1[ch];
586         else if (Quote == '"')
587             return lookup_attribute_data_2[ch];
588         else
589             return 0;       // Should never be executed, to avoid warnings on Comeau
590     }
591 }
592 
593 // Detect attribute value character
594 struct AttributeValuePurePred(alias Quote)
595 {
596     static ubyte test(ubyte ch)
597     {
598         if (Quote == '\'')
599             return lookup_attribute_data_1_pure[ch];
600         else if (Quote == ('"'))
601             return lookup_attribute_data_2_pure[ch];
602         else
603             return 0;       // Should never be executed, to avoid warnings on Comeau
604     }
605 }