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

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

Fixes for icXML 0.9

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