source: trunk/src/engine.c @ 15

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

Bytespace scanning in XML declarations; various updates

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