source: trunk/src/engine.c @ 17

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

Initiating ASCII/EBCDIC selection using templates

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