source: trunk/src/engine.c @ 125

Last change on this file since 125 was 125, checked in by lindanl, 11 years ago

Character references: calculation and error detection.

File size: 57.6 KB
Line 
1/*  engine.c - Parabix XML parsing engine.
2    Copyright (c) 2007, 2008, Robert D. Cameron and Dan Lin.
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 "engine.h"
9#include "byteplex.h"
10#include "xmldecl.h"
11#include "bytelex.h"
12#include "bitlex.h"
13#include "contentmodel.h"
14#include "contentmodel.c"
15#include "xml_error.h"
16
17#include <assert.h>
18#include <stdlib.h>
19#include <errno.h>
20#include <string.h>
21#include <string>
22#include <iostream>
23using namespace std;
24       
25inline char * copy_string (unsigned char * s, int lgth){               
26        char * d = new char[lgth+1];
27        memcpy(d, (char *)s,lgth); 
28        d[lgth] = '\0'; 
29        return d;
30}
31
32inline char * cat_string (char * s1, char * s2, int lgth1, int lgth2){
33        char * s = new char[lgth1 + lgth2 + 1];
34        memcpy(s, s1,lgth1);
35//      s[lgth1] = '\0';       
36//      strncat(s, s2, lgth2); 
37        memcpy(&s[lgth1],s2,lgth2);
38        s[lgth1 + lgth2] = '\0';
39        return s;
40}
41       
42       
43       
44Parser_Interface * Parser_Interface::ParserFactory(char * filename) {
45       
46        int chars_read;
47        unsigned char signature[4];
48        FILE * infile;
49        infile = fopen(filename, "rb");
50        if (!infile) {
51                fprintf(stderr, "Error: cannot open %s for input.\n", filename);
52                exit(-1);
53        }
54        fread(signature,1,4,infile);
55        Entity_Info * e = new Entity_Info;
56        Model_Info * m = new Model_Info;
57        e->AnalyzeSignature(signature);
58        Byteplex * b = Byteplex::ByteplexFactory(e, infile);
59        b->InitializeBuffer(signature,4);
60
61        if (e->code_unit_base == ASCII) {
62                return new ParsingEngine<ASCII>(e, m, b, false);
63        }
64        else /* if (e->code_unit_base == EBCDIC) */ {
65                return new ParsingEngine<EBCDIC>(e, m, b, false);
66        }       
67}
68
69Parser_Interface * Parser_Interface::ParserFactory(char * filename, Model_Info * m) {
70       
71        int chars_read;
72        unsigned char signature[4];
73        FILE * infile;
74        infile = fopen(filename, "rb");
75        if (!infile) {
76                fprintf(stderr, "Error: cannot open %s for input.\n", filename);
77                exit(-1);
78        }
79        fread(signature,1,4,infile);
80        Entity_Info * e = new Entity_Info;
81        e->AnalyzeSignature(signature);
82        Byteplex * b = Byteplex::ByteplexFactory(e, infile);
83        b->InitializeBuffer(signature,4);
84
85        if (e->code_unit_base == ASCII) {
86                return new ParsingEngine<ASCII>(e, m, b, true);
87        }
88        else /* if (e->code_unit_base == EBCDIC) */ {
89                return new ParsingEngine<EBCDIC>(e, m, b, true);
90        }       
91}
92
93Parser_Interface * Parser_Interface::ParserFactory(char * byte_buffer, int byte_count, Entity_Info * e, Model_Info * m){
94        Byteplex * b = Byteplex::ByteplexFactory(e, (unsigned char *) byte_buffer, byte_count);
95        if (e->code_unit_base == ASCII) {
96                return new ParsingEngine<ASCII>(e, m, b, false);
97        }
98        else {
99                return new ParsingEngine<EBCDIC>(e, m, b, false);
100        }       
101}
102
103Parser_Interface::~Parser_Interface() {
104}
105
106
107bool Parser_Interface::has_ByteOrderMark() {
108        return entity_Info->BOM_units > 0;
109}
110
111XML_version Parser_Interface::get_version() {
112        return entity_Info->version;
113}
114
115XML_standalone Parser_Interface::standalone_status() {
116        return entity_Info->standalone;
117}
118
119bool Parser_Interface::has_EncodingDecl() {
120        return entity_Info->has_encoding_decl;
121}
122
123unsigned char * Parser_Interface::get_Encoding() {
124        return entity_Info->encoding;
125}
126
127unsigned char * Parser_Interface::GetCodeUnitPtr(int pos) {
128        int rel_pos = pos - buffer_base_pos;
129        return &((unsigned char *) (byteplex->src_buffer))[rel_pos * (int) entity_Info->code_unit_size];
130}
131
132
133
134
135template <CodeUnit_Base C>
136ParsingEngine<C>::ParsingEngine(Entity_Info * e, Model_Info * m, Byteplex * b, bool is_external) : Parser_Interface () {
137        entity_Info = e;
138        model_info = m;
139        byteplex = b;
140
141        byteplex->DoByteplex();
142        byteplex->PreparePseudoASCII_Stream();
143         StrictWellFormedness=false;
144        LastAttOccurrence.assign(m->globalAttributeCount+1, 0);
145//      LastAttOccurrence.push_back(0);
146       
147        decl_parser = new XML_Decl_Parser<C>(byteplex);
148        int content_start = 0;
149        if(is_external == true)
150                content_start = decl_parser->ReadTextDeclaration(entity_Info);
151        else
152                content_start = decl_parser->ReadXMLInfo(entity_Info);
153       
154        bitplex = new Bitplex;
155        buf = (LexicalStreamSet *) simd_new(sizeof(LexicalStreamSet)/PACKSIZE);
156
157  /* Install sentinels for every lexical item stream*/
158#ifndef OPTIMIZE_SHORT_SCAN
159        BitBlock sentinel_value = simd_const_1(1);
160#endif
161#ifdef OPTIMIZE_SHORT_SCAN
162        BitBlock sentinel_value = sisd_sfli(simd_const_1(1), 8*sizeof(unsigned long));
163#endif
164        for (int j = minLexicalItem; j < LexicalItemCount; j++) {
165                buf->item_stream[j][BUFFER_BLOCKS] = sentinel_value;
166        }
167
168        buffer_base_pos = 0;
169        buffer_rel_pos = content_start;
170        buffer_limit_pos = min(BUFFER_SIZE, byteplex->units_in_buffer);
171        int blocks_in_buffer = (buffer_limit_pos + BLOCKSIZE - 1)/BLOCKSIZE;
172        x8data = byteplex->x8data;
173        lexer = Lexer<C>::LexerFactory(e, buf);
174        bitplex->TransposeToBitStreams(byteplex->x8data, blocks_in_buffer);
175        lexer->AnalyzeBuffer(bitplex->x8basis, buffer_limit_pos);
176}
177
178template <CodeUnit_Base C>
179ParsingEngine<C>::~ParsingEngine() {
180  // How do we do this?  model_info->~Model_Info();
181  entity_Info->~Entity_Info();
182  byteplex->~Byteplex();
183  decl_parser->~XML_Decl_Parser<C>();
184  bitplex->~Bitplex();
185  simd_delete((SIMD_type *) buf);
186  lexer->~Lexer_Interface();
187}
188
189template <CodeUnit_Base C>
190inline void ParsingEngine<C>::AdvanceBuffers(int preserve_pos){
191        int advance_amt = min(preserve_pos, text_or_markup_start) - buffer_base_pos;
192        advance_amt &= -PACKSIZE; // maintain alignment
193        byteplex->AdvanceInputBuffer(advance_amt);
194        buffer_base_pos += advance_amt;
195        buffer_rel_pos -= advance_amt;
196        buffer_limit_pos = min(BUFFER_SIZE, byteplex->units_in_buffer);
197        int blocks_in_buffer = (buffer_limit_pos + BLOCKSIZE - 1)/BLOCKSIZE;
198        byteplex->DoByteplex();
199        byteplex->PreparePseudoASCII_Stream();
200        bitplex->TransposeToBitStreams(byteplex->x8data, blocks_in_buffer);
201        lexer->AnalyzeBuffer(bitplex->x8basis, buffer_limit_pos);
202}
203
204template <CodeUnit_Base C>
205inline unsigned char * ParsingEngine<C>::cur() const {
206  return &((unsigned char *) x8data)[buffer_rel_pos];
207}
208
209template <CodeUnit_Base C>
210inline int ParsingEngine<C>::AbsPos() const {
211  return buffer_base_pos + buffer_rel_pos;
212}
213
214template <CodeUnit_Base C>
215inline int ParsingEngine<C>::LengthFrom(int start_pos) const {
216  return buffer_base_pos + buffer_rel_pos - start_pos;
217}
218
219
220
221template <CodeUnit_Base C>
222inline int ParsingEngine<C>::BufferRelPos() const {
223  return buffer_rel_pos;
224}
225
226
227template <CodeUnit_Base C>
228inline bool ParsingEngine<C>::at_EOF() const {
229  return (buffer_rel_pos >= buffer_limit_pos) && 
230         (buffer_limit_pos < BUFFER_SIZE);
231}
232
233template <CodeUnit_Base C>
234inline void ParsingEngine<C>::Advance(int n) {
235        int preserve_pos;
236        buffer_rel_pos += n;
237#ifndef OMIT_BITBUFFER_LIMIT_TEST_IN_ADVANCE
238  if (buffer_rel_pos >= BUFFER_SIZE) {
239        FinalizeBuffer_action(preserve_pos);
240        AdvanceBuffers(preserve_pos);
241  }
242#endif
243}
244
245
246#ifndef OPTIMIZE_SHORT_SCAN
247template <CodeUnit_Base C>
248inline void ParsingEngine<C>::ScanTo(int item) {
249        int preserve_pos;
250  buffer_rel_pos = bitstream_scan(buf->item_stream[item], 
251                                      buffer_rel_pos);
252  while (buffer_rel_pos >= BUFFER_SIZE) {
253        FinalizeBuffer_action(preserve_pos);
254        AdvanceBuffers(preserve_pos);
255        buffer_rel_pos = bitstream_scan(buf->item_stream[item], buffer_rel_pos);
256  }
257}
258#endif
259
260template <CodeUnit_Base C>
261inline void ParsingEngine<C>::ScanToMarkupStart() {
262        int preserve_pos;
263        text_or_markup_start = AbsPos();
264        buffer_rel_pos = bitstream_scan(buf->item_stream[MarkupStart], buffer_rel_pos);
265        while (buffer_rel_pos >= BUFFER_SIZE) {
266                Text_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
267                text_or_markup_start = AbsPos();
268                FinalizeBuffer_action(preserve_pos);
269                AdvanceBuffers(preserve_pos);
270                buffer_rel_pos = bitstream_scan(buf->item_stream[MarkupStart], buffer_rel_pos);
271        }
272}
273
274template <CodeUnit_Base C>
275inline void ParsingEngine<C>::ScanToCD_End_check() {
276        int preserve_pos;
277        buffer_rel_pos = bitstream_scan(buf->item_stream[CD_End_check], buffer_rel_pos);
278        while (buffer_rel_pos >= BUFFER_SIZE) {
279                Text_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
280                text_or_markup_start = AbsPos();
281                FinalizeBuffer_action(preserve_pos);
282                AdvanceBuffers(preserve_pos);
283                buffer_rel_pos = bitstream_scan(buf->item_stream[CD_End_check], buffer_rel_pos);
284        }
285}
286
287#ifdef OPTIMIZE_SHORT_SCAN
288template <CodeUnit_Base C>
289inline void ParsingEngine<C>::ScanTo(int item) {
290  SIMD_type * stream = buf->item_stream[item];
291  unsigned long * bitstream_ptr = (unsigned long *) (((intptr_t) stream) + buffer_rel_pos/8);
292  unsigned long bitstream_slice = *bitstream_ptr >> buffer_rel_pos % 8;
293  if (bitstream_slice != 0) {
294    buffer_rel_pos += __builtin_ctzl(bitstream_slice);
295  }
296  else {
297    buffer_rel_pos = (buffer_rel_pos & -8) + 8*sizeof(unsigned long);
298    buffer_rel_pos += bitstream_scan0((SIMD_type *) &bitstream_ptr[1]);
299    while (buffer_rel_pos >= BUFFER_BLOCKS * BLOCKSIZE) {
300      buffer_rel_pos = BUFFER_BLOCKS * BLOCKSIZE;
301      FinalizeBuffer_action(preserve_pos);
302          AdvanceBuffers(preserve_pos);
303      buffer_rel_pos = bitstream_scan(buf->item_stream[item], buffer_rel_pos);
304    }
305  }
306}
307#endif
308
309template <CodeUnit_Base C>
310inline void ParsingEngine<C>::WF_Error (XML_Constraint errCode) {
311        ShowConstraintError(errCode);
312        exit(-1);
313//      Error_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
314}
315       
316
317template <CodeUnit_Base C>
318inline void ParsingEngine<C>::Validity_Error (XML_Constraint errCode) {
319        ShowConstraintError(errCode);
320        Error_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
321}
322       
323template <CodeUnit_Base C>
324inline void ParsingEngine<C>::Syntax_Error (XML_NonTerminal errNT) {
325        ShowSyntaxError(errNT);
326        exit(-1);
327//      Error_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
328}
329       
330
331/* Parse a comment beginning "<!--" */
332template <CodeUnit_Base C>
333inline void ParsingEngine<C>::Parse_Comment() {
334
335        Advance(4); /* Skip "<!--". */
336        ScanTo(Hyphen);
337        while (!at_DoubleHyphen<C>(cur())) {
338                if(at_EOF())
339                        Syntax_Error(NT_CDSect);
340                Advance(2); /* Skip hyphen-nonhyphen pair */
341                ScanTo(Hyphen); 
342        }
343        if (at_Comment_End<C>(cur())) {
344                Advance(3); /* Skip "-->". */
345                Comment_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
346        }
347        else {
348                Advance(2);  /* "--" */
349                Syntax_Error(NT_Comment);
350        }
351}
352
353/* Parse an end tag beginning "</" */
354template <CodeUnit_Base C>
355inline void ParsingEngine<C>::Parse_EndTag() {
356        Advance(2); /* Skip "</". */
357        int nameID = Parse_Name();
358        if (AtChar<C,'>'>(cur())) {
359                Advance(1);
360                EndTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
361        }
362        else {
363                ScanTo(NonWS);
364                if (AtChar<C,'>'>(cur())) {
365                        Advance(1);
366                        EndTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
367                }
368                else Syntax_Error(NT_ETag);
369        }
370}
371
372/* Parse a CDATA section beginning "<![CDATA". */
373template <CodeUnit_Base C>
374inline void ParsingEngine<C>::Parse_CDATA() {
375        Advance(8); /* Skip "<![CDATA". */
376        if (!AtChar<C,'['>(cur())) {
377                Syntax_Error(NT_CDStart);
378        }
379        else { 
380                Advance(1);
381                CDATA_start_action(GetCodeUnitPtr(text_or_markup_start));
382                text_or_markup_start = AbsPos();
383                ScanTo(CD_End_check);
384                while (!at_CDATA_End<C>(cur())) {
385                        if(at_EOF())
386                                Syntax_Error(NT_CDSect);
387                        Advance(1);
388                        ScanTo(CD_End_check);
389                }
390                Text_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
391                Advance(3); /* Skip "]]>". */
392                CDATA_end_action(GetCodeUnitPtr(AbsPos()));
393        }
394}
395
396template <CodeUnit_Base C>
397inline void ParsingEngine<C>::Parse_EntityRef() {
398    Advance(1);  // skip "&"
399    int ref_start = AbsPos();
400        int nameID = Parse_Name();  /* Name delimiter */
401    if (!AtChar<C,';'>(cur())) {
402                Syntax_Error(NT_Reference);
403    }
404        else {
405                int lgth = AbsPos()-ref_start;
406                char * s = new char[lgth+1];
407                memcpy(s, GetCodeUnitPtr(ref_start),lgth); 
408                s[lgth] = '\0';
409               
410                Advance(1);
411                Reference_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
412               
413                //      The following code will replace Reference_Action.
414                GEntity_info * this_info;
415                Parser_Interface * entity_parser;
416                int entityID = model_info->GlobalGEntityTable[s]; 
417                if (entityID == 0)
418                        WF_Error(wfErr_wf_entdeclared);
419                else{
420                        this_info = model_info->GEntityData[entityID-1];
421                        if (this_info->is_external){
422                               
423                        if (entity_Info->standalone != Standalone_no)
424                                WF_Error(wfErr_NoExternalRefs);
425                        else {
426                                        entity_parser = ParserFactory(this_info->systemLiteral, model_info);
427                                        entity_parser->Parse_WF_Content();
428                                        if(!entity_parser->at_EOF())
429                                                Syntax_Error(NT_content);
430                                        entity_parser->~Parser_Interface();
431                        }
432                        }
433                        else {
434                                if (this_info->is_simple == true);
435//                                      printf("Entity is %s\n",this_info->ReplacementText);
436                                else{
437//                                      printf("Not a simple text: %s\n",this_info->ReplacementText);
438                                        entity_parser = ParserFactory(this_info->ReplacementText, strlen(this_info->ReplacementText),entity_Info, model_info);
439                                        entity_parser->Parse_WF_Content();
440                                        if(!entity_parser->at_EOF())
441                                                Syntax_Error(NT_content);
442                                        entity_parser->~Parser_Interface();
443                                }
444                        }
445                }
446               
447        }
448}
449       
450template <CodeUnit_Base C>
451inline void ParsingEngine<C>::Parse_CharRef() {
452        Advance(2);  // skip "&#"
453        int ch_val = 0;
454        if (AtChar<C,'x'>(cur())) {
455                Advance(1);
456                while(at_HexDigit<C>(cur())){
457                        ch_val = HexVal<C>(cur()[0]) + (ch_val<<4);
458                        if (ch_val> 0x10FFFF )
459                                WF_Error(wfErr_wf_Legalchar);
460                        Advance(1);
461                }
462        }
463        else {
464                while(at_Digit<C>(cur())){
465                        ch_val = DigitVal<C>(cur()[0]) + ch_val*10;
466                        if (ch_val> 0x10FFFF )
467                                WF_Error(wfErr_wf_Legalchar);
468                        Advance(1);
469                }
470        }
471        if ((ch_val == 0x0) || ((ch_val | 0x7FF) == 0xDFFF)|| ((ch_val | 0x1) == 0xFFFF))
472                                WF_Error(wfErr_wf_Legalchar);   
473                else  if (entity_Info->version != XML_1_1)
474                        if (((ch_val < 0x20) && (ch_val != 0x9) && (ch_val != 0xD) && (ch_val != 0xA)))
475                                WF_Error(wfErr_wf_Legalchar); 
476                               
477        if (!AtChar<C,';'>(cur())) {
478                        Syntax_Error(NT_CharRef);
479        }
480                else {
481                        Advance(1);
482                        Reference_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
483                }
484}
485
486template <CodeUnit_Base C>
487inline void ParsingEngine<C>::Parse_PI (){
488        int nameID;
489        Advance(2); /* Skip "<?". */
490        int target_start = AbsPos();
491        if (at_XxMmLll<C>(cur())) {
492                nameID = Parse_Name();
493                if (AbsPos() - target_start == 3) Syntax_Error(NT_PI);
494        }
495        else nameID = Parse_Name();
496        PI_Target_action(GetCodeUnitPtr(target_start), LengthFrom(target_start));
497        if (!at_PI_End<C>(cur())) requireWS();
498        ScanTo(QMark);
499        while (!at_PI_End<C>(cur())) {
500                if(at_EOF())
501                        Syntax_Error(NT_PI);
502                Advance(1);
503                ScanTo(QMark);
504        }
505        Advance(2); /* Skip "?>". */
506        PI_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
507}
508 
509/* Parse a start or empty element tag. */
510template <CodeUnit_Base C>
511inline void ParsingEngine<C>::Parse_StartTag (){
512        int att_name_start;
513        int att_val_start;
514        int att_name_end, att_val_end;
515        unsigned char quoteCh;
516        Advance(1);
517        int nameID = Parse_Name();  /* Name delimiter: WS, "/" or ">" */
518        ElementName_action(GetCodeUnitPtr(text_or_markup_start+1), LengthFrom(text_or_markup_start+1));
519        /* The following test optimizes the most common case of a
520        start tag with no attributes.  */
521        if (AtChar<C,'>'>(cur())) {
522                Advance(1);
523                StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
524        }
525        else {
526                ScanTo(NonWS);
527                if (AtChar<C,'>'>(cur())) {
528                        Advance(1);
529                        StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
530                }
531                else if (at_EmptyElementDelim<C>(cur())) {
532                        Advance(2);
533                        EmptyElement_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
534                }
535                else do {
536                        /* Must be an attribute-value pair or error. */
537                        att_name_start = AbsPos();
538                        int nameID = Parse_Name();
539                        att_name_end = AbsPos();
540                        int lgth = att_name_end-att_name_start;
541               
542                        int attID = model_info->getOrInsertGlobalAttName(GetCodeUnitPtr(att_name_start), lgth);
543                        if (attID >= LastAttOccurrence.size()) LastAttOccurrence.push_back(0);
544                        else {
545                                if (LastAttOccurrence[attID] > text_or_markup_start) {
546                                        WF_Error(wfErr_uniqattspec); /* Duplicate attribute. */
547                                        break;
548                                }                       
549                        }
550                        LastAttOccurrence[attID] = att_name_start;
551                        /* The following optimized tests handle the frequently occurring
552                        case that there are no blanks on either side of the equals sign.
553                        In many cases, the very first test handles 100% of actual
554                        attribute-value pairs encountered. */
555                        if (at_EqualsQuote<C>(cur())) Advance(1); 
556                        else {
557                                ScanTo(NonWS);
558                                if (!AtChar<C,'='>(cur())) {
559                                        Syntax_Error(NT_STag); 
560                                        break;
561                                }
562                                Advance(1);
563                                ScanTo(NonWS);
564                                if (!AtQuote<C>(cur())) {
565                                        Syntax_Error(NT_STag); 
566                                        break;
567                                }
568                        }
569                        att_val_start = AbsPos()+1;
570                        Parse_AttValue();
571                        att_val_end = AbsPos()-1;
572                        if (at_xmlns<C>(cur()+att_name_start-AbsPos())) {
573                                Namespace_action(GetCodeUnitPtr(att_name_start), att_name_end - att_name_start,
574                                                 GetCodeUnitPtr(att_val_start), att_val_end - att_val_start);
575                        }
576                        else {
577                                AttributeValue_action(GetCodeUnitPtr(att_name_start), att_name_end - att_name_start,
578                                                 GetCodeUnitPtr(att_val_start), att_val_end - att_val_start);
579                        }
580                        /* Now check for end or repeat. Avoid whitespace scan if possible.*/
581                        if (AtChar<C,'>'>(cur())) {
582                                Advance(1);
583                                StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
584                                break;
585                        }
586                        else if (at_EmptyElementDelim<C>(cur())) {
587                                Advance(2);
588                                EmptyElement_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
589                                break;
590                        }
591                        ScanTo(NonWS);
592                        if (AtChar<C,'>'>(cur())) {
593                                Advance(1);
594                                StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
595                                break;
596                        }
597                        else if (at_EmptyElementDelim<C>(cur())) {
598                                Advance(2);
599                                EmptyElement_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
600                                break;
601                        }
602                        else if (AbsPos() == att_val_end + 1) { 
603                                /* No WS following att value */
604                                Syntax_Error(NT_STag);
605                                break;
606                        }
607                } while (1);
608        }
609}
610
611template <CodeUnit_Base C>
612inline void ParsingEngine<C>::text_if_nonnull_action(){
613        if (AbsPos() > text_or_markup_start) {
614                Text_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
615                text_or_markup_start = AbsPos();
616        }
617}
618
619
620
621template <CodeUnit_Base C>
622inline void ParsingEngine<C>::Parse_WF_EndTag(int nameID) {
623        Advance(2); /* Skip "</". */
624       
625        int name_start = AbsPos();
626       
627        int endNameID = Parse_Name();  /* Name delimiter: WS, "/" or ">" */
628        if (nameID != endNameID)
629                        WF_Error(wfErr_GIMatch);
630                       
631        if (AtChar<C,'>'>(cur())) {
632                Advance(1);
633                EndTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
634        }
635    else {
636                ScanTo(NonWS);
637                if (AtChar<C,'>'>(cur())) {
638                        Advance(1);
639                        EndTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
640                }
641                else Syntax_Error(NT_ETag);
642    }
643}
644/* Parse a valid start or empty element tag. */
645template <CodeUnit_Base C>
646inline int ParsingEngine<C>::Parse_WF_StartTag (bool& is_emptyStartTag){
647        int att_name_start;
648        int att_val_start;
649        int att_name_end, att_val_end;
650        unsigned char quoteCh;
651        Advance(1);
652       
653        int nameID = Parse_Name(); 
654       
655        ElementName_action(GetCodeUnitPtr(text_or_markup_start+1), LengthFrom(text_or_markup_start+1));
656        /* The following test optimizes the most common case of a
657        start tag with no attributes.  */
658        if (AtChar<C,'>'>(cur())) {
659                Advance(1);
660                StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
661        }
662        else {
663                ScanTo(NonWS);
664                if (AtChar<C,'>'>(cur())) {
665                        Advance(1);
666                        StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
667                }
668                else if (at_EmptyElementDelim<C>(cur())) {
669                        Advance(2);
670                        is_emptyStartTag = true;
671                        EmptyElement_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
672                }
673                else do {
674                        /* Must be an attribute-value pair or error. */
675                        att_name_start = AbsPos();
676                        int nameID = Parse_Name();
677                        att_name_end = AbsPos();
678                        int lgth = att_name_end-att_name_start;
679               
680                        int attID = model_info->getOrInsertGlobalAttName(GetCodeUnitPtr(att_name_start), lgth);
681                        if (attID >= LastAttOccurrence.size()) LastAttOccurrence.push_back(0);
682                        else {
683                                if (LastAttOccurrence[attID] > text_or_markup_start) {
684                                        WF_Error(wfErr_uniqattspec); /* Duplicate attribute. */
685                                        break;
686                                }                       
687                        }
688                        LastAttOccurrence[attID] = att_name_start;
689                        /* The following optimized tests handle the frequently occurring
690                        case that there are no blanks on either side of the equals sign.
691                        In many cases, the very first test handles 100% of actual
692                        attribute-value pairs encountered. */
693                        if (at_EqualsQuote<C>(cur())) Advance(1); 
694                        else {
695                                ScanTo(NonWS);
696                                if (!AtChar<C,'='>(cur())) {
697                                        Syntax_Error(NT_STag); 
698                                        break;
699                                }
700                                ScanTo(NonWS);
701                                if (!AtQuote<C>(cur())) {
702                                        Syntax_Error(NT_STag); 
703                                        break;
704                                }
705                        }
706                        att_val_start = AbsPos()+1;
707                        Parse_AttValue();
708                        att_val_end = AbsPos()-1;
709                        if (at_xmlns<C>(cur()+att_name_start-AbsPos())) {
710                                Namespace_action(GetCodeUnitPtr(att_name_start), att_name_end - att_name_start,
711                                                 GetCodeUnitPtr(att_val_start), att_val_end - att_val_start);
712                        }
713                        else {
714                                AttributeValue_action(GetCodeUnitPtr(att_name_start), att_name_end - att_name_start,
715                                                 GetCodeUnitPtr(att_val_start), att_val_end - att_val_start);
716                        }
717                        /* Now check for end or repeat. Avoid whitespace scan if possible.*/
718                        if (AtChar<C,'>'>(cur())) {
719                                Advance(1);
720                                StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
721                                break;
722                        }
723                        else if (at_EmptyElementDelim<C>(cur())) {
724                                Advance(2);
725                                is_emptyStartTag = true;       
726                                EmptyElement_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
727                                break;
728                        }
729                        ScanTo(NonWS);
730                        if (AtChar<C,'>'>(cur())) {
731                                Advance(1);
732                                StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
733                                break;
734                        }
735                        else if (at_EmptyElementDelim<C>(cur())) {
736                                Advance(2);
737                                is_emptyStartTag = true;
738                                EmptyElement_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
739                                break;
740                        }
741                        else if (AbsPos() == att_val_end + 1) { 
742                                /* No WS following att value */
743                                Syntax_Error(NT_STag);
744                                break;
745                        }
746                } while (1);
747        }
748        return nameID;
749}
750
751
752
753template <CodeUnit_Base C>
754inline void ParsingEngine<C>::Parse_WF_Element() {
755        bool is_emptyStartTag = false;
756        int nameID = Parse_WF_StartTag(is_emptyStartTag);
757#ifdef DEBUG
758        printf("Parse_Element: elemID = %d, is_emptyStartTag=%i\n",elemID, is_emptyStartTag);
759#endif
760        if (!is_emptyStartTag) {
761                Parse_WF_Content();
762                Parse_WF_EndTag(nameID);
763        }
764}
765
766
767template <CodeUnit_Base C>
768inline void ParsingEngine<C>::Parse_WF_Content() {
769        do {
770                text_or_markup_start = AbsPos();
771                ScanToMarkupStart(); /* '<', '&', or ']' for ']]>' test */
772                if (at_ElementTag_Start<C>(cur())) {
773                        text_if_nonnull_action();
774                        Parse_WF_Element();
775                }
776                else if (at_EndTag_Start<C>(cur())) {
777                        text_if_nonnull_action();
778                        return;
779                }
780                else if (at_Comment_Start<C>(cur())) {
781                        text_if_nonnull_action();
782                        Parse_Comment();
783                }
784                else if (at_CharRef_Start<C>(cur())) {
785                        text_if_nonnull_action();
786                        Parse_CharRef();
787                }
788                else if (AtChar<C,'&'>(cur())) {
789                        text_if_nonnull_action();
790                        Parse_EntityRef();
791                }
792                else if (at_CDATA_Start<C>(cur())) {
793                        text_if_nonnull_action();
794                        Parse_CDATA();
795                }
796                else if (at_PI_Start<C>(cur())) {
797                        text_if_nonnull_action();
798                        Parse_PI();
799                }
800                else if (at_CDATA_End<C>(cur())) {
801                        text_if_nonnull_action();
802                        Advance(3);
803                        Syntax_Error(NT_CharData);
804                }
805                else if (at_EOF()) {
806                        text_if_nonnull_action();
807                        return;
808                }
809                else if (AtChar<C,'<'>(cur())) {
810                        Syntax_Error(NT_markupdecl);
811                }
812                else {
813                        Advance(1);
814                        continue;
815                }
816        } while (1);
817}
818
819
820
821template <CodeUnit_Base C>
822inline void ParsingEngine<C>::ParseContent() {
823        DocumentStart_action(); 
824        vector<int> elemStack;
825        int elemID;
826        bool is_emptyStartTag = false;
827        do {
828                text_or_markup_start = AbsPos();
829                ScanToMarkupStart(); /* '<', '&', or ']' for ']]>' test */
830/*              if (AtChar<C,'<'>(cur())) {
831                        text_if_nonnull_action();
832                        Parse_Markup<C>();
833                }*/
834                if (at_ElementTag_Start<C>(cur())) {
835                        text_if_nonnull_action();
836                        Parse_StartTag();
837//                      elemID = Parse_ValidStartTag(is_emptyStartTag);
838//                      if(!is_emptyStartTag)
839//                              elemStack.push_back(elemID);
840//                      else
841//                              is_emptyStartTag = false;
842                }
843                else if (at_EndTag_Start<C>(cur())) {
844                        text_if_nonnull_action();
845                        Parse_EndTag();
846//                      elemID = Parse_ValidEndTag();
847//                      if (elemStack.size()<= 0 || elemID != elemStack[elemStack.size()-1])
848//                              Syntax_Error(NT_ETag);
849//                      else
850//                              elemStack.pop_back();
851                }
852                else if (at_Comment_Start<C>(cur())) {
853                        text_if_nonnull_action();
854                        Parse_Comment();
855                }
856                else if (at_CharRef_Start<C>(cur())) {
857                        text_if_nonnull_action();
858                        Parse_CharRef();
859                }
860                else if (AtChar<C,'&'>(cur())) {
861                        text_if_nonnull_action();
862                        Parse_EntityRef();
863                }
864                else if (at_CDATA_Start<C>(cur())) {
865                        text_if_nonnull_action();
866                        Parse_CDATA();
867                }
868                else if (at_PI_Start<C>(cur())) {
869                        text_if_nonnull_action();
870                        Parse_PI();
871                }
872                else if (at_CDATA_End<C>(cur())) {
873                        text_if_nonnull_action();
874                        Advance(3);
875                        Syntax_Error(NT_CharData);
876                }
877                else if (at_EOF()) {
878                        text_if_nonnull_action();
879                        break;
880                }
881                else if (AtChar<C,'<'>(cur())) {
882                        Syntax_Error(NT_markupdecl);
883                }
884                else {
885                        Advance(1);
886                        continue;
887                }
888        } while (1);
889        DocumentEnd_action();   
890}
891
892
893template <CodeUnit_Base C>
894inline void ParsingEngine<C>::Parse_DocType (){
895
896        int old_abspos, start_pos;
897        ScanTo(NonWS);
898        start_pos = AbsPos();
899       
900        if (at_DOCTYPE_start<C>(cur()))
901        Advance(9);
902        else{
903//              printf("No Document definition!\n");
904                return;
905        }
906        requireWS();
907        int root_name_start = AbsPos();
908        int nameID = Parse_Name();
909        char * s = copy_string(GetCodeUnitPtr(root_name_start),AbsPos()-root_name_start);
910
911        old_abspos = AbsPos(); 
912    ScanTo(NonWS);
913    if(at_SYSTEM<C>(cur())||at_PUBLIC<C>(cur())){
914        model_info->has_external_DTD = true;
915        if(old_abspos == AbsPos())
916                Syntax_Error(NT_doctypedecl);
917        Parse_ExternalID(model_info->external_DTD_systemLiteral, model_info->external_DTD_pubidLiteral);
918        Parser_Interface * entity_parser;
919        entity_parser = ParserFactory(model_info->external_DTD_systemLiteral, model_info);
920                entity_parser->Parse_ExtSubsetDecl();
921                entity_parser->~Parser_Interface();
922    }
923    else model_info->has_external_DTD = false;
924    ScanTo(NonWS);     
925
926        if (AtChar<C,'['>(cur())){
927                Advance(1);
928                Parse_IntSubset();
929                if (AtChar<C,']'>(cur()))
930                        Advance(1);
931                else
932                Syntax_Error(NT_doctypedecl);
933                ScanTo(NonWS);
934        }
935       
936        if (AtChar<C,'>'>(cur())){
937                Advance(1);   
938                int rootID = model_info->GlobalElementTable[s];
939
940                CRE_Seq * rslt = new CRE_Seq();
941                rslt->subCMs.push_back(new CRE_Name(rootID));
942                CM_RegExp * cre = new CM_RegExp();
943                cre->content_re = rslt;         
944               
945                int id_count = cre->content_re->Set_IDs(0);
946                cre->content_re->Set_First_Map();               
947                symbol_set_t * transition_map = new symbol_set_t[id_count+1];
948                cre->content_re->follow_map[0] = id_count+1;
949               
950                cre->content_re->Set_Follow_Map(transition_map);
951                transition_map[0] = cre->content_re->first_map;
952                if (cre->content_re->matches_empty)
953                        transition_map[0][0]=id_count+1;
954                       
955                cre -> transition_map = transition_map;
956               
957                model_info->rootModel = cre;
958
959        }
960        else
961                Syntax_Error(NT_doctypedecl);   
962}
963
964template <CodeUnit_Base C>
965inline void ParsingEngine<C>::Parse_ExternalID (char *& systemLiteral, char *& pubidLiteral){
966        int quot_start, lgth;
967        if(at_SYSTEM<C>(cur())){
968                Advance(6);
969                pubidLiteral = NULL;
970                requireWS();
971                if (!AtQuote<C>(cur())) Syntax_Error(NT_ExternalID);
972                quot_start = AbsPos()+1;
973                Parse_SystemLiteral (); /*  SystemLiteral */
974                lgth = AbsPos() - quot_start - 1;                       
975                systemLiteral = copy_string(GetCodeUnitPtr(quot_start),lgth);
976        }
977        else if (at_PUBLIC<C>(cur())){
978                Advance(6);
979                requireWS();
980                if (!AtQuote<C>(cur())) Syntax_Error(NT_ExternalID);
981                quot_start = AbsPos()+1;
982                Parse_PubidLiteral ();/*  PubidLiteral */
983                lgth = AbsPos() - quot_start - 1;                       
984                pubidLiteral = copy_string(GetCodeUnitPtr(quot_start),lgth);
985                systemLiteral = NULL;
986                if (AtChar<C, '>'>(cur())) return;
987                requireWS();
988                if (AtQuote<C>(cur())) {
989                        quot_start = AbsPos()+1;       
990                        Parse_SystemLiteral ();/*  SystemLiteral */
991                        lgth = AbsPos() - quot_start - 1;                       
992                        systemLiteral = copy_string(GetCodeUnitPtr(quot_start),lgth);
993                }
994        }
995        else
996                Syntax_Error(NT_ExternalID); 
997}
998
999template <CodeUnit_Base C>
1000inline void ParsingEngine<C>::Parse_SystemLiteral (){
1001        unsigned char quoteCh;
1002        if(AtQuote<C>(cur())){
1003                quoteCh = cur()[0];
1004                Advance(1);
1005        }       
1006        ScanTo(Quote);                 
1007        while (cur()[0] != quoteCh){
1008                if(at_EOF())
1009                        Syntax_Error(NT_SystemLiteral);
1010                Advance(1);
1011                ScanTo(Quote);
1012        }
1013        Advance(1);
1014}
1015
1016template <CodeUnit_Base C>
1017inline void ParsingEngine<C>::Parse_PubidLiteral (){
1018        unsigned char quoteCh;
1019        if(AtQuote<C>(cur())){
1020                quoteCh = cur()[0];
1021                Advance(1);
1022        }       
1023        while (at_PubidChar<C>(cur())) Advance(1);
1024        if (cur()[0] != quoteCh){
1025                Syntax_Error(NT_PubidLiteral);
1026        }
1027        Advance(1);
1028}
1029
1030template <CodeUnit_Base C>
1031inline void ParsingEngine<C>::Parse_IntSubset (){
1032       
1033        while(1){
1034                ScanTo(NonWS); 
1035                text_or_markup_start = AbsPos();
1036                if (AtChar<C,'%'>(cur()))
1037                        Parse_PEReference();   
1038                else if (AtChar<C,'<'>(cur())){
1039                        Advance(1);
1040
1041                        if (AtChar<C,'?'>(cur())){
1042                                if (at_xml<C>(cur()))
1043                                        Syntax_Error(NT_intSubset);
1044                                else
1045                                        Parse_PI();
1046                        }
1047                        else if(AtChar<C,'!'>(cur())){
1048                                Advance(1);
1049                                if(at_DoubleHyphen<C>(cur()))
1050                                        Parse_Comment();
1051                                else if(at_ELEMENT<C>(cur()))
1052                                        Parse_Elementdecl();
1053                                else if(at_ATTLIST<C>(cur()))
1054                                        Parse_AttlistDecl();
1055                                else if(at_ENTITY<C>(cur()))
1056                                        Parse_Entitydecl();
1057                                else if(at_NOTATION<C>(cur()))
1058                                        Parse_Notationdecl();
1059                                else{
1060                                        Syntax_Error(NT_markupdecl);           
1061                                }                                                               
1062                        }
1063                        else
1064                                Syntax_Error(NT_markupdecl); 
1065                }
1066                else if (AtChar<C,']'>(cur())){
1067                        break;
1068                }
1069                else
1070                        Syntax_Error(NT_intSubset); 
1071        }
1072}
1073
1074
1075template <CodeUnit_Base C>
1076inline void ParsingEngine<C>::Parse_PEReference (){
1077
1078        Advance(1); /* Skip "%". */
1079        int nameID = Parse_Name(); 
1080        if (AtChar<C,';'>(cur())) {
1081                Advance(1);
1082                PEReference_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
1083        }
1084        else
1085                Syntax_Error(NT_PEReference);
1086}
1087
1088
1089template <CodeUnit_Base C>
1090inline void ParsingEngine<C>::Parse_Elementdecl (){
1091
1092        Advance(7); /* Skip "<!ELEMENT". */
1093
1094    requireWS();
1095    int name_start = AbsPos();
1096        int nameID = Parse_Name();
1097        int lgth = AbsPos() - name_start;
1098        int elemID = model_info->getOrInsertGlobalElement(GetCodeUnitPtr(name_start), lgth);
1099
1100        requireWS();
1101        ContentModel * cm;
1102        /* Start parsing "contentspec"*/
1103        if (at_EMPTY<C>(cur())) {
1104        Advance(5);
1105        cm = new CM_Empty();
1106        model_info->ContentModelData[elemID] = cm;
1107        }
1108    else if (at_ANY<C>(cur())) {
1109        Advance(3);
1110        cm = new CM_Any();
1111        model_info->ContentModelData[elemID] = cm;
1112    }
1113    else {
1114        if (AtChar<C,'('>(cur()))
1115                        Advance(1);
1116                ScanTo(NonWS);
1117                if (at_PCDATA<C>(cur())){
1118                        cm = Parse_RemainingMixed();
1119                        model_info->ContentModelData[elemID] = cm;
1120                }
1121                else{
1122
1123                        CM_RegExp * cre = new CM_RegExp;
1124                        cre->content_re = Parse_RemainingChildren();
1125
1126                        int id_count = cre->content_re->Set_IDs(0);
1127                        cre->content_re->Set_First_Map();       
1128                        symbol_set_t * transition_map = new symbol_set_t[id_count+1];
1129                        cre->content_re->follow_map[0] = id_count+1;
1130                       
1131                        cre->content_re->Set_Follow_Map(transition_map);
1132                        transition_map[0] = cre->content_re->first_map;
1133                       
1134                        if (cre->content_re->matches_empty)
1135                                transition_map[0][0]=id_count+1;
1136                               
1137                        cre -> transition_map = transition_map;
1138                       
1139                        model_info->ContentModelData[elemID] = cre;
1140                        cm = cre;
1141                }                       
1142    }
1143    ScanTo(NonWS);   
1144
1145        if (AtChar<C,'>'>(cur())) {
1146                Advance(1);
1147        }
1148        else
1149                Syntax_Error(NT_elementdecl);
1150}
1151template <CodeUnit_Base C>
1152inline ContentModel * ParsingEngine<C>::Parse_RemainingMixed (){
1153        CM_Mixed * r = new CM_Mixed();
1154        Advance(7);  /* Skip "#PCDATA". */
1155   
1156    if (AtChar<C,')'>(cur())){
1157        if (AtChar<C,'*'>(cur())) {
1158                Advance(2);
1159                }
1160                else {
1161                        Advance(1);
1162                }
1163    }
1164    else{
1165        ScanTo(NonWS);
1166        int k = 0;
1167        while (AtChar<C,'|'>(cur())){
1168                        Advance(1);
1169                        ScanTo(NonWS);
1170                        int name_start = AbsPos();
1171                        int nameID = Parse_Name();
1172                        int lgth = AbsPos() - name_start;
1173                        int elemID = model_info->getOrInsertGlobalElement(GetCodeUnitPtr(name_start), lgth);
1174                        r->elements[elemID] = ++k;
1175                        ScanTo(NonWS);
1176                }
1177                if (at_Para_star<C>(cur())) Advance(2);
1178                else {
1179                        Syntax_Error(NT_Mixed);
1180                        exit(-1);
1181        }
1182    }
1183    return r;
1184}
1185
1186
1187template <CodeUnit_Base C>
1188inline Content_RE * ParsingEngine<C>::Parse_RemainingChildren (){
1189        Content_RE * c1 = Parse_Cp();
1190        Content_RE * r = c1;
1191        ScanTo(NonWS);
1192        if(AtChar<C,'|'>(cur())){
1193                CRE_Choice * rslt = new CRE_Choice;
1194                rslt->subCMs.push_back(c1);
1195                Advance(1);
1196                ScanTo(NonWS);
1197                rslt->subCMs.push_back(Parse_Cp());
1198                ScanTo(NonWS);
1199                while(!AtChar<C,')'>(cur())){
1200                        if(AtChar<C,'|'>(cur()))
1201                                Advance(1);
1202                        else
1203                                Syntax_Error(NT_children);
1204                        ScanTo(NonWS);
1205                        rslt->subCMs.push_back(Parse_Cp());
1206                        ScanTo(NonWS);
1207                }
1208                Advance(1);
1209                rslt->Compile();
1210                r = rslt;
1211        }
1212        else if(AtChar<C,','>(cur())){
1213                CRE_Seq * rslt = new CRE_Seq;
1214                rslt->subCMs.push_back(c1);
1215                Advance(1);
1216                ScanTo(NonWS);
1217                rslt->subCMs.push_back(Parse_Cp());
1218                ScanTo(NonWS);
1219                while(!AtChar<C,')'>(cur())){
1220                        if(AtChar<C,','>(cur()))
1221                                Advance(1);
1222                        else
1223                                Syntax_Error(NT_children);
1224                        ScanTo(NonWS);
1225                        rslt->subCMs.push_back(Parse_Cp());
1226                        ScanTo(NonWS);
1227                }
1228                Advance(1);
1229                rslt->Compile();
1230                r = rslt;
1231        }       
1232        else if(AtChar<C,')'>(cur())){
1233                Advance(1);
1234        }
1235        else
1236                Syntax_Error(NT_children);
1237               
1238        if (AtChar<C,'?'>(cur())) {
1239                Advance(1);
1240                r = new CRE_Opt(r);
1241        }
1242        else if (AtChar<C,'*'>(cur())) {
1243                Advance(1);
1244                r = new CRE_Star(r);
1245        }
1246        else if (AtChar<C,'+'>(cur())) {
1247                Advance(1);
1248                r = new CRE_Plus(r);
1249        }
1250
1251        return r;
1252}
1253
1254template <CodeUnit_Base C>
1255inline Content_RE * ParsingEngine<C>::Parse_Cp (){
1256        if (AtChar<C,'('>(cur())){
1257                Advance(1);
1258                ScanTo(NonWS);
1259                Parse_RemainingChildren();
1260        }
1261        else{
1262                int name_start = AbsPos();
1263                int nameID = Parse_Name();
1264                int lgth = AbsPos() - name_start;
1265                int elemID = model_info->getOrInsertGlobalElement(GetCodeUnitPtr(name_start), lgth);
1266                CRE_Name * r = new CRE_Name(elemID);
1267
1268                if (AtChar<C,'?'>(cur())) {
1269                        Advance(1);
1270                        return new CRE_Opt(r);
1271                }
1272                else if (AtChar<C,'*'>(cur())) {
1273                        Advance(1);
1274                        return new CRE_Star(r);
1275                }
1276                else if (AtChar<C,'+'>(cur())) {
1277                        Advance(1);
1278                        return new CRE_Plus(r);
1279                }
1280                else return r;
1281        }
1282}
1283
1284template <CodeUnit_Base C>
1285inline void ParsingEngine<C>::Parse_AttlistDecl (){
1286       
1287        int old_abspos;
1288       
1289        int name_start;
1290        int lgth;
1291       
1292        int elemID;
1293        int attID;
1294       
1295        Advance(7); /* Skip "ATTLIST. */
1296        requireWS();
1297       
1298        name_start = AbsPos();
1299        int nameID = Parse_Name();
1300        lgth = AbsPos()-name_start;
1301        elemID = model_info->getOrInsertGlobalElement(GetCodeUnitPtr(name_start), lgth);
1302       
1303        old_abspos = AbsPos();
1304        ScanTo(NonWS);
1305        while(!AtChar<C,'>'>(cur())) {
1306                if(old_abspos == AbsPos())
1307                Syntax_Error(NT_AttlistDecl);
1308               
1309        name_start = AbsPos();
1310                int nameID = Parse_Name();
1311                lgth = AbsPos()-name_start;
1312               
1313                attID = model_info->getOrInsertGlobalAttName(GetCodeUnitPtr(name_start), lgth);
1314                if (attID >= LastAttOccurrence.size()) LastAttOccurrence.push_back(0);
1315        ATT_info * this_info = new ATT_info;
1316        this_info->globalATT_id = attID;
1317        requireWS();
1318        if (at_CDATA<C>(cur())){
1319                Advance(5);
1320                this_info->attType = CDATA_att;
1321        }
1322        else if(at_ID<C>(cur())){
1323                Advance(2);
1324                this_info->attType = ID_att;
1325        }
1326        /* Make sure to check IDREFS before IDREF*/
1327        else if(at_IDREFS<C>(cur())){
1328                Advance(6);
1329                this_info->attType = IDREFS_att;
1330        }
1331        else if(at_IDREF<C>(cur())){
1332                Advance(5);
1333                this_info->attType = IDREF_att;
1334        }
1335        else if(at_ENTITY<C>(cur())){
1336                Advance(6);
1337                this_info->attType = ENTITY_att;
1338        }
1339        else if(at_ENTITIES<C>(cur())){
1340                Advance(8);
1341                this_info->attType = ENTITIES_att;
1342        }
1343        /* Make sure to check NMTOKENS before NMTOKEN*/
1344        else if(at_NMTOKENS<C>(cur())){
1345                Advance(8);
1346                this_info->attType = NMTOKENS_att;
1347        }
1348        else if(at_NMTOKEN<C>(cur())){
1349                Advance(7);
1350                this_info->attType = NMTOKEN_att;
1351        }
1352        else if(at_NOTATION<C>(cur())){ /* NotationType = 'NOTATION' S Enumeration
1353                                                                         when Nmtoken = Name */
1354                Advance(8);
1355                        requireWS();
1356                Parse_Notation(this_info);
1357                this_info->attType = NOTATION_att;
1358        }
1359        else if(AtChar<C,'('>(cur())){
1360                Parse_Enumeration(this_info);
1361                this_info->attType = enumeration_att;
1362        }
1363        else
1364                Syntax_Error(NT_AttlistDecl);
1365        requireWS();
1366        Parse_DefaultDecl(this_info);
1367
1368                ScanTo(NonWS);
1369                model_info->ElementAttributeData[elemID].push_back(this_info);
1370        }
1371
1372        Advance(1);
1373}
1374
1375template <CodeUnit_Base C>
1376inline void ParsingEngine<C>::Parse_Notation (ATT_info * this_info){
1377
1378        if(AtChar<C,'('>(cur()))
1379                Advance(1);
1380        else
1381                Syntax_Error(NT_NotationType);
1382        ScanTo(NonWS);
1383       
1384    int name_start = AbsPos();
1385        int nameID = Parse_Name();
1386        int     lgth = AbsPos()-name_start;
1387       
1388        char *s = new char[lgth+1];
1389        memcpy(s, GetCodeUnitPtr(name_start), lgth);
1390        s[lgth] = '\0';
1391
1392        /*Notation name is not in the global table!*/
1393        if(model_info->GlobalNotationTable[s]==0)
1394                Validity_Error(vErr_notatn);
1395       
1396        ScanTo(NonWS);
1397        while(AtChar<C,'|'>(cur())){
1398                Advance(1);
1399                ScanTo(NonWS);         
1400                name_start = AbsPos();
1401                int nameID = Parse_Name();
1402                lgth = AbsPos()-name_start;
1403       
1404                char *s = new char[lgth+1];
1405                memcpy(s, GetCodeUnitPtr(name_start), lgth);
1406                s[lgth] = '\0';
1407       
1408                if(model_info->GlobalNotationTable[s]==0)
1409                        Validity_Error(vErr_notatn);
1410                       
1411                ScanTo(NonWS);
1412        }
1413        if (AtChar<C,')'>(cur())) 
1414                Advance(1);
1415        else
1416                Syntax_Error(NT_NotationType);
1417}
1418
1419template <CodeUnit_Base C>
1420inline void ParsingEngine<C>::Parse_Enumeration (ATT_info * this_info){
1421
1422        int enumCount=0;
1423        if(AtChar<C,'('>(cur()))
1424                Advance(1);
1425        else
1426                Syntax_Error(NT_Enumeration);
1427        ScanTo(NonWS);
1428       
1429        int     name_start = AbsPos();
1430        int nameID = Parse_Name();
1431        int     lgth = AbsPos()-name_start;
1432       
1433        char *s = new char[lgth+1];
1434        memcpy(s, GetCodeUnitPtr(name_start), lgth);
1435        s[lgth] = '\0';
1436       
1437        this_info->enumValues[s]=++(enumCount);
1438       
1439        ScanTo(NonWS);
1440        while(AtChar<C,'|'>(cur())){
1441                Advance(1);
1442                ScanTo(NonWS);         
1443                name_start = AbsPos();
1444                int nameID = Parse_Name();
1445                lgth = AbsPos()-name_start;
1446       
1447                char *s = new char[lgth+1];
1448                memcpy(s, GetCodeUnitPtr(name_start), lgth);
1449                s[lgth] = '\0';
1450       
1451                int enumID = this_info->enumValues[s];
1452                if(enumID==0){ 
1453                        this_info->enumValues[s]=++(enumCount);
1454                        enumID = enumCount;
1455                }
1456                else if(!StrictWellFormedness){
1457                        Validity_Error(vErr_NoDuplicateTokens);
1458                }
1459                ScanTo(NonWS);
1460        }
1461        if (AtChar<C,')'>(cur())) 
1462                Advance(1);
1463        else
1464                Syntax_Error(NT_Enumeration);
1465}
1466
1467template <CodeUnit_Base C>
1468inline void ParsingEngine<C>::Parse_DefaultDecl (ATT_info * this_info){
1469        if(at_REQUIRED<C>(cur())){
1470                Advance(9);
1471                this_info->defaultKind = REQUIRED_att;
1472        }
1473        else if(at_IMPLIED<C>(cur())){
1474                Advance(8);
1475                this_info->defaultKind = IMPLIED_att;
1476        }
1477        else {
1478                if(at_FIXED<C>(cur())){
1479                        Advance(6);
1480                        requireWS();
1481                        this_info->defaultKind = FIXED_att;
1482                }
1483                else this_info->defaultKind = DEFAULT_att;
1484                if(AtQuote<C>(cur())){
1485                        int quot_start = AbsPos()+1;
1486                        Parse_AttValue();
1487                        /* need to normalize */
1488                        this_info->defaultValueLgth = AbsPos() - quot_start - 1;
1489                       
1490                        this_info->defaultValue = new unsigned char[this_info->defaultValueLgth+1];
1491                        memcpy(this_info->defaultValue, GetCodeUnitPtr(quot_start),this_info->defaultValueLgth); 
1492                        this_info->defaultValue[this_info->defaultValueLgth] = '\0';
1493                        }
1494                else
1495                        Syntax_Error(NT_DefaultDecl);
1496        }
1497}
1498
1499template <CodeUnit_Base C>
1500inline void ParsingEngine<C>::Parse_Entitydecl (){
1501       
1502        int name_start;
1503        int quot_start;
1504        int lgth;
1505        int old_abspos;
1506        char * s;
1507       
1508        Advance(6); /* Skip "ENTITY. */
1509        requireWS();
1510       
1511        if (AtChar<C,'%'>(cur())){
1512                Advance(1);
1513                requireWS();
1514               
1515                name_start = AbsPos();
1516                int nameID = Parse_Name();
1517                lgth = AbsPos()- name_start;
1518                s = new char[lgth+1];
1519                memcpy(s, GetCodeUnitPtr(name_start),lgth); 
1520                s[lgth] = '\0';
1521       
1522                PEntity_info * this_info = new PEntity_info;
1523                int entityID = model_info->GlobalPEntityTable[s];
1524                if(entityID==0){       
1525                        model_info->GlobalPEntityTable[s]=++(model_info->globalPEntityCount);
1526                        entityID = model_info->globalPEntityCount;
1527                        this_info->globalPEntity_id = entityID;
1528                }
1529                else
1530                        printf("Warning: Entity definition already exist!\n");
1531       
1532                requireWS();
1533                if(AtQuote<C>(cur())){
1534                Parse_PEntityValue(this_info);
1535                this_info->is_external = false;
1536        }
1537        else {
1538                Parse_ExternalID(this_info->systemLiteral, this_info->pubidLiteral);
1539                this_info->is_external = true;
1540                if (this_info->systemLiteral == NULL) Syntax_Error(NT_EntityDecl);
1541        }
1542        model_info->PEntityData.push_back(this_info);
1543        }
1544        else{
1545                name_start = AbsPos();
1546                int nameID = Parse_Name();
1547                lgth = AbsPos()- name_start;
1548                s = new char[lgth+1];
1549                memcpy(s, GetCodeUnitPtr(name_start),lgth); 
1550                s[lgth] = '\0';
1551       
1552                GEntity_info * this_info = new GEntity_info();
1553                int entityID = model_info->GlobalGEntityTable[s];
1554                if(entityID==0){       
1555                        model_info->GlobalGEntityTable[s]=++(model_info->globalGEntityCount);
1556                        entityID = model_info->globalGEntityCount;
1557                        this_info->globalGEntity_id = entityID;
1558                }
1559                else
1560                        printf("Warning: Entity definition already exist!\n");
1561                       
1562                requireWS();
1563               
1564                if(AtQuote<C>(cur())){
1565                Parse_GEntityValue(this_info);                 
1566                this_info->is_external = false;
1567        }
1568        else {
1569                Parse_ExternalID(this_info->systemLiteral, this_info->pubidLiteral);
1570                this_info->is_external = true;
1571                if (this_info->systemLiteral == NULL) Syntax_Error(NT_EntityDecl);
1572                        old_abspos = AbsPos();
1573                        ScanTo(NonWS);
1574                if(at_NDATA<C>(cur())){
1575                        if(old_abspos == AbsPos())
1576                                Syntax_Error(NT_EntityDecl);
1577                        else
1578                                Advance(5);
1579                        requireWS();
1580                        name_start = AbsPos();
1581                        int nameID = Parse_Name();
1582                        lgth = AbsPos() - name_start;
1583                                this_info->NDataName = copy_string(GetCodeUnitPtr(name_start),lgth);
1584                }
1585                }
1586        model_info->GEntityData.push_back(this_info);
1587        }
1588        ScanTo(NonWS);
1589        if (AtChar<C,'>'>(cur())){
1590                Advance(1);
1591        }
1592        else
1593                Syntax_Error(NT_EntityDecl);
1594}
1595
1596template <CodeUnit_Base C>
1597inline void ParsingEngine<C>::Parse_Notationdecl (){
1598
1599        int old_abspos;
1600        Advance(8); /* Skip "NOTATION. */
1601        requireWS();
1602       
1603        int name_start = AbsPos();
1604        int nameID = Parse_Name();
1605        int     lgth = AbsPos()-name_start;
1606       
1607        char *s = new char[lgth+1];
1608        memcpy(s, GetCodeUnitPtr(name_start), lgth);
1609        s[lgth] = '\0';
1610
1611        int notationID = model_info->GlobalNotationTable[s];
1612        if(notationID==0){     
1613                model_info->GlobalNotationTable[s]=++(model_info->globalNotationCount);
1614                notationID = model_info->globalNotationCount;
1615        }
1616        else /*Duplicate notation name!*/
1617                Validity_Error(vErr_NoDuplicateTokens);
1618        Notation_info * this_info = new Notation_info;
1619                       
1620    Parse_ExternalID(this_info->systemLiteral, this_info->pubidLiteral);
1621        ScanTo(NonWS);
1622        if (AtChar<C,'>'>(cur())) {
1623                Advance(1);
1624        }
1625        else
1626                Syntax_Error(NT_NotationDecl);
1627}
1628
1629template <CodeUnit_Base C>
1630inline void ParsingEngine<C>::requireWS(){
1631       
1632    int old_abspos = AbsPos(); 
1633    ScanTo(NonWS);
1634    if(old_abspos == AbsPos())
1635        Syntax_Error(NT_S);
1636}
1637
1638template <CodeUnit_Base C>
1639inline void ParsingEngine<C>::Parse_AttValue(){
1640       
1641        int     quoteCh = cur()[0];
1642        Advance(1); /* Skip " or ' */
1643
1644        ScanTo(Quote);                 
1645        while (cur()[0] != quoteCh){
1646                if (at_CharRef_Start<C>(cur())){
1647                        Parse_CharRef();
1648                        ScanTo(Quote);
1649                }
1650                else if (AtChar<C,'&'>(cur())){
1651                        Parse_EntityRef();
1652                        ScanTo(Quote);
1653                }
1654                else if (AtQuote<C>(cur())) {
1655                        Advance(1);
1656                        ScanTo(Quote);
1657                }
1658                else /* if (AtChar<C,'<'>(cur())) */
1659                        WF_Error(wfErr_CleanAttrVals);
1660        }
1661        Advance(1);
1662}
1663
1664template <CodeUnit_Base C>
1665inline void ParsingEngine<C>::Parse_GEntityValue(GEntity_info * this_info){
1666       
1667        int     quoteCh = cur()[0];
1668        Advance(1); /* Skip " or ' */
1669        this_info->is_simple = true;
1670        int quot_start = AbsPos();
1671        ScanTo(Quote);         
1672        char *  replText = copy_string(GetCodeUnitPtr(quot_start),AbsPos()-quot_start);
1673
1674        while (cur()[0] != quoteCh){
1675                if (at_CharRef_Start<C>(cur())){
1676                        strcat (replText,Replace_CharRef());
1677                        quot_start = AbsPos();
1678                        ScanTo(Quote);
1679                }
1680                else if (AtChar<C,'&'>(cur())){
1681                        strcat (replText,Replace_EntityRef(this_info->is_simple));
1682                        quot_start = AbsPos();
1683                        ScanTo(Quote);
1684                }
1685                else if (AtQuote<C>(cur())) {
1686                        quot_start = AbsPos();
1687                        Advance(1);
1688                        ScanTo(Quote);
1689                }
1690                else { /* '<' found */
1691                        quot_start = AbsPos();
1692                        Advance(1);
1693                        ScanTo(Quote);
1694                        this_info->is_simple = false;
1695                       
1696                }
1697                replText = cat_string (replText,(char *)GetCodeUnitPtr(quot_start), strlen(replText), AbsPos()-quot_start);
1698        }
1699        this_info->ReplacementText = replText;
1700        Advance(1);
1701}
1702
1703template <CodeUnit_Base C>
1704inline char * ParsingEngine<C>::Replace_EntityRef(bool& is_simple){
1705        Advance(1);
1706        int entity_start = AbsPos();
1707        int nameID = Parse_Name(); 
1708        char * s = copy_string(GetCodeUnitPtr(entity_start),AbsPos()-entity_start);
1709        if (AtChar<C,';'>(cur()))
1710                Advance(1);
1711        else
1712                Syntax_Error(NT_EntityValue);
1713        int entityID = model_info->GlobalGEntityTable[s]; 
1714        if (entityID == 0)
1715                WF_Error(wfErr_wf_entdeclared);
1716        else{
1717                if (model_info->GEntityData[entityID-1]->is_simple == false)
1718                        is_simple = false;
1719                return model_info->GEntityData[entityID-1]->ReplacementText;
1720        }
1721       
1722}
1723
1724template <CodeUnit_Base C>
1725inline void ParsingEngine<C>::Parse_PEntityValue(PEntity_info * this_info){
1726}
1727
1728template <CodeUnit_Base C>
1729inline char * ParsingEngine<C>::Replace_CharRef(){
1730        Advance(1);
1731        int entity_start = AbsPos();
1732        int nameID = Parse_Name(); 
1733        char * s = copy_string(GetCodeUnitPtr(entity_start),AbsPos()-entity_start);
1734        int entityID = model_info->GlobalGEntityTable[s]; 
1735        if (entityID == 0)
1736                WF_Error(wfErr_wf_entdeclared);
1737        else
1738                return model_info->GEntityData[entityID-1]->ReplacementText;   
1739       
1740}
1741
1742template <CodeUnit_Base C>
1743inline void ParsingEngine<C>::Parse_Prolog(){
1744        ScanTo(NonWS);
1745        int old_pos = AbsPos();
1746        while (!at_DOCTYPE_start<C>(cur())) {
1747                if (at_Comment_Start<C>(cur())) 
1748                        Parse_Comment();
1749                else if (at_PI_Start<C>(cur()))
1750                                Parse_PI();
1751                else{
1752                        Prolog_action(GetCodeUnitPtr(old_pos), LengthFrom(old_pos));
1753                        return;
1754                }
1755                ScanTo(NonWS);
1756        }
1757        Parse_DocType();
1758        ScanTo(NonWS);
1759        while(at_Comment_Start<C>(cur()) || at_PI_Start<C>(cur()) ){
1760                if (at_Comment_Start<C>(cur()))
1761                        Parse_Comment();
1762                else 
1763                        Parse_PI();
1764                ScanTo(NonWS);
1765        }
1766        Prolog_action(GetCodeUnitPtr(old_pos), LengthFrom(old_pos));
1767}
1768
1769template <CodeUnit_Base C>
1770inline void ParsingEngine<C>::Parse_ExtSubsetDecl() {
1771        int start_pos=AbsPos();
1772        while(!at_EOF()){
1773                if(at_condSect_start<C>(cur())){               
1774                        Advance(3);
1775                        ScanTo(NonWS);
1776                        if (at_INCLUDE<C>(cur())){
1777                                Advance(7);
1778                                ScanTo(NonWS);
1779                                if(AtChar<C,'['>(cur())){
1780                                        Advance(1);
1781                                        Parse_ExtSubsetDecl();
1782                                        if(at_CDATA_End<C>(cur()))
1783                                                Advance(3);
1784                                        else Syntax_Error(NT_includeSect);
1785                                }
1786                                else Syntax_Error(NT_includeSect);
1787                        }
1788                        else if (at_IGNORE<C>(cur())){
1789                                Advance(6);
1790                                ScanTo(NonWS);         
1791                                if(AtChar<C,'['>(cur())){
1792                                        int section_depth=1;
1793                                        Advance(1);
1794                                        while(!at_EOF()){
1795                                                ScanToMarkupStart();
1796                                                if(at_condSect_start<C>(cur())){
1797                                                        Advance(3);
1798                                                        section_depth++;
1799                                                }
1800                                                else if(at_CDATA_End<C>(cur())){
1801                                                        Advance(3);
1802                                                        section_depth--;
1803                                                }
1804                                                if(section_depth==0) return;                                   
1805                                        }
1806                                        Syntax_Error(NT_ignoreSectContents);   
1807                                }
1808                                else Syntax_Error(NT_ignoreSect);
1809                        }
1810                        else Syntax_Error(NT_conditionalSect);
1811                }
1812                else if (AtChar<C,'%'>(cur()))
1813                        Parse_PEReference();   
1814                else if (AtChar<C,'<'>(cur())){
1815                        Advance(1);
1816
1817                        if (AtChar<C,'?'>(cur())){
1818                                Parse_PI();
1819                        }
1820                        else if(AtChar<C,'!'>(cur())){
1821                                Advance(1);
1822                                if(at_DoubleHyphen<C>(cur()))
1823                                        Parse_Comment();
1824                                else if(at_ELEMENT<C>(cur()))
1825                                        Parse_Elementdecl();
1826                                else if(at_ATTLIST<C>(cur()))
1827                                        Parse_AttlistDecl();
1828                                else if(at_ENTITY<C>(cur()))
1829                                        Parse_Entitydecl();
1830                                else if(at_NOTATION<C>(cur()))
1831                                        Parse_Notationdecl();                                   
1832                                else{
1833                                        Syntax_Error(NT_markupdecl);   
1834                                }                                                               
1835                        }
1836                        else
1837                                Syntax_Error(NT_markupdecl); 
1838                }
1839                else
1840                        Syntax_Error(NT_extSubsetDecl); 
1841                ScanTo(NonWS);
1842        }
1843        ExtSubsetDecl_action(GetCodeUnitPtr(start_pos), LengthFrom(start_pos));
1844}
1845
1846template <CodeUnit_Base C>
1847inline int ParsingEngine<C>::Parse_ValidEndTag() {
1848        Advance(2); /* Skip "</". */
1849       
1850        int name_start = AbsPos();
1851        int nameID = Parse_Name();  /* Name delimiter: WS, "/" or ">" */
1852        char * s = copy_string(GetCodeUnitPtr(name_start),AbsPos()-name_start);
1853        int elemID = model_info->GlobalElementTable[s];
1854        if(elemID==0)
1855                        Validity_Error(vErr_elementvalid);
1856                       
1857        if (AtChar<C,'>'>(cur())) {
1858                Advance(1);
1859                EndTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
1860        }
1861    else {
1862                ScanTo(NonWS);
1863                if (AtChar<C,'>'>(cur())) {
1864                        Advance(1);
1865                        EndTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
1866                }
1867                else Syntax_Error(NT_ETag);
1868    }
1869    return elemID;
1870}
1871/* Parse a valid start or empty element tag. */
1872template <CodeUnit_Base C>
1873inline int ParsingEngine<C>::Parse_ValidStartTag (bool& is_emptyStartTag){
1874        int att_name_start;
1875        int att_val_start;
1876        int att_name_end, att_val_end;
1877        unsigned char quoteCh;
1878        Advance(1);
1879       
1880        int name_start = AbsPos();
1881        int nameID = Parse_Name();  /* Name delimiter: WS, "/" or ">" */
1882        char * s = copy_string(GetCodeUnitPtr(name_start),AbsPos()-name_start);
1883        int elemID = model_info->GlobalElementTable[s];
1884        if(elemID==0)
1885                        Validity_Error(vErr_elementvalid);
1886       
1887        ElementName_action(GetCodeUnitPtr(text_or_markup_start+1), LengthFrom(text_or_markup_start+1));
1888        /* The following test optimizes the most common case of a
1889        start tag with no attributes.  */
1890        if (AtChar<C,'>'>(cur())) {
1891                Advance(1);
1892                StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
1893        }
1894        else {
1895                ScanTo(NonWS);
1896                if (AtChar<C,'>'>(cur())) {
1897                        Advance(1);
1898                        StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
1899                }
1900                else if (at_EmptyElementDelim<C>(cur())) {
1901                        Advance(2);
1902                        is_emptyStartTag = true;
1903                        EmptyElement_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
1904                }
1905                else do {
1906                        /* Must be an attribute-value pair or error. */
1907                        att_name_start = AbsPos();
1908                        int nameID = Parse_Name();
1909                        att_name_end = AbsPos();
1910                        int lgth = att_name_end-att_name_start;
1911               
1912                        int attID = model_info->getOrInsertGlobalAttName(GetCodeUnitPtr(att_name_start), lgth);
1913                        if (attID >= LastAttOccurrence.size()) LastAttOccurrence.push_back(0);
1914                        else {
1915                                if (LastAttOccurrence[attID] > text_or_markup_start) {
1916                                        WF_Error(wfErr_uniqattspec); /* Duplicate attribute. */
1917                                        break;
1918                                }                       
1919                        }
1920                        LastAttOccurrence[attID] = att_name_start;
1921                        /* The following optimized tests handle the frequently occurring
1922                        case that there are no blanks on either side of the equals sign.
1923                        In many cases, the very first test handles 100% of actual
1924                        attribute-value pairs encountered. */
1925                        if (at_EqualsQuote<C>(cur())) Advance(1); 
1926                        else {
1927                                ScanTo(NonWS);
1928                                if (!AtChar<C,'='>(cur())) {
1929                                        Syntax_Error(NT_STag); 
1930                                        break;
1931                                }
1932                                ScanTo(NonWS);
1933                                if (!AtQuote<C>(cur())) {
1934                                        Syntax_Error(NT_STag); 
1935                                        break;
1936                                }
1937                        }
1938                        att_val_start = AbsPos()+1;
1939                        Parse_AttValue();
1940                        att_val_end = AbsPos()-1;
1941                        if (at_xmlns<C>(cur()+att_name_start-AbsPos())) {
1942                                Namespace_action(GetCodeUnitPtr(att_name_start), att_name_end - att_name_start,
1943                                                 GetCodeUnitPtr(att_val_start), att_val_end - att_val_start);
1944                        }
1945                        else {
1946                                AttributeValue_action(GetCodeUnitPtr(att_name_start), att_name_end - att_name_start,
1947                                                 GetCodeUnitPtr(att_val_start), att_val_end - att_val_start);
1948                        }
1949                        /* Now check for end or repeat. Avoid whitespace scan if possible.*/
1950                        if (AtChar<C,'>'>(cur())) {
1951                                Advance(1);
1952                                StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
1953                                break;
1954                        }
1955                        else if (at_EmptyElementDelim<C>(cur())) {
1956                                Advance(2);
1957                                is_emptyStartTag = true;       
1958                                EmptyElement_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
1959                                break;
1960                        }
1961                        ScanTo(NonWS);
1962                        if (AtChar<C,'>'>(cur())) {
1963                                Advance(1);
1964                                StartTag_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
1965                                break;
1966                        }
1967                        else if (at_EmptyElementDelim<C>(cur())) {
1968                                Advance(2);
1969                                is_emptyStartTag = true;
1970                                EmptyElement_action(GetCodeUnitPtr(text_or_markup_start), LengthFrom(text_or_markup_start));
1971                                break;
1972                        }
1973                        else if (AbsPos() == att_val_end + 1) { 
1974                                /* No WS following att value */
1975                                Syntax_Error(NT_STag);
1976                                break;
1977                        }
1978                } while (1);
1979        }
1980        return elemID;
1981}
1982
1983template <CodeUnit_Base C>
1984inline int ParsingEngine<C>::Parse_ValidElement() {
1985        bool is_emptyStartTag = false;
1986        int elemID = Parse_ValidStartTag(is_emptyStartTag);
1987#ifdef DEBUG
1988        printf("Parse_ValidElement: elemID = %d, is_emptyStartTag=%i\n",elemID, is_emptyStartTag);
1989#endif
1990        ContentModel * cm = model_info->ContentModelData[elemID];
1991        switch (cm->cm_type) {
1992                case cm_Empty:
1993                        if (!is_emptyStartTag) {
1994                                if (at_EndTag_Start<C>(cur())) {
1995                                        if (Parse_ValidEndTag()!=elemID) Validity_Error(vErr_elementvalid);
1996//                                      Parse_EndTag();
1997                                }
1998                                else {
1999                                        Validity_Error(vErr_elementvalid);
2000                                }
2001                        }
2002                        break;
2003                case cm_Any:           
2004                        if (!is_emptyStartTag) {
2005                                Parse_AnyContent();
2006                                if (Parse_ValidEndTag()!=elemID) Validity_Error(vErr_elementvalid);
2007                        }
2008                        break;
2009                case cm_Mixed:         
2010                        if (!is_emptyStartTag) {
2011                                Parse_MixedContent(((CM_Mixed *) cm)->elements);
2012                                if (Parse_ValidEndTag()!=elemID) Validity_Error(vErr_elementvalid);
2013                        }
2014                        break;
2015                case cm_RegExp:
2016                        CM_RegExp * cre = (CM_RegExp *) cm;
2017                        int content_state = 0;
2018                        if (!is_emptyStartTag) {
2019                                content_state = Parse_ValidContent(cre);
2020                                if (Parse_ValidEndTag()!=elemID) Validity_Error(vErr_elementvalid);                     
2021                        }
2022                        if (cre->transition_map[content_state][0]==0) {
2023                                Validity_Error(vErr_elementvalid);
2024                        }
2025        }
2026        return elemID;
2027}
2028
2029template <CodeUnit_Base C>
2030inline int ParsingEngine<C>::Parse_ValidContent(CM_RegExp * cre) {
2031        int cur_state = 0;
2032        do {
2033                ScanTo(NonWS);
2034                /* If non-null report WS  WS_action()? */
2035                if (at_EndTag_Start<C>(cur())) {
2036                        break;
2037                }
2038                else if (at_ElementTag_Start<C>(cur())) {
2039                        int elemID = Parse_ValidElement();
2040#ifdef DEBUG
2041                        printf("Content model state transition %i", cur_state);
2042#endif
2043                        cur_state = cre->transition_map[cur_state][elemID];
2044#ifdef DEBUG
2045                        printf("-> %i\n", cur_state);
2046#endif
2047                }
2048                else if (at_Comment_Start<C>(cur())) {
2049                        Parse_Comment();
2050                }
2051                else if (at_PI_Start<C>(cur())) {
2052                        Parse_PI();
2053                }
2054                else if (AtChar<C,'&'>(cur())) {
2055                        Parse_EntityRef();
2056                }
2057                else if (at_EOF()) {
2058                        break;
2059                }
2060                else if (AtChar<C,'<'>(cur())) {
2061                        Syntax_Error(NT_markupdecl);
2062                }
2063                else {
2064                        Validity_Error(vErr_elementvalid);
2065                }
2066        } while(1);
2067        return cur_state;
2068}
2069
2070
2071template <CodeUnit_Base C>
2072inline void ParsingEngine<C>::Parse_AnyContent() {
2073        do {
2074                text_or_markup_start = AbsPos();
2075                ScanToMarkupStart(); /* '<', '&', or ']' for ']]>' test */
2076                if (at_ElementTag_Start<C>(cur())) {
2077                        text_if_nonnull_action();
2078                        int elemID = Parse_ValidElement();
2079                }
2080                else if (at_EndTag_Start<C>(cur())) {
2081                        text_if_nonnull_action();
2082                        return;
2083                }
2084                else if (at_Comment_Start<C>(cur())) {
2085                        text_if_nonnull_action();
2086                        Parse_Comment();
2087                }
2088                else if (at_CharRef_Start<C>(cur())) {
2089                        text_if_nonnull_action();
2090                        Parse_CharRef();
2091                }
2092                else if (AtChar<C,'&'>(cur())) {
2093                        text_if_nonnull_action();
2094                        Parse_EntityRef();
2095                }
2096                else if (at_CDATA_Start<C>(cur())) {
2097                        text_if_nonnull_action();
2098                        Parse_CDATA();
2099                }
2100                else if (at_PI_Start<C>(cur())) {
2101                        text_if_nonnull_action();
2102                        Parse_PI();
2103                }
2104                else if (at_CDATA_End<C>(cur())) {
2105                        text_if_nonnull_action();
2106                        Advance(3);
2107                        Syntax_Error(NT_CharData);
2108                }
2109                else if (at_EOF()) {
2110                        text_if_nonnull_action();
2111                        return;
2112                }
2113                else if (AtChar<C,'<'>(cur())) {
2114                        Syntax_Error(NT_markupdecl);
2115                }
2116                else {
2117                        Advance(1);
2118                        continue;
2119                }
2120        } while (1);
2121}
2122template <CodeUnit_Base C>
2123inline void ParsingEngine<C>::Parse_MixedContent(symbol_set_t elems) {
2124        do {
2125                text_or_markup_start = AbsPos();
2126                ScanToMarkupStart(); /* '<', '&', or ']' for ']]>' test */
2127/*              if (AtChar<C,'<'>(cur())) {
2128                        text_if_nonnull_action();
2129                        Parse_Markup<C>();
2130                }*/
2131                if (at_ElementTag_Start<C>(cur())) {
2132                        text_if_nonnull_action();
2133                        int elemID = Parse_ValidElement();
2134                        if (elems[elemID] == 0) {
2135                                Validity_Error(vErr_elementvalid);
2136                        }
2137                }
2138                else if (at_EndTag_Start<C>(cur())) {
2139                        text_if_nonnull_action();
2140                        return;
2141                }
2142                else if (at_Comment_Start<C>(cur())) {
2143                        text_if_nonnull_action();
2144                        Parse_Comment();
2145                }
2146                else if (at_CharRef_Start<C>(cur())) {
2147                        text_if_nonnull_action();
2148                        Parse_CharRef();
2149                }
2150                else if (AtChar<C,'&'>(cur())) {
2151                        text_if_nonnull_action();
2152                        Parse_EntityRef();
2153                }
2154                else if (at_CDATA_Start<C>(cur())) {
2155                        text_if_nonnull_action();
2156                        Parse_CDATA();
2157                }
2158                else if (at_PI_Start<C>(cur())) {
2159                        text_if_nonnull_action();
2160                        Parse_PI();
2161                }
2162                else if (at_CDATA_End<C>(cur())) {
2163                        text_if_nonnull_action();
2164                        Advance(3);
2165                        Syntax_Error(NT_CharData);
2166                }
2167                else if (at_EOF()) {
2168                        text_if_nonnull_action();
2169                        return;
2170                }
2171                else if (AtChar<C,'<'>(cur())) {
2172                        Syntax_Error(NT_markupdecl);
2173                }
2174                else {
2175                        Advance(1);
2176                        continue;
2177                }
2178        } while (1);
2179}
2180
2181template <CodeUnit_Base C>
2182inline int ParsingEngine<C>::Parse_Name() {
2183        int name_pos = AbsPos();
2184        ScanTo(NameFollow);
2185        int lgth = AbsPos()-name_pos;
2186        char * s = copy_string(GetCodeUnitPtr(name_pos),lgth);
2187        int nameID = model_info->GlobalNameTable[s];
2188        if(nameID == 0){
2189                if (entity_Info->version == XML_1_1){
2190                        if (!is_XML11_UTF8_Name(GetCodeUnitPtr(name_pos),lgth)) Syntax_Error(NT_Name);
2191                }
2192                else if (!is_XML10_UTF8_Name(GetCodeUnitPtr(name_pos),lgth)) Syntax_Error(NT_Name);
2193                model_info->GlobalNameTable[s]=++model_info->globalNameCount;
2194                nameID = model_info->globalNameCount;
2195        }
2196        return nameID;
2197}
2198
2199
2200template <CodeUnit_Base C>
2201inline void ParsingEngine<C>::Parse_DocumentContent() {
2202#ifdef VALIDATION
2203        int final_state = Parse_ValidContent(model_info->rootModel);
2204        if (model_info->rootModel->transition_map[final_state][0]==0) {
2205                Validity_Error(vErr_elementvalid);
2206        }
2207#endif
2208#ifndef VALIDATION
2209        Parse_WF_Element();
2210        ScanTo(NonWS);
2211        while(at_Comment_Start<C>(cur()) || at_PI_Start<C>(cur()) ){
2212                if (at_Comment_Start<C>(cur()))
2213                        Parse_Comment();
2214                else 
2215                        Parse_PI();
2216                ScanTo(NonWS);
2217        }
2218        if (!at_EOF()) {
2219                Syntax_Error(NT_document);
2220        }       
2221#endif
2222}
2223
Note: See TracBrowser for help on using the repository browser.