source: trunk/src/engine.c @ 12

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

Text declarations for external parsed entities.

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