source: trunk/src/xmldecl.c @ 1932

Last change on this file since 1932 was 529, checked in by cameron, 9 years ago

Encoding Name validation.

File size: 8.7 KB
Line 
1/*  xmldecl.c - Parsing XML and Text Declarations.
2    Copyright (c) 2008, Robert D. Cameron.
3    Licensed to the public under the Open Software License 3.0.
4    Licensed to International Characters, Inc., under the Academic
5    Free License 3.0.
6
7*/
8
9#include "byteplex.h"
10#include "xmldecl.h"
11#include "xml_error.h"
12#include "multiliteral.h"
13#include "bytelex.h"
14
15Entity_Info::Entity_Info() {
16        encoding = NULL;
17}
18Entity_Info::~Entity_Info() {
19        delete [] encoding;
20}
21
22/* Signature-based character set family detection in accord with
23   Appendix F of the XML 1.0 and 1.1 specifications. */
24
25/* These definitions use b2int16 to determine appropriate doublebyte
26   values based on endianness of the underlying architecture. */
27static const int x0000 = b2int16<0x00, 0x00>::value;
28static const int xFEFF = b2int16<0xFE, 0xFF>::value;
29static const int xFFFE = b2int16<0xFF, 0xFE>::value;
30static const int x003C = b2int16<0x00, 0x3C>::value;
31static const int x3C00 = b2int16<0x3C, 0x00>::value;
32static const int x4C6F = b2int16<0x4C, 0x6F>::value;
33static const int xA794 = b2int16<0xA7, 0x94>::value;
34static const int xEFBE = b2int16<0xEF, 0xBE>::value;
35
36void Entity_Info::AnalyzeSignature(unsigned char * signature) {
37        uint16_t * XML_dbl_byte = (uint16_t *) signature;
38        switch (XML_dbl_byte[0]) {
39                case x0000:
40                        switch (XML_dbl_byte[1]) {
41                                case xFEFF: set_charset_family(ASCII, QuadByte, BigEndian, 1);break;
42                                case xFFFE: set_charset_family(ASCII, QuadByte, Unusual_2143, 1);break;
43                                case x3C00: set_charset_family(ASCII, QuadByte, Unusual_2143, 0);break;
44                                default: set_charset_family(ASCII, QuadByte, BigEndian, 0);
45                        }
46                        break;
47                case xFEFF:
48                        if (XML_dbl_byte[1] == x0000)
49                                set_charset_family(ASCII, QuadByte, Unusual_3412, 1);
50                        else set_charset_family(ASCII, DoubleByte, BigEndian, 1);
51                        break;
52                case xFFFE:
53                        if (XML_dbl_byte[1] == x0000)
54                                set_charset_family(ASCII, QuadByte, LittleEndian, 1);
55                        else set_charset_family(ASCII, DoubleByte, LittleEndian, 1);
56                        break;
57                case x003C:
58                        if (XML_dbl_byte[1] == x0000)
59                                set_charset_family(ASCII, QuadByte, Unusual_3412, 0);
60                        else set_charset_family(ASCII, DoubleByte, BigEndian, 0);
61                        break;
62                case x3C00:
63                        if (XML_dbl_byte[1] == x0000)
64                                set_charset_family(ASCII, QuadByte, LittleEndian, 0);
65                        else set_charset_family(ASCII, DoubleByte, LittleEndian, 0);
66                        break;
67                case x4C6F:
68                        if (XML_dbl_byte[1] == xA794)
69                                set_charset_family(EBCDIC, SingleByte, BigEndian, 0);
70                        else set_charset_family(ASCII, SingleByte, BigEndian, 0);
71                        break;
72                case xEFBE:
73                        if (signature[2] == 0xBF)
74                                set_charset_family(ASCII, SingleByte, BigEndian, 3);
75                        else set_charset_family(ASCII, SingleByte, BigEndian, 0);
76                        break;
77                default:
78                        set_charset_family(ASCII, SingleByte, BigEndian, 0);
79        }
80}
81void Entity_Info::set_charset_family(CodeUnit_Base C, CodeUnit_Size S, CodeUnit_ByteOrder O, int B){
82                code_unit_base = C;
83                code_unit_size = S;
84                byte_order = O;
85                BOM_units = B;
86 }
87
88
89template <CodeUnit_Base C>
90XML_Decl_Parser<C>::XML_Decl_Parser(Byteplex * b){
91        byteplex = b;
92        buffer_base_pos = 0;
93        x8data = (unsigned char *) byteplex->x8data;
94}
95
96template <CodeUnit_Base C>
97XML_Decl_Parser<C>::~XML_Decl_Parser(){
98}
99
100template <CodeUnit_Base C>
101inline void XML_Decl_Parser<C>::DeclError() {
102        DeclarationError(AbsPos());
103}
104
105template <CodeUnit_Base C>
106inline int XML_Decl_Parser<C>::AbsPos() const {
107        return  buffer_base_pos + buffer_rel_pos;
108}
109
110template <CodeUnit_Base C>
111inline unsigned char * XML_Decl_Parser<C>::cur() const {
112        return &x8data[buffer_rel_pos];
113}
114
115template <CodeUnit_Base C>
116inline void XML_Decl_Parser<C>::Advance(int n) {
117        buffer_rel_pos += n;
118        if (buffer_rel_pos >= BYTEPLEX_SIZE) {
119                 byteplex->AdvanceInputBuffer(BYTEPLEX_SIZE);
120        }
121}
122
123template <CodeUnit_Base C>
124inline void XML_Decl_Parser<C>::Scan_WS() {
125        while (at_WhiteSpace_10<C>(cur())) Advance(1);
126}
127
128template <CodeUnit_Base C>
129inline void XML_Decl_Parser<C>::ScanToEncodingName() {
130        int quote_start_pos = buffer_rel_pos;
131        if (at_ASCII_letter<C>(cur())) {
132          buffer_rel_pos+=1;
133          while (at_ASCII_ncnamechar<C>(cur())) buffer_rel_pos+=1;
134        }
135        if (buffer_rel_pos >= BYTEPLEX_SIZE) {
136                byteplex->AdvanceInputBuffer(quote_start_pos);
137                buffer_rel_pos -= quote_start_pos;
138                buffer_base_pos += quote_start_pos;
139                while (!AtQuote<C>(cur())) buffer_rel_pos+=1;
140                if (buffer_rel_pos >= BYTEPLEX_SIZE) {
141                        ImplementationLimitError("Encoding name exceeds BYTEPLEX_SIZE");
142                }
143        }
144}
145
146template <CodeUnit_Base C>
147inline void XML_Decl_Parser<C>::ParseVersion(Entity_Info & e) {
148        /* Skip "version" */
149        Advance(7);
150        Scan_WS();
151        if (!AtChar<C,'='>(cur())) DeclError();
152        Advance(1);
153        Scan_WS();
154        if (at_1_0<C>(cur())) e.version = XML_1_0;
155        else if (at_1_1<C>(cur())) e.version = XML_1_1;
156        else DeclError();
157        Advance(5);
158}
159
160template <CodeUnit_Base C>
161inline void XML_Decl_Parser<C>::ParseEncoding(Entity_Info & e) {
162        /* Skip "encoding" */
163        Advance(8);
164        e.has_encoding_decl = true;
165        Scan_WS();
166        if (!AtChar<C,'='>(cur())) DeclError();
167        Advance(1);
168        Scan_WS();
169        if (AtQuote<C>(cur())) {
170                unsigned char quoteCh = cur()[0];
171                Advance(1);
172                int start_pos = AbsPos();
173                ScanToEncodingName();
174                if (cur()[0] != quoteCh) DeclError();
175                int lgth = AbsPos() - start_pos;
176                e.encoding = new unsigned char[lgth + 1];
177                memcpy(e.encoding, &x8data[start_pos-buffer_base_pos], lgth);
178                e.encoding[lgth] = '\0';
179        }
180        else DeclError();
181        Advance(1);
182}
183
184template <CodeUnit_Base C>
185inline void XML_Decl_Parser<C>::ParseStandalone(Entity_Info & e) {
186        /* Skip "standalone" */
187        Advance(10);
188        Scan_WS();
189        if (!AtChar<C,'='>(cur())) DeclError();
190        Advance(1);
191        Scan_WS();
192        if (at_yes<C>(cur())) {Advance(5); e.standalone = Standalone_yes;}
193        else if (at_no<C>(cur())) {Advance(4); e.standalone = Standalone_no;}
194        else DeclError();
195}
196
197template <CodeUnit_Base C>
198void XML_Decl_Parser<C>::ReadXMLInfo(Entity_Info & e) {
199        e.version = no_XML_version_value;
200        e.has_encoding_decl = false;
201        e.standalone = Standalone_no_value;
202        buffer_rel_pos = e.BOM_units;
203        // It is possible that there is no XML declaration.
204        if (!at_XmlDecl_start<C>(cur())) {
205                e.content_start = AbsPos();
206                return;
207        }
208        // Otherwise, the XML declaration exists and must have
209        // at least version information.
210        Advance(6);
211        Scan_WS();
212        if (!at_version<C>(cur())) DeclError();
213        ParseVersion(e);
214        if (at_PI_End<C>(cur())) {
215                e.content_start = AbsPos()+2;
216                return;
217        }
218        if (!at_WhiteSpace_10<C>(cur())) DeclError();
219        Scan_WS();
220        if (at_encoding<C>(cur())) {
221                ParseEncoding(e);
222                if (at_PI_End<C>(cur())) {
223                        e.content_start = AbsPos()+2;
224                        return;
225                }
226                if (!at_WhiteSpace_10<C>(cur())) DeclError();
227                Scan_WS();
228        }
229        if (at_standalone<C>(cur())) {
230                ParseStandalone(e);
231                Scan_WS();
232        }
233        if (!at_PI_End<C>(cur())) DeclError();
234        e.content_start = AbsPos()+2;
235}
236
237// Similar to reading the XML_declaration of the document entity,
238// ReadTextDeclaration reads the text declaration of an external
239// parsed entity.
240template <CodeUnit_Base C>
241void XML_Decl_Parser<C>::ReadTextDeclaration(Entity_Info & e) {
242        e.version = no_XML_version_value;
243        e.has_encoding_decl = false;
244        e.standalone = Standalone_no_value;
245        buffer_rel_pos = e.BOM_units;
246        // It is possible that there is no text declaration.
247        if (!at_XmlDecl_start<C>(cur())) {
248                e.content_start = AbsPos();
249                return;
250        }
251        // Otherwise, the text declaration exists and may have
252        // version information.
253        Advance(6);
254        Scan_WS();
255        if (at_version<C>(cur())) {
256                ParseVersion(e);
257                // Must have whitespace character before encoding declaration.
258                if (!at_WhiteSpace_10<C>(cur())) DeclError();
259                Scan_WS();
260        }
261        if (!at_encoding<C>(cur())) DeclError();
262        ParseEncoding(e);
263        Scan_WS();
264        if (!at_PI_End<C>(cur())) DeclError();
265        e.content_start = AbsPos()+2;
266}
267
268template <CodeUnit_Base C>
269void XML_Decl_Parser<C>::ReadXMLorTextDecl(Entity_Info & e) {
270        e.version = no_XML_version_value;
271        e.has_encoding_decl = false;
272        e.standalone = Standalone_no_value;
273        buffer_rel_pos = e.BOM_units;
274        // It is possible that there is no XML or text declaration.
275        if (!at_XmlDecl_start<C>(cur())) {
276                e.content_start = AbsPos();
277                return;
278        }
279        // Otherwise, the XML or text declaration exists and may have
280        // version information.
281        Advance(6);
282        Scan_WS();
283        if (at_version<C>(cur())) {
284                ParseVersion(e);
285                if (at_PI_End<C>(cur())) {
286                        e.content_start = AbsPos()+2;
287                        return;
288                }
289                if (!at_WhiteSpace_10<C>(cur())) DeclError();
290                Scan_WS();
291                if (at_encoding<C>(cur())) {
292                        ParseEncoding(e);
293                        if (at_PI_End<C>(cur())) {
294                                e.content_start = AbsPos()+2;
295                                return;
296                        }
297                        if (!at_WhiteSpace_10<C>(cur())) DeclError();
298                        Scan_WS();
299                }
300                if (at_standalone<C>(cur())) {
301                        ParseStandalone(e);
302                        Scan_WS();
303                }
304        }
305        else {  // Without version, we can only have a text declaration,
306                // in which case an encoding spec is required.
307                if (!at_encoding<C>(cur())) DeclError();
308                ParseEncoding();
309                Scan_WS();
310                // No standalone spec is allowed in a text declaration.
311        }
312        if (!at_PI_End<C>(cur())) DeclError(); 
313        e.content_start = AbsPos()+2;
314}
Note: See TracBrowser for help on using the repository browser.