source: trunk/src/engine.c @ 14

Last change on this file since 14 was 14, checked in by cameron, 11 years ago

Optimized ]]> testing; end-tag scan

File size: 19.3 KB
Line 
1/*  engine.c - Parabix XML parsing engine.
2    Copyright (c) 2007, 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#include "ilax.h"
9#include "engine.h"
10#include "xmlbuffer.h"
11#include "bitlex.h"
12#include "charsets/ext_ascii_8.h"
13#include "charsets/ext_ascii_16.h"
14
15#include <assert.h>
16#include <stdlib.h>
17#include <errno.h>
18#include <string.h>
19
20ParsingEngine::ParsingEngine (char * filename) {
21#ifdef BUFFER_PROFILING
22        bitstream_timer = init_BOM_timer(BUFFER_BLOCKS * BLOCKSIZE);
23        lextranspose_timer = init_BOM_timer(BUFFER_BLOCKS * BLOCKSIZE);
24        scanner_timer = init_BOM_timer(BUFFER_BLOCKS * BLOCKSIZE);
25#endif
26
27#define OFFSET32_SENTINEL
28
29  /* Install sentinels for every lexical item stream*/
30#ifndef OPTIMIZE_SHORT_SCAN
31  BitBlock sentinel_value = simd_const_1(1);
32#endif
33#ifdef OPTIMIZE_SHORT_SCAN
34  BitBlock sentinel_value = bitblock_sfli(simd_const_1(1), 8*sizeof(unsigned long));
35#endif
36  for (int j = MarkupStart; j < LexicalItemCount; j++) {
37    buf.item_stream[j][BUFFER_BLOCKS] = sentinel_value;
38  }
39  buffer_base_pos = 0;
40  buffer_rel_pos = 0;
41  xml_buf = new XML_Buffer::XML_Buffer(filename, BLOCKSIZE);
42}
43
44void ParsingEngine::InitLexer() {
45  unsigned char * XML_signature = xml_buf->GetBytePtr(0);
46  if (xml_buf->PrepareBytes(4) < 4) {
47    printf("No XML input document.\n");
48    exit(-1);
49  }
50  Charset_Family family = Charset_Family_Detect(XML_signature);
51  switch (family) {
52    case Ext_ASCII_8:
53      printf("Ext_ASCII_8 document detected.\n");
54      lex = new Ext_ASCII_8_Lexer::Ext_ASCII_8_Lexer(xml_buf, &buf);
55      //lex = new Lexer::Lexer(xml_buf, &buf);
56      //xml_buf->InstallPadding(sentinel);
57      break;
58    case Ext_ASCII_16BE:
59      printf("Ext_ASCII_16BE document detected.\n");
60      lex = new Ext_ASCII_16BE_Lexer::Ext_ASCII_16BE_Lexer(xml_buf, &buf);
61      break;
62    case Ext_ASCII_16LE:
63      printf("Ext_ASCII_16LE document detected.\n");
64      lex = new Ext_ASCII_16LE_Lexer::Ext_ASCII_16LE_Lexer(xml_buf, &buf);
65      break;
66    default:
67      printf("Error: Charset family %i detected, but not supported.\n", family);
68      exit(-1);
69  }
70  rel_EOF_pos = lex-> AdvanceBuffer(0);
71}
72
73
74inline void ParsingEngine::AdvanceToNewBasePosn(int advance_amt) {
75  buffer_base_pos += advance_amt;
76  buffer_rel_pos = 0;
77}
78
79inline unsigned char * ParsingEngine::x8dataPtr(int offset) const {
80  return &((unsigned char *) buf.x8data)[buffer_rel_pos+offset];
81}
82
83
84inline int ParsingEngine::AbsPos() const {
85  return buffer_base_pos + buffer_rel_pos;
86}
87
88
89inline int ParsingEngine::BufferRelPos() const {
90  return buffer_rel_pos;
91}
92
93inline bool ParsingEngine::at_EOF () const {
94  return buffer_rel_pos >= rel_EOF_pos;
95}
96
97inline void ParsingEngine::Advance(int n) {
98  buffer_rel_pos += n;
99#ifndef OMIT_BITBUFFER_LIMIT_TEST_IN_ADVANCE
100  if (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
101    FinalizeBuffer_action();
102#ifdef BUFFER_PROFILING
103    end_BOM_interval(scanner_timer);
104#endif
105    AdvanceToNewBasePosn(buffer_rel_pos);
106    rel_EOF_pos = lex->AdvanceBuffer(AbsPos());
107  }
108#endif
109}
110
111#ifndef OPTIMIZE_SHORT_SCAN
112inline void ParsingEngine::ScanTo(int item) {
113  buffer_rel_pos = bitstream_scan(buf.item_stream[item], 
114                                      buffer_rel_pos);
115  while (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
116    FinalizeBuffer_action();
117#ifdef BUFFER_PROFILING
118    end_BOM_interval(scanner_timer);
119#endif
120    AdvanceToNewBasePosn(buffer_rel_pos);
121    rel_EOF_pos = lex->AdvanceBuffer(AbsPos());
122    buffer_rel_pos = bitstream_scan0(buf.item_stream[item]);
123  }
124}
125#endif
126
127
128#ifdef OPTIMIZE_SHORT_SCAN
129inline void ParsingEngine::ScanTo(int item) {
130  SIMD_type * stream = buf.item_stream[item];
131  unsigned long * bitstream_ptr = (unsigned long *) (((intptr_t) stream) + buffer_rel_pos/8);
132  unsigned long bitstream_slice = *bitstream_ptr >> buffer_rel_pos % 8;
133  if (bitstream_slice != 0) {
134    buffer_rel_pos += __builtin_ctzl(bitstream_slice);
135  }
136  else {
137    buffer_rel_pos = (buffer_rel_pos & -8) + 8*sizeof(unsigned long);
138    buffer_rel_pos += bitstream_scan0((SIMD_type *) &bitstream_ptr[1]);
139    while (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
140      buffer_rel_pos = BUFFER_BLOCKS * BLOCKSIZE;
141      FinalizeBuffer_action();
142#ifdef BUFFER_PROFILING
143      end_BOM_interval(scanner_timer);
144#endif
145      AdvanceToNewBasePosn(buffer_rel_pos);
146      rel_EOF_pos = lex->AdvanceBuffer(AbsPos());
147      buffer_rel_pos = bitstream_scan0(buf.item_stream[item]);
148    }
149  }
150}
151#endif
152
153
154
155inline bool ParsingEngine::AtChar(unsigned char c) const {
156  return *(x8dataPtr(0)) == c;
157}
158
159inline bool ParsingEngine::S_at(int offset) const {
160  // true for 0x09, 0x0A, 0x0D, 0x20: the XML1.0 space chars.
161  return *(x8dataPtr(offset)) <= 0x20;
162}
163
164#include "multiliteral.h"
165/* Now the XML recognizers. */
166
167inline bool ParsingEngine::at_EndTag_Start() const {
168  return s2int16(x8dataPtr(0)) == c2int16('<', '/');
169}
170
171inline bool ParsingEngine::at_Comment_Start() const {
172  return s4int32(x8dataPtr(0)) == c4int32('<', '!', '-', '-');
173}
174
175inline bool ParsingEngine::at_DoubleHyphen() const {
176  return s2int16(x8dataPtr(0)) == c2int16('-', '-');
177}
178
179inline bool ParsingEngine::at_Comment_End() const {
180  return s3int32(x8dataPtr(0)) == c3int32('-', '-', '>');
181}
182
183inline bool ParsingEngine::at_CDATA_Start() const {
184  return s8int64(x8dataPtr(0)) == 
185         c8int64('<', '!', '[', 'C', 'D', 'A', 'T', 'A');
186}
187
188inline bool ParsingEngine::at_CDATA_End() const {
189  return s3int32(x8dataPtr(0)) == c3int32(']', ']', '>');
190}
191
192inline bool ParsingEngine::at_PI_Start() const {
193  return s2int16(x8dataPtr(0)) == c2int16('<', '?');
194}
195
196inline bool ParsingEngine::at_PI_End() const {
197  return s2int16(x8dataPtr(0)) == c2int16('?', '>');
198}
199
200inline bool ParsingEngine::at_EqualsDQuote() const {
201  return s2int16(x8dataPtr(0)) == c2int16('=', '"');
202}
203
204inline bool ParsingEngine::at_EqualsSQuote() const {
205  return s2int16(x8dataPtr(0)) == c2int16('=', '\'');
206}
207
208inline bool ParsingEngine::at_xmlns() const {
209  return s5int64(x8dataPtr(0)) == c5int64('x', 'm', 'l', 'n', 's'); 
210}
211
212inline bool ParsingEngine::at_EmptyElementDelim() const {
213  return s2int16(x8dataPtr(0)) == c2int16('/', '>');
214}
215
216inline bool ParsingEngine::at_XmlDecl_start() const {
217  return (s5int64(x8dataPtr(0)) == c5int64('<', '?', 'x', 'm', 'l')) &&
218         S_at(5);
219}
220
221inline bool ParsingEngine::at_version() const {
222  return s7int64(x8dataPtr(0)) == c7int64('v', 'e', 'r', 's', 'i', 'o', 'n');
223}
224
225inline bool ParsingEngine::at_1_0() const {
226  return (s5int64(x8dataPtr(0)) == c5int64('"', '1', '.', '0', '"')) ||
227         (s5int64(x8dataPtr(0)) == c5int64('\'', '1', '.', '0', '\''));
228}
229
230inline bool ParsingEngine::at_1_1() const {
231  return (s5int64(x8dataPtr(0)) == c5int64('"', '1', '.', '1', '"')) ||
232         (s5int64(x8dataPtr(0)) == c5int64('\'', '1', '.', '1', '\''));
233}
234
235inline bool ParsingEngine::at_encoding() const {
236  return s8int64(x8dataPtr(0)) == c8int64('e', 'n', 'c', 'o', 'd', 'i', 'n', 'g');
237}
238
239inline bool ParsingEngine::at_standalone() const {
240  return (s8int64(x8dataPtr(0)) == c8int64('s', 't', 'a', 'n', 'd', 'a', 'l', 'o')) &
241         (s2int16(x8dataPtr(8)) == c2int16('n', 'e'));
242}
243
244inline bool ParsingEngine::at_yes() const {
245  return (s5int64(x8dataPtr(0)) == c5int64('"', 'y', 'e', 's', '"')) |
246         (s5int64(x8dataPtr(0)) == c5int64('\'', 'y', 'e', 's', '\''));
247}
248
249inline bool ParsingEngine::at_no() const {
250  return (s4int32(x8dataPtr(0)) == c4int32('"', 'n', 'o', '"')) |
251         (s4int32(x8dataPtr(0)) == c4int32('\'', 'n', 'o', '\''));
252}
253
254
255
256
257
258/* The at_ElementTag_Start recognizer rules out '<!', '<?', '</'
259   combinations while returning true for '<' followed by any NameStrt
260   character. */
261inline bool ParsingEngine::at_ElementTag_Start() const {
262 
263  return (*(x8dataPtr(0)) == '<') &
264         ((*(x8dataPtr(1)) & 0xE1) != 0x21);
265}
266
267/* Parse a markup item beginning '<' */
268inline void ParsingEngine::Parse_Markup () {
269        int markup_start = AbsPos();
270        if (at_ElementTag_Start()) {
271                Parse_StartTag();
272        }
273        else if (at_EndTag_Start()) {
274                Parse_EndTag();
275        }
276        else if (at_Comment_Start()) {
277                Parse_Comment();
278        }
279        else if (at_CDATA_Start()) {
280                Parse_CDATA();
281        }
282        else if (at_PI_Start()) {
283                Parse_PI();
284        }
285        else {
286                Advance(1);
287                Error_action(markup_start, AbsPos());
288        }
289}
290
291/* Parse a comment beginning "<!--" */
292inline void ParsingEngine::Parse_Comment () {
293        int markup_start = AbsPos();
294        Advance(4); /* Skip "<!--". */
295        ScanTo(Hyphen);
296        while (!at_DoubleHyphen()) {
297                Advance(2); /* Skip hyphen-nonhyphen pair */
298                ScanTo(Hyphen); 
299        }
300        if (at_Comment_End()) {
301                Advance(3); /* Skip "-->". */
302                Comment_action(markup_start, AbsPos());
303        }
304        else {
305                Advance(2);  /* "--" */
306                Error_action(markup_start, AbsPos());
307        }
308}
309
310/* Parse an end tag beginning "</" */
311inline void ParsingEngine::Parse_EndTag () {
312        int markup_start = AbsPos();
313#ifndef OMIT_ADVANCE_PRIOR_TO_EXCLUSIVE_SCAN
314        Advance(2); /* Skip "</". */
315#endif
316        ScanTo(NameFollow);
317        if (AtChar('>')) {
318                Advance(1);
319                EndTag_action(markup_start, AbsPos());
320        }
321        else {
322                ScanTo(NonWS);
323                if (AtChar('>')) {
324                        Advance(1);
325                        EndTag_action(markup_start, AbsPos());
326                }
327                else Error_action(markup_start, AbsPos());
328        }
329}
330
331/* Parse a CDATA section beginning "<![CDATA". */
332inline void ParsingEngine::Parse_CDATA () {
333        int markup_start = AbsPos();
334        Advance(8); /* Skip "<![CDATA". */
335        if (!AtChar('[')) {
336                Error_action(markup_start, AbsPos());
337        }
338        else {
339                ScanTo(CD_End_check);
340                while (!at_CDATA_End()) {
341                        Advance(1);
342                        ScanTo(CD_End_check);
343                }
344                Advance(3); /* Skip "]]>". */
345                CDATA_action(markup_start, AbsPos());
346        }
347}
348
349inline void ParsingEngine::Parse_Reference () {
350        int markup_start = AbsPos();
351        /* Advance(1);  // skip "&" */
352        ScanTo(NameFollow);  /* Name delimiter */
353        if (!AtChar(';')) {
354                Error_action(markup_start, AbsPos());
355        }
356        else {
357                Advance(1);
358                Reference_action(markup_start, AbsPos());
359        }
360}
361
362inline void ParsingEngine::Parse_PI () {
363        int markup_start = AbsPos();
364        Advance(2); /* Skip "<?". */
365        int target_start = AbsPos();
366        ScanTo(NameFollow);  /* Name delimiter */
367        // Check for illegal [Xx][Mm][Ll] target.
368        if ((AbsPos() - markup_start == 5) &&
369            ((s3int32(x8dataPtr(-3)) | c3int32(0x20, 0x20, 0x20)) == c3int32('x', 'm', 'l'))) {
370                Error_action(markup_start, AbsPos());
371                return;
372        } 
373        PI_Target_action(target_start, AbsPos());
374        ScanTo(QMark);
375        while (!at_PI_End()) {
376                Advance(1);
377                ScanTo(QMark);
378        }
379        Advance(2); /* Skip "?>". */
380        PI_action(markup_start, AbsPos());
381}
382 
383/* Parse a start or empty element tag. */
384inline void ParsingEngine::Parse_StartTag () {
385        int markup_start = AbsPos();
386        int att_name_start;
387        int att_val_start;
388        int att_name_end, att_val_end;
389        lexical_item Quote_stream;
390        ScanTo(NameFollow);  /* Name delimiter: WS, "/" or ">" */
391        ElementName_action(markup_start+1, AbsPos());
392        /* The following test optimizes the most common case of a
393        start tag with no attributes.  */
394        if (AtChar('>')) {
395                Advance(1);
396                StartTag_action(markup_start, AbsPos());
397        }
398        else {
399                ScanTo(NonWS);
400                if (AtChar('>')) {
401                        Advance(1);
402                        StartTag_action(markup_start, AbsPos());
403                }
404                else if (at_EmptyElementDelim()) {
405                        Advance(2);
406                        EmptyElement_action(markup_start, AbsPos());
407                }
408                else do {
409                        /* Must be an attribute-value pair or error. */
410                        att_name_start = AbsPos();
411                        ScanTo(NameFollow);
412                        att_name_end = AbsPos();
413                        /* The following optimized tests handle the frequently occurring
414                        case that there are no blanks on either side of the equals sign.
415                        In many cases, the very first test handles 100% of actual
416                        attribute-value pairs encountered. */
417                        if (at_EqualsDQuote()) {
418                                Advance(2); 
419                                att_val_start = AbsPos();
420                                Quote_stream = DQuote;
421                        }
422                        else if (at_EqualsSQuote()) {
423                                Advance(2); 
424                                att_val_start = AbsPos();
425                                Quote_stream = SQuote;
426                        }
427                        else {
428                                ScanTo(NonWS);
429                                if (!AtChar('=')) {
430                                        Error_action(markup_start, AbsPos()); 
431                                        break;
432                                }
433                                ScanTo(NonWS);
434                                att_val_start = AbsPos()+1;
435                                if (AtChar('"')) {
436                                        Advance(1); 
437                                        Quote_stream = DQuote;
438                                }
439                                else if (AtChar('\'')) {
440                                        Advance(1); 
441                                        Quote_stream = SQuote;
442                                }
443                                else {
444                                        Error_action(markup_start, AbsPos()); 
445                                        break;
446                                }
447                        }
448                        ScanTo(Quote_stream);
449                        while (AtChar('&')) {
450                                Parse_Reference();
451                                ScanTo(Quote_stream);
452                        }
453                        if (AtChar('<')) {
454                                Error_action(markup_start, AbsPos()); 
455                                break;
456                        }
457                        att_val_end = AbsPos();
458                        Advance(1); 
459                        if (at_xmlns()) {
460                                Namespace_action(att_name_start, att_name_end,
461                                                 att_val_start, att_val_end);
462                        }
463                        else {
464                                AttributeValue_action(att_name_start, att_name_end,
465                                                      att_val_start, att_val_end);
466                        }
467                        /* Now check for end or repeat. Avoid whitespace scan if possible.*/
468                        if (AtChar('>')) {
469                                Advance(1);
470                                StartTag_action(markup_start, AbsPos());
471                                break;
472                        }
473                        else if (at_EmptyElementDelim()) {
474                                Advance(2);
475                                EmptyElement_action(markup_start, AbsPos());
476                                break;
477                        }
478                        ScanTo(NonWS);
479                        if (AtChar('>')) {
480                                Advance(1);
481                                StartTag_action(markup_start, AbsPos());
482                                break;
483                        }
484                        else if (at_EmptyElementDelim()) {
485                                Advance(2);
486                                EmptyElement_action(markup_start, AbsPos());
487                                break;
488                        }
489                        else if (AbsPos() == att_val_end + 1) { 
490                                /* No WS following att value */
491                                Error_action(markup_start, AbsPos());
492                                break;
493                        }
494                } while (1);
495        }
496}
497
498
499inline void ParsingEngine::ParseContent () {
500
501        int text_start = AbsPos();
502        do {
503                ScanTo(MarkupStart); /* '<', '&', or ']' for ']]>' test */
504/*              if (AtChar('<')) {
505                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
506                        Parse_Markup();
507                }*/
508                int markup_start = AbsPos();
509                if (at_ElementTag_Start()) {
510                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
511                        Parse_StartTag();
512                }
513                else if (at_EndTag_Start()) {
514                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
515                        Parse_EndTag();
516                }
517                else if (at_Comment_Start()) {
518                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
519                        Parse_Comment();
520                }
521                else if (AtChar('&')) {
522                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
523                        Parse_Reference();
524                }
525                else if (at_CDATA_Start()) {
526                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
527                        Parse_CDATA();
528                }
529                else if (at_PI_Start()) {
530                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
531                        Parse_PI();
532                }
533                else if (at_CDATA_End()) {
534                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
535                        Advance(3);
536                        Error_action(AbsPos()-3, AbsPos());
537                }
538                else if (at_EOF()) {
539                        if (AbsPos() > text_start) Text_action(text_start, AbsPos());
540                        break;
541                }
542                else {
543                        Advance(1);
544                        continue;
545                }
546                text_start = AbsPos();
547        } while (1);
548#ifdef BUFFER_PROFILING
549        printf("Bit stream computation.\n");
550        dump_BOM_table(bitstream_timer);
551        printf("Lexical stream transposition.\n");
552        dump_BOM_table(lextranspose_timer);
553        printf("Scanning.\n");
554        dump_BOM_table(scanner_timer);
555#endif
556}
557
558//
559// The following does not yet validate the syntax of EncNames.
560// EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
561// Future approach: first use lookup in EncNameTable,
562//           if not found, do case convert, try again,
563//             (avoids cost of case convert normally)
564//           if not found, validate syntax of EncNames,
565//           report error or EncName unknown.
566//
567void ParsingEngine::ReadXmlInfo(Entity_Declaration_Info& xml_info) {
568  int BOM = lex->BOM_size(0);
569  xml_info.has_ByteOrderMark = BOM > 0;
570  xml_info.has_version_decl = false;
571  xml_info.has_encoding_decl = false;
572  xml_info.has_standalone_decl = false;
573  Advance(BOM);
574  int decl_start = AbsPos();
575  // It is possible that there is no XML declaration.
576  if (!at_XmlDecl_start()) return;
577  // Otherwise, the XML declaration exists and must have
578  // at least version information.
579  xml_info.has_version_decl = true;
580  Advance(6);
581  ScanTo(NonWS);
582  if (!at_version()) {Error_action(decl_start, AbsPos()); return;}
583  Advance(7);
584  ScanTo(NonWS);
585  if (!AtChar('=')) {Error_action(decl_start, AbsPos()); return;}
586  Advance(1);
587  ScanTo(NonWS);
588  if (at_1_0()) xml_info.version = 0;
589  else if (at_1_1()) xml_info.version = 1;
590  else {Error_action(decl_start, AbsPos()); return;}
591  Advance(5);
592  if (at_PI_End()) {Advance(2); return;}
593  if (!S_at(0)) {Error_action(decl_start, AbsPos()); return;}
594  ScanTo(NonWS);
595  if (at_encoding()) {
596      xml_info.has_encoding_decl = true;
597      Advance(8);
598      ScanTo(NonWS);
599      if (!AtChar('=')) {Error_action(decl_start, AbsPos()); return;}
600      Advance(1);
601      ScanTo(NonWS);
602      xml_info.encoding_start_pos = AbsPos()+1;
603      if (AtChar('"')) {
604        Advance(1);
605        ScanTo(DQuote);
606        if (!AtChar('"')) {Error_action(decl_start, AbsPos()); return;}
607      }
608      else if (AtChar('\'')) {
609        Advance(1);
610        ScanTo(SQuote);
611        if (!AtChar('\'')) {Error_action(decl_start, AbsPos()); return;}
612      }
613      else {Error_action(decl_start, AbsPos()); return;}
614      xml_info.encoding_end_pos = AbsPos();
615      Advance(1);
616      if (at_PI_End()) {Advance(2); return;}
617      if (!S_at(0)) {Error_action(decl_start, AbsPos()); return;}
618      ScanTo(NonWS);
619  }
620  if (at_standalone()) {
621      xml_info.has_standalone_decl = true;
622      Advance(10);
623      ScanTo(NonWS);
624      if (!AtChar('=')) {Error_action(decl_start, AbsPos()); return;}
625      Advance(1);
626      ScanTo(NonWS);
627      if (at_yes()) {Advance(5); xml_info.standalone = true;}
628      else if (at_no()) {Advance(4); xml_info.standalone = false;}
629      else {Error_action(decl_start, AbsPos()); return;}
630  }
631  ScanTo(NonWS);
632  if (at_PI_End()) {Advance(2); return;}
633  else {Error_action(decl_start, AbsPos()); return;}
634}
635
636// Similar to reading the XML_declaration of the document entity,
637// ReadTextDeclaration reads the text declaration of an external
638// parsed entity.  This is not really needed at present, for DTDless
639// processing.
640void ParsingEngine::ReadTextDeclaration(Entity_Declaration_Info& xml_info) {
641  int BOM = lex->BOM_size(0);
642  xml_info.has_ByteOrderMark = BOM > 0;
643  xml_info.has_version_decl = false;
644  xml_info.has_encoding_decl = false;
645  xml_info.has_standalone_decl = false;
646  Advance(BOM);
647  int decl_start = AbsPos();
648  // It is possible that there is no XML declaration.
649  if (!at_XmlDecl_start()) return;
650  // Otherwise, the text declaration exists and may have
651  // version information.
652  Advance(6);
653  ScanTo(NonWS);
654  if (at_version()) {
655    xml_info.has_version_decl = true;
656    Advance(7);
657    ScanTo(NonWS);
658    if (!AtChar('=')) {Error_action(decl_start, AbsPos()); return;}
659    Advance(1);
660    ScanTo(NonWS);
661    if (at_1_0()) xml_info.version = 0;
662    else if (at_1_1()) xml_info.version = 1;
663    else {Error_action(decl_start, AbsPos()); return;}
664    Advance(5);
665    // Must have whitespace character before declaration.
666    if (!S_at(0)) {Error_action(decl_start, AbsPos()); return;}
667    ScanTo(NonWS);
668  }
669  if (!at_encoding()) {Error_action(decl_start, AbsPos()); return;}
670  xml_info.has_encoding_decl = true;
671  Advance(8);
672  ScanTo(NonWS);
673  if (!AtChar('=')) {Error_action(decl_start, AbsPos()); return;}
674  Advance(1);
675  ScanTo(NonWS);
676  xml_info.encoding_start_pos = AbsPos()+1;
677  if (AtChar('"')) {
678      Advance(1);
679      ScanTo(DQuote);
680      if (!AtChar('"')) {Error_action(decl_start, AbsPos()); return;}
681  }
682  else if (AtChar('\'')) {
683      Advance(1);
684      ScanTo(SQuote);
685      if (!AtChar('\'')) {Error_action(decl_start, AbsPos()); return;}
686  }
687  else {Error_action(decl_start, AbsPos()); return;}
688  xml_info.encoding_end_pos = AbsPos();
689  Advance(1);
690  ScanTo(NonWS);
691  if (at_PI_End()) {Advance(2); return;}
692  else {Error_action(decl_start, AbsPos()); return;}
693}
Note: See TracBrowser for help on using the repository browser.