source: trunk/src/engine.c @ 156

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

Content model validation with recursive parsers; error messages.

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