source: icXML/icXML-devel/src/icxmlc/parsers/XMLWellFormednessParser.hpp @ 3151

Last change on this file since 3151 was 3151, checked in by cameron, 6 years ago

Updates for icxmlc files.

File size: 40.5 KB
Line 
1#ifndef XMLWELLFORMEDNESSPARSER_HPP
2#define XMLWELLFORMEDNESSPARSER_HPP
3
4#include <icxmlc/XMLParser.hpp>
5#include <icxmlc/XMLNamespaceBindingSet.hpp>
6#include <icxmlc/XMLScanIterator.hpp>
7#include <icxmlc/parsers/XMLDocumentAccumulator.hpp>
8#include <icxmlc/XMLNameChars.hpp>
9#include <xercesc/framework/XMLValidityCodes.hpp>
10#include <icxmlc/XMLConfig.hpp>
11
12XERCES_CPP_NAMESPACE_BEGIN
13
14template<class ScannerType>
15class XMLWellFormednessParser
16{
17    template<class XMLScannerType> friend class XMLParserImpl;
18
19    typedef DynamicArray<size_t, INITIAL_SYMBOL_TABLE_CAPACITY> DuplicateAttributeArrayType;
20
21public:
22
23    inline XMLWellFormednessParser
24    (
25        XMLParser &                           parser
26        , const XMLSymbolTable &              symbolTable
27        , const XMLReferenceTable &           referenceTable
28        , ScannerType &                       scanner
29    )
30    : fContentStream(parser.fContentStream)
31    , fContentIdx(parser.fContentIdx)
32    , fCursorPtr(&parser.fContentStream[parser.fContentIdx])
33    , fCursorEndPtr(parser.fCursorEndPtr)
34    , fSymbolStream(parser.fSymbolStream)
35    , fSymbolIdx(0)
36    , fSymbolPtr(&fSymbolStream[0])
37    , fSymbolCount(parser.fSymbolCount)
38    , fUriCount(parser.fUriCount)
39    , fReferenceStream(parser.fReferenceStream)
40    , fReferencePtr(&parser.fReferenceStream[parser.fReferenceIdx])
41    , fReferenceCount(parser.fReferenceCount)
42    , fStringEndStream(parser.fStringEndStream)
43    , fStringEndPtr(parser.fStringEndPtr)
44    , fStringCount(parser.fStringCount)
45    , fGidStack(parser.fGidStack)
46    , fInMarkup(parser.fInMarkup)
47    , fNoMore(parser.fNoMore)
48    , fEndsWithPartialContent(parser.fEndsWithPartialContent)
49    , fElementIndex(parser.fElementIndex)
50    , fMarkupCount(parser.fMarkupCount)
51    , fElementCount(parser.fMarkupCount) // assume all of the markup items are elements
52    , fAttributeCount(0)
53    , fProcessingInstructionCount(0)
54    , fCommentCount(0)
55    , fCDATACount(0)
56    , fScope(parser.fScope)
57    , fMaxAttributeCount(parser.fMaxAttributeCount)
58    , fMaxScope(parser.fMaxScope)
59    , fSymbolTable(symbolTable)
60    , fReferenceTable(referenceTable)
61    , fScanner(scanner)
62    {
63        fEndsWithPartialContent = false;
64        fUriCount = parser.fUriIdx + parser.fSymbolCount;
65    }
66
67    inline ~XMLWellFormednessParser()
68    {
69
70    }
71
72    template<XMLParser::DocumentStateType DocStateType>   
73    void checkWellformedness(XMLDocumentAccumulator * const accumulator);
74
75    IDISA_ALWAYS_INLINE
76    void checkEntityWellformedness();
77
78private:
79
80    template<XMLParser::DocumentStateType DocStateType, bool HasDTD, size_t CheckingEntity>
81    IDISA_ALWAYS_INLINE
82    void checkWellformedness(XMLDocumentAccumulator * const accumulator);
83
84    void reportDuplicateAttribute(const gid_t elementId, const gid_t attributeId);
85
86    void reportIncompleteDocument(const size_t scope);
87
88    void reportMismatchedEndTag(const size_t scope);
89
90    IDISA_ALWAYS_INLINE
91    ptrdiff_t getStringLength();
92
93    IDISA_ALWAYS_INLINE
94    const XMLSymbol & getSymbolByPtr(const SymbolPtrType symbolPtr) const
95    {
96        return getSymbolByGid(*symbolPtr);
97    }
98
99    IDISA_ALWAYS_INLINE
100    const XMLSymbol & getSymbolByGid(const gid_t gid) const
101    {
102        return fSymbolTable[gid];
103    }
104
105    IDISA_ALWAYS_INLINE
106    void skipPastAnyEntities();
107
108    IDISA_ALWAYS_INLINE
109    void scanContentEntities();
110
111    IDISA_ALWAYS_INLINE
112    size_t addDefaultAttributes
113    (
114        const XMLElementDefaultAttribute *  potentialAttribute
115        , DuplicateAttributeArrayType &     duplicateAttributeVector
116        , AugmentedContentStream &          contentStream
117        , ContentPtrType &                  contentPtr
118        , AugmentedSymbolStream &           symbolStream
119        , SymbolPtrType &                   symbolPtr
120        , const XMLSymbol &                 element
121    );
122
123    IDISA_ALWAYS_INLINE
124    size_t addDefaultAttributes
125    (
126        const XMLElementDefaultAttribute *  potentialAttribute
127        , AugmentedContentStream &          contentStream
128        , ContentPtrType &                  contentPtr
129        , AugmentedSymbolStream &           symbolStream
130        , SymbolPtrType &                   symbolPtr
131        , const XMLSymbol &                 element
132    );
133
134    IDISA_ALWAYS_INLINE
135    void regenerateContentStream
136    (
137        AugmentedContentStream &        contentStream
138        , const ContentPtrType          contentPtr
139        , AugmentedSymbolStream &       symbolStream
140        , const SymbolPtrType           symbolPtr
141    );
142
143    IDISA_ALWAYS_INLINE
144    size_t addDefaultAttributes
145    (
146        const XMLElementDefaultAttribute *
147        , DuplicateAttributeArrayType &
148        , FakeContentStream &
149        , ContentPtrType &
150        , FakeSymbolStream &
151        , SymbolPtrType &
152        , const XMLSymbol &
153    ) {}
154
155    IDISA_ALWAYS_INLINE
156    size_t addDefaultAttributes
157    (
158        const XMLElementDefaultAttribute *
159        , FakeContentStream &
160        , ContentPtrType &
161        , FakeSymbolStream &
162        , SymbolPtrType &
163        , const XMLSymbol &
164    )  {}
165
166    IDISA_ALWAYS_INLINE
167    void regenerateContentStream(FakeContentStream &, const ContentPtrType, FakeSymbolStream &, const SymbolPtrType) {}
168
169private:
170
171    ContentStream &                     fContentStream;
172    const size_t                        fContentIdx;
173    ContentPtrType                      fCursorPtr;
174    ContentPtrType &                    fCursorEndPtr;
175
176    SymbolArray &                                               fSymbolStream;
177    const size_t                        fSymbolIdx;
178    SymbolPtrType                       fSymbolPtr;
179    size_t &                            fSymbolCount;
180    size_t &                            fUriCount;
181
182    ReferenceArray &                    fReferenceStream;
183    ReferencePtrType                    fReferencePtr;
184    size_t &                            fReferenceCount;
185
186    StringPtrArray      &                                       fStringEndStream;
187    const StringPtrArray::Type *        fStringEndPtr;
188    size_t &                            fStringCount;
189
190    XMLParser::GidStack &               fGidStack;
191
192    const bool                          fInMarkup;
193    bool &                              fEndsWithPartialContent;
194    const bool                          fNoMore;
195
196    size_t                              fElementIndex;
197    size_t                              fMarkupCount;
198    size_t                              fScope;   
199
200    size_t                              fElementCount;
201    size_t                              fAttributeCount;
202    size_t                              fProcessingInstructionCount;
203    size_t                              fCommentCount;
204    size_t                              fCDATACount;
205
206    size_t &                            fMaxAttributeCount;
207    size_t &                            fMaxScope;
208
209    const XMLSymbolTable &              fSymbolTable;
210    const XMLReferenceTable &           fReferenceTable;   
211    ScannerType &                       fScanner;
212};
213
214
215#if defined(PRINT_DEBUG_MESSAGE) && !defined(PRINT_DEBUG_IGNORE_WELL_FORMEDNESS_MESSAGES)
216void TEST_TAG_MARKUP_CHAR(const XMLCh markupChar);
217void TEST_ATTRIBUTE_MARKUP_CHAR(const XMLCh markupChar);
218#else
219#define TEST_TAG_MARKUP_CHAR(markupChar)
220#define TEST_ATTRIBUTE_MARKUP_CHAR(markupChar)
221#endif
222
223/// -----------------------------------------------------------------------------------------------------------
224
225// what if the wellformedness checker handled all DTD validation? even if schemas could be used?
226
227template<class XMLScannerType>
228template<XMLParser::DocumentStateType DocStateType, bool HasDTD, size_t CheckingEntity>
229void XMLWellFormednessParser<XMLScannerType>::checkWellformedness(XMLDocumentAccumulator * const accumulator)
230{
231    DEBUG_WELL_FORMEDNESS_MESSAGE("######################################################################");
232    DEBUG_WELL_FORMEDNESS_MESSAGE
233    (
234        "BEGIN " << (DocStateType == XMLParser::Element ? "ELEMENT" : "MISCELLANEOUS") << " WELL-FORMEDNESS SCAN:" << (HasDTD ? " (DTD)" : "") << ' ' << fMarkupCount
235    );
236    DEBUG_WELL_FORMEDNESS_MESSAGE("######################################################################");
237
238    DuplicateAttributeArrayType attributeMarkupCountVector(fSymbolTable.count());
239
240    // depending on the ScanType, decide whether to create and augmented stream or reuse the existing one.
241    // NOTE: all character references and predefined entities are resolved within the CharacterSetAdapter.
242    // So the only way we can have any remaining references is if we have a DTD with general entities.
243
244    typename ContentStreamA<HasDTD>::Type contentStream(fContentStream);
245    typename SymbolStreamA<HasDTD>::Type symbolStream(fSymbolStream);
246    // typename DelimiterStreamA<HasDTD>::Type delimiterStream(fStringEndStream);
247
248    ContentPtrType lastContentPtr = fCursorPtr;
249    SymbolPtrType lastSymbolPtr = fSymbolPtr;
250
251    XMLCh markupChar;
252
253    // TODO: what if the wellformedness checker rearranged the symbols so elements always come after any attributes?
254    // might simplify the code of later passes and eliminate the unnessary 'goto'?
255
256    switch (fInMarkup)
257    {
258        do
259        {
260    case 0: DEBUG_WELL_FORMEDNESS_MESSAGE(" << atContent=" << (fCursorPtr - &fContentStream[0]) << ':' << fCursorPtr )
261            if ((DocStateType == XMLParser::Prolog) || (DocStateType == XMLParser::Miscellaneous))
262            {
263                // wellformedness constraint: content can only exist between start and end tag pairs.
264                const XMLCh * const endOfContent = *fStringEndPtr++;
265                const size_t length = endOfContent - fCursorPtr;
266                if (likely(*endOfContent == chNull && XMLStringU::isWhitespace(fCursorPtr, length)))
267                {
268                    accumulator->writeIgnorableWhitespace(fCursorPtr, length);
269                }
270                else
271                {
272                    fScanner.emitError(XMLErrs::ExpectedCommentOrPI);
273                }
274                fCursorPtr = endOfContent;
275            }
276            else if (DocStateType == XMLParser::Element)
277            {
278                fCursorPtr = *fStringEndPtr++;
279                if (HasDTD)
280                {
281                    // if we found a reference, the reference itself must be legal or the CSA would have reported it
282                    scanContentEntities();
283                }
284            }
285            fCursorPtr++;
286    case 1:     if (unlikely(fMarkupCount == 0))
287            {
288                fEndsWithPartialContent = (fCursorPtr[-1] == 0xFFFF);
289                break;
290            }
291            // process the next markup element
292            markupChar = *fCursorPtr;
293
294            DEBUG_WELL_FORMEDNESS_MESSAGE(" << atMarkup=" << (fCursorPtr - &fContentStream[0]) << ':' << markupChar );
295
296            TEST_TAG_MARKUP_CHAR(markupChar);
297
298            switch (markupChar & MarkupMask)
299            {
300                /// ------------------------------------------------------------------------ ///
301                case StartTagWithAttributes:
302                    if (DocStateType == XMLParser::Prolog)
303                    {
304                        return;
305                    }
306                    else if (DocStateType == XMLParser::Miscellaneous)
307                    {
308                        fScanner.emitError(XMLErrs::ExpectedCommentOrPI);
309                    }
310                    else if (DocStateType == XMLParser::Element)
311                    {
312                        size_t attCount = 0;
313
314                        const gid_t elementGid = *fSymbolPtr++;
315
316                        do
317                        {
318                            /// --------------------------------------------------------------------------------------------------------------
319                            /// DOCUMENT ATTRIBUTE RESOLUTION
320                            /// --------------------------------------------------------------------------------------------------------------
321
322                            ++attCount;
323
324                            const gid_t attributeGid = *fSymbolPtr++;
325
326                            // extract the next attribute ...
327
328                            // duplicate attribute check: if we have observed the attribute symbol in this
329                            // element, then it must have been used within the current attribute list; if so,
330                            // it's a duplicate symbol.
331
332                            if (unlikely(attributeMarkupCountVector[attributeGid] == fMarkupCount))
333                            {
334                                reportDuplicateAttribute(elementGid, attributeGid);
335                            }
336                            else
337                            {
338                                attributeMarkupCountVector[attributeGid] = fMarkupCount;
339                            }
340
341                            DEBUG_WELL_FORMEDNESS_MESSAGE(" -- atAttribute" << attCount << ' ' << getSymbolByGid(attributeGid) << ':' << attributeGid << '=' << (fCursorPtr - &fContentStream[0]) << ':' << (fCursorPtr + 1))
342
343                            fCursorPtr = *fStringEndPtr++;
344                            if (HasDTD)
345                            {
346                                // if we found a reference, the reference itself must be legal or the CSA would have reported it
347                                skipPastAnyEntities();
348                            }
349
350                            // if the next markup char's value is 2 (10), then we're at the end of the start/empty tag
351                            markupChar = *++fCursorPtr;
352
353                            TEST_ATTRIBUTE_MARKUP_CHAR(markupChar);
354                        }
355                        while ((markupChar & MarkupMask) == Attribute);
356
357                        /// --------------------------------------------------------------------------------------------------------------
358                        /// DEFAULT ATTRIBUTE RESOLUTION
359                        /// --------------------------------------------------------------------------------------------------------------
360
361                        if (HasDTD)
362                        {
363                            const XMLSymbol & element = getSymbolByGid(elementGid);
364
365                            if (unlikely(element.hasDefaultAttributes()))
366                            {
367                                const size_t defaultAttributeCount =
368                                    addDefaultAttributes
369                                    (
370                                        element.getDefaultAttributeList()
371                                        , attributeMarkupCountVector
372                                        , contentStream
373                                        , lastContentPtr
374                                        , symbolStream
375                                        , lastSymbolPtr
376                                        , element
377                                    );
378
379                                fStringCount += defaultAttributeCount;
380                                attCount += defaultAttributeCount;
381                            }
382                        }
383
384                        if (unlikely(fMaxAttributeCount < attCount))
385                        {
386                            fMaxAttributeCount = attCount;
387                        }
388
389                        fAttributeCount += attCount;
390
391                        ++fCursorPtr;
392
393                        /// --------------------------------------------------------------------------------------------------------------
394
395                        const bool isEmpty = (markupChar == EmptyTag);
396
397                        DEBUG_WELL_FORMEDNESS_MESSAGE
398                        (
399                            (isEmpty ? " >> atEmptyTag " : " >> atStartTag ") << fSymbolTable[elementGid]
400                            << " gid=" << elementGid
401                            << " markupCount=" << fMarkupCount
402                            << " scope=" << fScope
403                        )
404
405                        // outdent scope by one if and only if this element is an empty tag
406                        if (likely(!isEmpty))
407                        {
408                            if (unlikely(fScope >= fMaxScope))
409                            {
410                                fMaxScope = fScope + 1;
411                                if (unlikely(fMaxScope >= fGidStack.capacity()))
412                                {
413                                    fGidStack.resizeToFit(fScope, fMaxScope);
414                                }
415                            }
416                            fGidStack[fScope++] = elementGid;
417                        }
418                        else if (unlikely(fScope == 0)) // root element
419                        {
420                            fMarkupCount--;
421                            goto scope_exit;
422                        }                       
423                    }
424                    break;
425                /// ------------------------------------------------------------------------ ///
426                case StartTagWithoutAttributes:
427                    if (DocStateType == XMLParser::Prolog)
428                    {
429                        return;
430                    }
431                    else if (DocStateType == XMLParser::Miscellaneous)
432                    {
433                        fScanner.emitError(XMLErrs::ExpectedCommentOrPI);
434                    }
435                    else if (DocStateType == XMLParser::Element)
436                    {
437                        const gid_t elementGid = *fSymbolPtr++;
438
439                        if (HasDTD)
440                        {
441                            const XMLSymbol & element = getSymbolByGid(elementGid);
442
443                            if (unlikely(element.hasDefaultAttributes()))
444                            {
445                                const size_t defaultAttributeCount =
446                                    addDefaultAttributes
447                                    (
448                                        element.getDefaultAttributeList()
449                                        , contentStream
450                                        , lastContentPtr
451                                        , symbolStream
452                                        , lastSymbolPtr
453                                        , element
454                                    );
455
456                                if (unlikely(fMaxAttributeCount < defaultAttributeCount))
457                                {
458                                    fMaxAttributeCount = defaultAttributeCount;
459                                }
460                                fStringCount += defaultAttributeCount;
461                                fAttributeCount += defaultAttributeCount;
462                            }
463                        }
464
465                        ++fCursorPtr;
466
467                        const bool isEmpty = (markupChar == EmptyTag);
468
469                        DEBUG_WELL_FORMEDNESS_MESSAGE
470                        (
471                            (isEmpty ? " >> atEmptyTag " : " >> atStartTag ") << fSymbolTable[elementGid]
472                            << " gid=" << elementGid
473                            << " markupCount=" << fMarkupCount
474                            << " scope=" << fScope
475                        )
476
477                        if (likely(!isEmpty))
478                        {                           
479                            if (unlikely(fScope >= fMaxScope))
480                            {
481                                fMaxScope = fScope + 1;
482                                if (unlikely(fMaxScope == fGidStack.capacity()))
483                                {
484                                    fGidStack.expand(fGidStack.capacity());
485                                }
486                            }
487                            fGidStack[fScope++] = elementGid;
488                        }
489                        else if (unlikely(fScope == 0)) // root element
490                        {
491                            fMarkupCount--;
492                            goto scope_exit;
493                        }
494                    }
495                    break;
496                /// ------------------------------------------------------------------------ ///
497                case EndTag:
498                    if (DocStateType == XMLParser::Prolog)
499                    {
500                        fScanner.emitError(XMLErrs::MoreEndThanStartTags);
501                    }
502                    else if (DocStateType == XMLParser::Miscellaneous)
503                    {
504                        fScanner.emitError(XMLErrs::ExpectedCommentOrPI);
505                    }
506                    else if (DocStateType == XMLParser::Element)
507                    {
508                        fElementCount--;
509
510                        const gid_t elementGid = *fSymbolPtr++;
511
512                        DEBUG_WELL_FORMEDNESS_MESSAGE
513                        (
514                            " >> atEndTag " << getSymbolByGid(elementGid)
515                            << " gid=" << elementGid
516                            << " markupCount=" << fMarkupCount
517                            << " scope=" << fScope
518                        )
519
520                        // check to be sure that we can "pop" the element off the stack
521                        if (unlikely(fScope == CheckingEntity))
522                        {
523                            fScanner.emitError(CheckingEntity ? XMLErrs::PartialTagMarkupError : XMLErrs::MoreEndThanStartTags);
524                        }
525                        else
526                        {
527                            // now check that this is the element we were looking for...
528                            if (unlikely(fGidStack[--fScope] != elementGid))
529                            {
530                                // check the uri and local parts? would that be legal?
531                                reportMismatchedEndTag(fScope);
532                            }
533                            else if (unlikely(fScope == 0)) // root element
534                            {
535                                fMarkupCount--;
536                                goto scope_exit;
537                            }
538                        }
539                    }
540                    ++fCursorPtr;
541                    break;
542                /// ------------------------------------------------------------------------ ///
543                case ProcessingInstruction:
544                    {
545                        fElementCount--;
546                        fProcessingInstructionCount++;
547
548                        const XMLCh * target = ++fCursorPtr;
549
550                        const size_t targetLength = getStringLength();
551
552                        DEBUG_WELL_FORMEDNESS_MESSAGE
553                        (
554                            " >> atProcessingInstruction " << targetLength << ':' << target
555                            << " markupCount=" << fMarkupCount
556                        )
557
558                        // XML (5th edition): 2.6 Processing Instructions
559                        //      PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
560                        if (unlikely(!XMLNameChar::test(target, targetLength)))
561                        {
562                            fScanner.emitError(XMLErrs::PINameExpected);
563                        }
564                        else if (unlikely(XMLStringU::isXML(target)))
565                        {
566                            fScanner.emitError((CheckingEntity && fScope == CheckingEntity) ? XMLErrs::TextDeclNotLegalHere : XMLErrs::NoPIStartsWithXML);
567                        }
568
569                        // XML Namespaces: 7 Conformance of Documents:
570                        // No entity names, processing instruction targets, or notation names contain any colons.
571                        // TODO: blend this into the XMLNameChar::test function through a "constant" parameter
572                        if (likely(fScanner.getDoNamespaces()))
573                        {
574                            if (unlikely(XMLStringU::indexOf<chColon>(target, targetLength) != -1))
575                            {
576                                fScanner.emitError(XMLErrs::ColonNotLegalWithNS);
577                            }
578                        }
579
580                        fCursorPtr += targetLength + 1;
581
582                        const size_t length = getStringLength();
583
584                        if ((DocStateType == XMLParser::Prolog) || (DocStateType == XMLParser::Miscellaneous))
585                        {
586                            const_cast<WritableContentPtrType>(fCursorPtr)[length - 1] = chNull;
587
588                            fScanner.handlePI(target, fCursorPtr, length - 1, *accumulator);
589                        }
590
591                        fCursorPtr += length + 1;
592                    }
593                    break;
594                /// ------------------------------------------------------------------------ ///
595                case Comment:
596                    {
597                        //    v
598                        // <!--COMMENT-->
599
600                        ++fCursorPtr;
601
602                        fElementCount--;
603                        fCommentCount++;
604
605                        const size_t length = getStringLength();
606
607                        DEBUG_WELL_FORMEDNESS_MESSAGE(" --- atComment=" << length << ':' << fCursorPtr);
608
609                        //              v
610                        // <!--COMMENT-->
611
612                        if ((DocStateType == XMLParser::Prolog) || (DocStateType == XMLParser::Miscellaneous))
613                        {
614                            // When we get a comment, the content string will read "-COMMENT--"; we offset the
615                            // start position and length to adjust for this and replace the first "-" in the trailing
616                            // "--" with null to terminate the string so the end user only receives "COMMENT".
617
618                            const_cast<WritableContentPtrType>(fCursorPtr)[length - 2] = chNull;                           
619
620                            fScanner.handleComment(fCursorPtr, length - 2, *accumulator);
621                        }
622
623                        fCursorPtr += length + 1;
624                    }
625                    break;
626                /// ------------------------------------------------------------------------ ///
627                case CDATA:
628                    if (DocStateType == XMLParser::Element)
629                    {
630                        const XMLCh * cdata = ++fCursorPtr;
631
632                        fElementCount--;
633                        fCDATACount++;
634
635                        //   v
636                        // <![CDATA[ ... ]]>
637
638                        if (unlikely(!XMLStringU::isCDATA(cdata)))
639                        {
640                            // "CDATA[" check failed
641                            fScanner.emitError(XMLErrs::ExpectedCommentOrCDATA);
642                        }
643
644                        fCursorPtr += 6;
645
646
647                        //                 v
648                        // <![CDATA[ ... ]]>
649                        const size_t length = getStringLength();
650
651                        DEBUG_WELL_FORMEDNESS_MESSAGE(" --- atCDATA=" << length << ':' << fCursorPtr);
652
653
654                        fCursorPtr += length + 1;
655                    }
656                    else
657                    {
658                        fScanner.emitError(XMLErrs::ExpectedCommentOrPI);
659                    }
660                    break;
661
662                default:
663                    UNREACHABLE
664            /// ------------------------------------------------------------------------ ///
665            }
666            fMarkupCount--;
667        }
668        while (1);
669        break;
670    default:
671        assert (!"INVALID TAG MARKUP CHARACTER DETECTED!");
672        UNREACHABLE
673    }
674
675scope_exit:
676
677    // calculate max element / child depth increase?   
678
679    /**
680    If we have augmented the streams in some way, the following code will copy them back over the original streams.
681    **/
682
683    if (HasDTD && (unlikely(contentStream.pos() != 0)))
684    {
685        regenerateContentStream(contentStream, lastContentPtr, symbolStream, lastSymbolPtr);
686    }
687
688
689}
690
691/// --------------------------------------------------------------------------------------------------------------------------------
692
693template<class ScannerType>
694void XMLWellFormednessParser<ScannerType>::
695skipPastAnyEntities()
696{
697    while (unlikely(*fCursorPtr == Entity))
698    {
699        DEBUG_WELL_FORMEDNESS_MESSAGE(" -- skipping " << fReferenceTable[*fReferencePtr])
700        *fReferencePtr++;
701        // skip to the next delimiter
702        fCursorPtr = *fStringEndPtr++;
703    }
704}
705
706template<class ScannerType>
707void XMLWellFormednessParser<ScannerType>::
708scanContentEntities()
709{
710    while (unlikely(*fCursorPtr == Entity))
711    {
712        const XMLReplacementText & ref = fReferenceTable[*fReferencePtr++];
713        DEBUG_WELL_FORMEDNESS_MESSAGE(" -- accumulating ref: " << ref)       
714        // increment the uri stream size, max attribute count, and max scope appropriately
715        fMaxAttributeCount = max<size_t>(fMaxAttributeCount, ref.fMaxAttributeCount);
716        fMaxScope = max<size_t>(fMaxScope, fScope + ref.fMaxScope);
717        fUriCount += ref.fSymbolCount;
718        fElementCount += ref.fElementCount;
719        fAttributeCount += ref.fAttributeCount;
720        fProcessingInstructionCount += ref.fProcessingInstructionCount;
721        fCommentCount += ref.fCommentCount;
722        fCDATACount += ref.fCDATACount;
723        // skip to the next delimiter
724        fCursorPtr = *fStringEndPtr++;
725    }
726}
727
728/// -------------------------------------------------------------------------------------------------------------------
729/// DEFAULT ATTRIBUTE RESOLUTION
730/// -------------------------------------------------------------------------------------------------------------------
731
732template<class ScannerType>
733size_t XMLWellFormednessParser<ScannerType>::
734addDefaultAttributes
735(
736    const XMLElementDefaultAttribute *  potentialAttribute
737    , DuplicateAttributeArrayType &     duplicateAttributeVector
738    , AugmentedContentStream &          contentStream
739    , ContentPtrType &                  contentPtr
740    , AugmentedSymbolStream &           symbolStream
741    , SymbolPtrType &                   symbolPtr
742    , const XMLSymbol &                 element
743)
744{
745    bool add = false;
746    size_t attCount = 0;
747    gid_t attributeGid;
748
749    // scan to see if at least one attribute will be defaulted in
750    do
751    {
752        attributeGid = potentialAttribute->getGid();
753        if (duplicateAttributeVector[attributeGid] != fMarkupCount)
754        {
755            add = true;
756            break;
757        }
758        potentialAttribute = potentialAttribute->getNext();
759    }
760    while (potentialAttribute);
761
762    if (add)
763    {
764        // yes; we're defaulting one in. buffer the original content and append the attribute.
765        if (fCursorPtr > contentPtr)
766        {
767            // copy over the content stream
768            contentStream.appendAndIncrement(contentPtr, fCursorPtr - contentPtr);
769        }
770
771        if (fSymbolPtr > symbolPtr)
772        {
773            // copy all symbols since we last augmented the symbol stream, including the element gid.
774            symbolStream.appendAndIncrement(symbolPtr, fSymbolPtr - symbolPtr);
775        }
776
777        do
778        {
779            if (fScanner.preValidateDefaultAttribute(*(element.getQName()), *(getSymbolByGid(attributeGid).getQName()), potentialAttribute->isExternal()))
780            {
781                attCount++;
782                // insert the new content
783                contentStream.add(DefaultAttribute);
784                const XMLCh * value = potentialAttribute->getValue();
785                const size_t length = potentialAttribute->getValueLen();
786                contentStream.append(value, length + 1); // also insert the trailing Null
787                // insert the default attribute symbol gid
788                symbolStream.add(attributeGid);
789
790                DEBUG_WELL_FORMEDNESS_MESSAGE(" -- atDefAttribute" << attCount << ' ' << getSymbolByGid(attributeGid) << ':' << attributeGid << '=' << value)
791            }
792
793            for (;;)
794            {
795                potentialAttribute = potentialAttribute->getNext();
796                if (!potentialAttribute)
797                {
798                    add = false;
799                    break;
800                }
801
802                attributeGid = potentialAttribute->getGid();
803                if (duplicateAttributeVector[attributeGid] != fMarkupCount)
804                {
805                    // add = true;
806                    break;
807                }
808            }
809        }
810        while (add);
811    }
812
813    return attCount;
814}
815
816/// ------------------------------------------------------------------------------------------------------------------
817
818template<class ScannerType>
819size_t XMLWellFormednessParser<ScannerType>::
820addDefaultAttributes
821(
822    const XMLElementDefaultAttribute *  defaultAttribute
823    , AugmentedContentStream &          contentStream
824    , ContentPtrType &                  contentPtr
825    , AugmentedSymbolStream &           symbolStream
826    , SymbolPtrType &                   symbolPtr
827    , const XMLSymbol &                 element
828)
829{
830    if (fCursorPtr > contentPtr)
831    {
832        // copy over the content stream
833        contentStream.appendAndIncrement(contentPtr, fCursorPtr - contentPtr);
834    }
835
836    if (fSymbolPtr > symbolPtr)
837    {
838        // copy all symbols since we last augmented the symbol stream, including the element gid.
839        symbolStream.appendAndIncrement(symbolPtr, fSymbolPtr - symbolPtr);
840    }
841
842    // by contract, we know that a default attribute cannot contain duplicate attributes; just add all of them.
843    size_t attCount = 0;
844    do
845    {
846        const gid_t attributeGid = defaultAttribute->getGid();
847        if (fScanner.preValidateDefaultAttribute(*(element.getQName()), *(getSymbolByGid(attributeGid).getQName()), defaultAttribute->isExternal()))
848        {
849            attCount++;
850            // insert the new content
851            contentStream.add(DefaultAttribute);
852            const XMLCh * value = defaultAttribute->getValue();
853            const size_t length = defaultAttribute->getValueLen();
854            contentStream.append(value, length + 1); // also insert the trailing Null
855            // insert the default attribute symbol gid
856            symbolStream.add(attributeGid);
857
858            DEBUG_WELL_FORMEDNESS_MESSAGE(" -- atDefAttribute" << attCount << ' ' << getSymbolByGid(attributeGid) << ':' << defaultAttribute->getGid() << '=' << value)
859        }
860
861        defaultAttribute = defaultAttribute->getNext();
862    }
863    while (defaultAttribute);
864
865    return attCount;
866}
867
868
869/// ------------------------------------------------------------------------------------------------------------------
870
871template<class XMLScannerType>
872void XMLWellFormednessParser<XMLScannerType>::regenerateContentStream
873(
874    AugmentedContentStream &        contentStream
875    , const ContentPtrType          contentPtr
876    , AugmentedSymbolStream &       symbolStream
877    , const SymbolPtrType           symbolPtr
878)
879{
880    // TODO: change the function so it claims the expanded array if the temp streams had to expand rather than simply creating a new one?
881
882    // append the remaining content to the augmented stream
883    const size_t remainingContent = fCursorEndPtr - contentPtr;
884    const size_t contentIdx = fContentIdx + contentStream.pos();
885    fContentStream.move(contentPtr, contentIdx, remainingContent);
886    fContentStream.copy(&contentStream[0], fContentIdx, contentStream.pos());   
887    const size_t length = contentIdx + remainingContent;
888    fCursorEndPtr = &fContentStream[length];
889    fContentStream[length] = 0xFFFF;
890
891    // generate the delimiter stream
892    XMLChIterator2<chNull, Entity> delimiterItr(&fContentStream[0], length);
893    if (unlikely(fStringCount >= fStringEndStream.capacity()))
894    {
895        fStringEndStream.resizeToFit(0, fStringCount);
896    }
897
898    size_t stringCount = 0;
899    while (delimiterItr.next())
900    {
901        fStringEndStream[stringCount++] = &fContentStream[delimiterItr.pos()];
902    }
903    fStringEndStream[stringCount] = fCursorEndPtr;
904    fStringCount = stringCount;
905
906
907    // copy over the symbol stream
908    const size_t remainingSymbols = &fSymbolStream[fSymbolCount] - symbolPtr;
909    const size_t symbolIdx = symbolStream.pos();
910    fSymbolStream.move(symbolPtr, symbolIdx, remainingSymbols);
911    fSymbolStream.copy(&symbolStream[0], 0, symbolIdx);
912    fSymbolCount = symbolIdx + remainingSymbols;
913}
914
915/// ------------------------------------------------------------------------------------------------------------------
916
917template<class XMLScannerType>
918template<XMLParser::DocumentStateType DocStateType>
919void XMLWellFormednessParser<XMLScannerType>::checkWellformedness(XMLDocumentAccumulator *const accumulator)
920{
921    // choose the most optimal method to check the well-formedness of this document
922    // and potentially generate the augmented streams.
923
924    if (DocStateType == XMLParser::Element)
925    {             
926        if (unlikely(fScanner.getHasInternalOrExternalDTD()))
927        {
928            checkWellformedness<XMLParser::Element, true, 0>(accumulator);
929        }
930        else
931        {
932            checkWellformedness<XMLParser::Element, false, 0>(accumulator);
933        }
934
935        // test to be sure that we aren't missing end tags
936        if (unlikely(fNoMore && fScope != 0))
937        {
938            reportIncompleteDocument(fScope);
939        }
940    }
941    else
942    {
943        checkWellformedness<DocStateType, false, 0>(accumulator);
944    }
945}
946
947/// ------------------------------------------------------------------------------------------------------------------
948
949template<class XMLScannerType>
950void XMLWellFormednessParser<XMLScannerType>::checkEntityWellformedness()
951{
952    if (unlikely(fScope == 0 && !fInMarkup))
953    {
954        // if we're checking entity well-formedness, assume that we start within a scope in the source document.
955        // note: if for any reason the initial scope has to be changed, make sure that the "CheckingEntity" parameter
956        // is set to the initial scope.
957        fScope = 1;
958    }
959
960    checkWellformedness<XMLParser::Element, true, 1>(NULL);
961
962    // test to be sure that that we have exactly as many start tags as we do end tags
963    // and that the entity entity has been parsed successfully.
964    if (unlikely(fMarkupCount != 0 || (fNoMore && fScope != 1)))
965    {
966        fScanner.emitError(XMLErrs::PartialTagMarkupError);
967    }
968}
969
970/// ------------------------------------------------------------------------------------------------------------------
971
972template<class XMLScannerType>
973void XMLWellFormednessParser<XMLScannerType>::reportDuplicateAttribute(const gid_t elementId, const gid_t attributeId)
974{
975    fScanner.emitError(XMLErrs::AttrAlreadyUsedInSTag, getSymbolByGid(attributeId).getName(), getSymbolByGid(elementId).getName());
976}
977
978template<class XMLScannerType>
979void XMLWellFormednessParser<XMLScannerType>::reportIncompleteDocument(const size_t scope)
980{
981    fScanner.emitError(XMLErrs::EndedWithTagsOnStack, getSymbolByGid(fGidStack[scope - 1]).getName());
982}
983
984template<class XMLScannerType>
985void XMLWellFormednessParser<XMLScannerType>::reportMismatchedEndTag(const size_t scope)
986{
987    fScanner.emitError(XMLErrs::ExpectedEndOfTagX, getSymbolByGid(fGidStack[scope]).getName());
988}
989
990/// ------------------------------------------------------------------------------------------------------------------
991
992template<class XMLScannerType>
993ptrdiff_t XMLWellFormednessParser<XMLScannerType>::getStringLength()
994{
995    #ifdef PRINT_DEBUG_MESSAGE
996    assert (fCursorPtr <= *fStringEndPtr);
997    assert (&fContentStream[0] <= fCursorPtr);
998    assert (*fStringEndPtr < fCursorEndPtr);
999    #endif
1000
1001    return *fStringEndPtr++ - fCursorPtr;
1002}
1003
1004/// ------------------------------------------------------------------------------------------------------------------
1005
1006#if defined(PRINT_DEBUG_MESSAGE) && !defined(PRINT_DEBUG_IGNORE_WELL_FORMEDNESS_MESSAGES)
1007inline void TEST_TAG_MARKUP_CHAR(const XMLCh markupChar)
1008{
1009    switch (markupChar)
1010    {
1011        case StartTagWithAttributes:
1012        case DefaultAttribute:
1013        case StartTagWithoutAttributes:
1014        case EmptyTag:
1015        case EndTag:
1016        case ProcessingInstruction:
1017        case Comment:
1018        case CDATA:
1019            break;
1020        default:
1021            DEBUG_WELL_FORMEDNESS_MESSAGE("ERROR! UNKNOWN MARKUP CHAR: " << markupChar);
1022            exit(-1);
1023    }
1024}
1025#else
1026#undef TEST_TAG_MARKUP_CHAR
1027#endif
1028
1029
1030#if defined(PRINT_DEBUG_MESSAGE) && !defined(PRINT_DEBUG_IGNORE_WELL_FORMEDNESS_MESSAGES)
1031inline void TEST_ATTRIBUTE_MARKUP_CHAR(const XMLCh markupChar)
1032{
1033    switch (markupChar)
1034    {
1035        case StartTagWithAttributes:
1036        case StartTagWithoutAttributes:
1037        case DefaultAttribute:
1038        case EmptyTag:
1039            break;
1040        case EndTag:
1041        case ProcessingInstruction:
1042        case Comment:
1043        case CDATA:
1044            DEBUG_WELL_FORMEDNESS_MESSAGE("ERROR! UNEXPECTED ATTRIBUTE MARKUP CHAR: " << markupChar);
1045            exit(-1);
1046            break;
1047        default:
1048            DEBUG_WELL_FORMEDNESS_MESSAGE("ERROR! UNKNOWN ATTRIBUTE MARKUP CHAR: " << markupChar);
1049            exit(-1);
1050    }
1051}
1052#else
1053#undef TEST_ATTRIBUTE_MARKUP_CHAR
1054#endif
1055
1056
1057XERCES_CPP_NAMESPACE_END
1058
1059#endif // XMLWELLFORMEDNESSPARSER_HPP
Note: See TracBrowser for help on using the repository browser.