source: icXML/icXML-devel/src/icxmlc/XMLParserImpl.c @ 2720

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

Initial check-in of icXML 0.8 source files

File size: 38.7 KB
Line 
1/*
2 *  Copyright © 2012 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icXML is a trademark of International Characters.
5 */
6
7/*
8 * @author Nigel Medforth, nigelm -at- interational-characters.com
9 * @version $Id: XMLParserImpl.c 207 2012-12-02 20:38:22Z robc $
10 *
11 */
12
13#include <icxmlc/XMLParserImpl.hpp>
14#include <xercesc/util/TransService.hpp>
15
16XERCES_CPP_NAMESPACE_BEGIN
17
18#define XML_PARSER_IMPL(retType) \
19        template<class XMLScannerType> \
20        retType \
21        XMLParserImpl<XMLScannerType>
22
23#define XML_PARSER_IMPL_WITH_DOCUMENT_STATE_PARAMS(retType) \
24        template<class XMLScannerType> \
25        template<XMLParser::DocumentStateType docStateType> \
26        retType \
27        XMLParserImpl<XMLScannerType>
28
29// ---------------------------------------------------------------------------------------------------------
30
31XML_PARSER_IMPL(void)::
32init
33(
34        XMLCharacterSetAdapter *        adapter
35        , XMLTranscoder *                       transcoder
36        , const XMLFileLoc                      line
37        , const XMLFileLoc                      column
38    , const XMLVersion          /* version */
39)
40{
41        // reset the curr and next line col trackers to the actual position
42        fCurrLineCol.set(line, column);
43        fCharacterSetAdapter = adapter;
44        fSymbolTable.setTranscoder(transcoder);
45        adapter->init(fScanner, &fSymbolTable, fCurrLineCol);
46        // registerSegFaultHandler();
47}
48
49// ---------------------------------------------------------------------------------------------------------
50
51XML_PARSER_IMPL(void)::
52preScanDocumentPage
53(
54        XMLByte                                 *       rawByteBuf
55        , const XMLSize_t                       rawBytesAvail
56        , const bool                            noMore
57        , XMLReader                             *       reader
58)
59{
60        /** ---------------------------------- BEGIN PARALLEL XML PARSING ---------------------------------- **/
61
62        DEBUG_TRANSITION_MESSAGE("######################################################################");
63        DEBUG_TRANSITION_MESSAGE("BEGIN XML PARSING SCAN: avail=" << rawBytesAvail << " noMore=" << noMore);
64        DEBUG_TRANSITION_MESSAGE("######################################################################");
65
66        fRawBytesAvail = rawBytesAvail;
67    fNoMore = noMore;
68
69        unsigned int bytesEaten;
70
71        fCursorEndPtr =
72                fCharacterSetAdapter->parse
73                (
74                        rawByteBuf
75                        , fRawDataOffset
76                        , fRawBytesAvail
77                        , noMore
78                        , fContentBuf
79                        , (fCursorPtr - &fContentBuf[0]) // contentOffset
80                        , fMarkupCount
81                        , fSymbolArray
82                        , fSymbolCount
83                        , fStringEndPtr
84                        , fStringCount
85                        , fNextLineCol
86                        , &fNewLineOrSkipMaskStream[fLineColStartIndex]
87                        , &fDelMaskStream[fLineColStartIndex]
88                        , fIncompleteMarkupBytes
89                        , fUnusedSymbols
90                        , fUnusedContent
91                        , bytesEaten
92                );
93
94        fSymbolIdx = 0;
95        fCursorPtr = &fContentBuf[0];
96        fCurrentStringEndPtr = &fStringEndPtr[0];
97
98        /** ----------------------------------- BUFFER SYMBOL STREAM ----------------------------------- **/
99
100        if (likely(!noMore))
101        {
102                // what's the earliest symbol position that we need to copy back? all data after
103                // this point must be copied back and will not be modified or inspected when
104                // parsing the next document page.
105
106                if (bytesEaten == XMLReader::kRawBufSize)
107                {
108                        fRawDataOffset = 0;
109                        reader->refreshRawBuffer(XMLReader::kRawBufSize, 0);
110                }
111                else
112                {
113                        // NOTE: the utf16 issue is probably here; its doing a copyback but does not
114                        // realize that a 128-bit bitblock is actually 256 bytes of raw data.
115                        const size_t blockSize = BLOCK_SIZE * fCharacterSetAdapter->getCodeUnitSize();
116                        fRawDataOffset = (fRawBytesAvail - bytesEaten + (blockSize - 1)) & ~(blockSize - 1);
117                        reader->refreshRawBuffer(bytesEaten, bytesEaten & (blockSize - 1));
118                }
119        }
120
121        /** ----------------------------------- BEGIN NAMESPACE SCAN ----------------------------------- **/
122
123        if (fScanner->getDoNamespaces())
124        {
125                resolveDocumentPageNamespaces();
126        }
127
128        /** ----------------------------------- BEGIN VALIDATION SCAN ----------------------------------- **/
129
130        // TODO: currently the scanMarkup and scanContent functions call the Scanner functions that both
131        // perform Element/Attribute validation and emit the final element/attribute lists to the user. If we
132        // remove the emit feature from those functions and instead create a third "output" pass, we could
133        // simply store the resolved ElemDecl and AttDefs in a void* list and have validation be its own stage.
134
135}
136
137// -------------------------------------------------------------------------------------------
138
139/**
140Scan the prolog portion of the document, which includes everything before the root element
141including the DTD subsets. Returns true if it successfully found the end of the prolog.
142(i.e., no more data is required to complete it.)
143**/
144XML_PARSER_IMPL(bool)::
145scanProlog()
146{
147    DEBUG_TRANSITION_MESSAGE(" ---------------------------- SCANNING PROLOG -------------------------------");
148
149        int r;
150        switch (fInMarkup)
151        {
152                case 0:     for (;;)
153                                        {
154                                                size_t length;
155                        r = scanContent<XMLParser::Prolog>(length);
156                                                if (r) break;
157
158        case 1:         r = scanMarkup<XMLParser::Prolog>();
159                                                if (r) break;
160                                        }
161                                        break;
162
163                default:    UNREACHABLE
164        }
165
166    return (r == XMLParser::EndOfPage);
167}
168
169// -------------------------------------------------------------------------------------------
170
171XML_PARSER_IMPL(bool)::
172scanDocumentPage()
173{
174        DEBUG_TRANSITION_MESSAGE("######################################################################");
175        DEBUG_TRANSITION_MESSAGE("BEGIN SCAN DOCUMENT PAGE:");
176        DEBUG_TRANSITION_MESSAGE("######################################################################");
177
178    XMLParser::XMLScanState retVal;
179        switch (fInMarkup)
180        {
181                case 0:     for (;;)
182                                        {
183                                                size_t length;
184                        retVal = scanContent<XMLParser::Element>(length);
185                        if (retVal) break;
186
187        case 1:                 retVal = scanMarkup<XMLParser::Element>();
188                        if (retVal) break;
189                                        }
190                                        break;
191
192                default:    UNREACHABLE
193        }
194
195    if (unlikely(retVal == XMLParser::EndOfDocumentSection && fScope != 0))
196    {
197        fScanner->emitError(XMLErrs::EndedWithTagsOnStack, fElement[fElementIndex]->getRawName());
198    }
199
200    return (retVal == XMLParser::EndOfPage);
201}
202
203// -------------------------------------------------------------------------------------------
204
205/** This function automatically sends the next piece of content / markup to the
206        appropriate scanner event handler. If it cannot complete a particular piece
207        of content or markup, it returns false.
208 **/
209XML_PARSER_IMPL(XMLParser::XMLScanState)::
210scanNext()
211{
212    XMLParser::XMLScanState retVal;
213        switch (fInMarkup)
214        {
215                case 0:     size_t length;
216                    retVal = scanContent<XMLParser::Element>(length);
217                    if (retVal) break;
218                                        fInMarkup = 1;
219                                        // if we obtained a zero-length content string, just fall through
220                                        // and grab the next piece of markup instead.
221                                        if (length) break;
222
223        case 1:     retVal = scanMarkup<XMLParser::Element>();
224                    if (retVal) break;
225                                        fInMarkup = 0;
226                                        break;
227
228                default:    UNREACHABLE
229        }
230
231    if (unlikely(retVal == XMLParser::EndOfDocumentSection && fScope != 0))
232    {
233        fScanner->emitError(XMLErrs::EndedWithTagsOnStack, fElement[fElementIndex]->getRawName());
234    }
235
236    return retVal;
237}
238
239// -------------------------------------------------------------------------------------------
240
241XML_PARSER_IMPL(bool)::
242scanMiscellaneous()
243{
244        XMLParser::XMLScanState r;
245        switch (fInMarkup)
246        {
247                case 0:     for (;;)
248                                        {
249                                                size_t length;
250                        r = scanContent<XMLParser::Miscellaneous>(length);
251                                                if (r) break;
252
253        case 1:         r = scanMarkup<XMLParser::Miscellaneous>();
254                                                if (r) break;
255                                        }
256                                        break;
257                default:    UNREACHABLE
258        }
259        return (r == XMLParser::EndOfPage);
260}
261
262// ---------------------------------------------------------------------------------------------------------
263
264XML_PARSER_IMPL_WITH_DOCUMENT_STATE_PARAMS(XMLParser::XMLScanState)::
265scanContent(size_t & length)
266{
267        length = getStringLength(fCursorPtr, fCurrentStringEndPtr);
268
269        // *fCurrentStringEndPtr will be 0 if and only if this is a complete string
270        if (unlikely(fCursorPtr[length] != 0))
271        {
272                DEBUG_TRANSITION_MESSAGE(" +++ aborting due to partial content string +++");
273                fCurrentStringEndPtr--;
274                fInMarkup = 0;
275                #ifndef CALCULATE_COPY_BACK_POSITION
276                // fUnusedContent = length;
277                // fUnusedSymbols = 0;
278                #endif
279        XMLParser::XMLScanState RET_VAL[2] = {XMLParser::EndOfPage, XMLParser::EndOfDocumentSection};
280        return RET_VAL[this->fNoMore];
281        }
282
283    DEBUG_TRANSITION_MESSAGE(" --- atContent: {" << length << ',' << fCursorPtr << '}')
284
285        // note: the startOfContentPtr stores the fCursorPtr position so that we can
286        // advance the fCursorPtr prior to giving the content to the scanner. This
287        // ensures that if an error occurs, we'll report the error line/col at the end
288        // of the content string, which is how Xerces reports it.
289
290        if (likely(length != 0))
291        {
292                const XMLCh * startOfContentPtr = fCursorPtr;
293                fCursorPtr += length;
294
295                if ((docStateType == XMLParser::Prolog) || (docStateType == XMLParser::Miscellaneous))
296                {
297                        if (unlikely(!XMLStringU::isWhitespace(startOfContentPtr, length)))
298                        {
299                                fScanner->emitError(XMLErrs::ExpectedCommentOrPI);
300                                return XMLParser::EndOfDocumentSection;
301                        }
302                        fScanner->handleIgnorableWhitespace
303                        (
304                                startOfContentPtr,
305                                length
306                        );
307                }
308                else
309                {
310                        fScanner->handleContent
311                        (
312                                startOfContentPtr,
313                                length
314                        );
315                }
316        }
317        ++fCursorPtr;
318        return XMLParser::HasMoreData;
319}
320
321// ---------------------------------------------------------------------------------------------------------
322
323XML_PARSER_IMPL_WITH_DOCUMENT_STATE_PARAMS(XMLParser::XMLScanState)::
324scanMarkup()
325{
326        if (unlikely(fMarkupCount == 0))
327        {
328                DEBUG_TRANSITION_MESSAGE(" +++ aborting due to incomplete pending markup +++");
329                fInMarkup = 1;
330                #ifndef CALCULATE_COPY_BACK_POSITION
331                // fUnusedContent = 0;
332                // fUnusedSymbols = fSymbolCount - fSymbolIdx;
333                #endif
334
335        XMLParser::XMLScanState RET_VAL[2] = {XMLParser::EndOfPage, XMLParser::EndOfDocumentSection};
336        return RET_VAL[fNoMore];
337        }
338
339        DEBUG_TRANSITION_MESSAGE("----------------------------------------------------------------------");
340
341        XMLCh markupChar = *fCursorPtr;
342
343        XMLParser::XMLScanState retVal = XMLParser::HasMoreData;
344
345        switch (markupChar & (EmptyTag - 1))
346        {
347                /// ------------------------------------------------------------------------ ///
348                case StartTagWithoutAttributes:
349                        if (docStateType == XMLParser::Prolog)
350                        {
351                                fInMarkup = 1;
352                                return XMLParser::EndOfDocumentSection;
353                        }
354                        else if (docStateType == XMLParser::Miscellaneous)
355                        {
356                                fScanner->emitError(XMLErrs::ExpectedCommentOrPI);
357                                return XMLParser::EndOfDocumentSection;
358                        }
359                        else if (docStateType == XMLParser::Element)
360                        {
361                                const gid_t elementGid = fSymbolArray[fSymbolIdx];
362                                XMLSymbol * const element = getSymbol(fSymbolIdx);
363                                unsigned int uriId = getSymbolUri(fSymbolIdx);
364                                // the namespace context id allows the scanner to map prefix to uris and determine what
365                                // prefixes and uris are in scope.
366                                fScanner->setContextId(fContextIdArray[fSymbolIdx]);
367                                element->getQName()->setURI(uriId);
368
369                                element->fLastOccurence = ++fElementCount;
370
371                                const bool isRoot = (fScope == 0);
372                                const bool isEmpty = (markupChar >> 3);
373
374                                DEBUG_TRANSITION_MESSAGE
375                                (
376                                        (char*)(isEmpty ? " --- atEmptyTag=" : " --- atStartTag=")
377                                        << element
378                                        << " idx="
379                                        << fSymbolIdx
380                                );
381
382                                XMLElementDecl * elemDecl =
383                                        fScanner->handleStartTag
384                                        (
385                                                element
386                                                , fAttributeList
387                                                , 0
388                                                , isRoot
389                                                , isEmpty
390                                                , fReaderNum
391                                        );
392
393                                addElement(elemDecl, elementGid, isRoot, isEmpty);
394
395                                // verify that this gets properly 'calculated' to remove the if test
396                                retVal = (isRoot & isEmpty) ? XMLParser::EndOfDocumentSection : XMLParser::HasMoreData;
397
398                                ++fSymbolIdx;
399                                ++fCursorPtr;
400                        }
401                        break;
402                /// ------------------------------------------------------------------------ ///
403                case StartTagWithAttributes:
404                        if (docStateType == XMLParser::Prolog)
405                        {
406                                fInMarkup = 1;
407                                return XMLParser::EndOfDocumentSection;
408                        }
409                        else if (docStateType == XMLParser::Miscellaneous)
410                        {
411                                fScanner->emitError(XMLErrs::ExpectedCommentOrPI);
412                                return XMLParser::EndOfDocumentSection;
413                        }
414                        else if (docStateType == XMLParser::Element)
415                        {
416                                // v        v            v
417                                // <...> OR <... ...> OR <... .../>
418                                const gid_t elementGid = fSymbolArray[fSymbolIdx];
419                                XMLSymbol * const element = getSymbol(fSymbolIdx);
420                                const unsigned int uriId = getSymbolUri(fSymbolIdx);
421                                fScanner->setContextId(fContextIdArray[fSymbolIdx]);
422                                element->getQName()->setURI(uriId);
423
424                                const unsigned int elementCount = ++fElementCount;
425
426                                DEBUG_TRANSITION_MESSAGE
427                                (
428                                        " --- atStartOrEmptyTag:"
429                                        << element
430                                        << " idx="
431                                        << fSymbolIdx
432                                );
433
434                                // QUESTION: using some sort of switch dispatch, could it be possible to feed in some
435                                // sort of branch prediction-friendly algorithms for this, assuming we have a schema/
436                                // dtd or can reuse the symbol's known attribute count? would the cost of the dispatch
437                                // exceed the cost of just doing it as is given hardware prefetchers? Even if was better
438                                // would the difference even be noticable?
439
440                                XMLSize_t attCount = 0;
441
442                                do
443                                {
444                                        // we're at an attribute; grab it
445
446                                        //             v
447                                        // <... ATTNAME='VALUE' ...
448                                        XMLSymbol * attribute = getSymbol(++fSymbolIdx);
449                                        unsigned int attrUriId = getSymbolUri(fSymbolIdx);
450                                        attribute->getQName()->setURI(attrUriId);
451
452                                        // duplicate attribute check: if we have observed the attribute symbol in this
453                                        // element, then it must have been used within the current attribute list; if so,
454                                        // it's a duplicate symbol.
455                                        if (unlikely(attribute->fLastOccurence == elementCount))
456                                        {
457                                                fScanner->emitError
458                                                (
459                                                        XMLErrs::AttrAlreadyUsedInSTag, attribute->getName(), element->getName()
460                                                );
461                                        }
462                                        attribute->fLastOccurence = elementCount;
463
464                                        // pull the attribute value out of the content buffer
465                                        const ptrdiff_t length = getStringLength(++fCursorPtr, fCurrentStringEndPtr);
466
467                                        if (unlikely(attrUriId == XMLNamespaceResolver::fSchemaInstanceUriId))
468                                        {
469                                                const XMLCh * localPart = attribute->getQName()->getLocalPart();
470                                                if (XMLString::equals(localPart, SchemaSymbols::fgXSI_TYPE))
471                                                {
472                                                        fScanner->setXsiType(fCursorPtr, length);
473                                                }
474                                                else if (XMLString::equals(localPart, SchemaSymbols::fgATT_NILL))
475                                                {
476                                                        fScanner->setXsiNil(fCursorPtr, length);
477                                                }
478                                        }
479
480                                        if (unlikely(attCount == fAttributeList.capacity()))
481                                        {
482                                                fAttributeList.expand(fAttributeList.capacity());
483                                        }
484
485                                        fAttributeList[attCount].set(attribute, fCursorPtr, length);
486
487                                        DEBUG_TRANSITION_MESSAGE
488                                        (
489                                                " --- atAttribute" << (attCount + 1) << ':'
490                                                << attribute
491                        << '='
492                                                << fCursorPtr
493                        << " idx="
494                                                << fSymbolIdx
495                                        );
496
497                                        fCursorPtr += length;
498                                        attCount++;
499                                        markupChar = *++fCursorPtr;
500                                }
501                                while ((markupChar & (EmptyTag - 1)) != 0);
502
503                                // set the element occurance back to its 'original' value.
504                                element->fLastOccurence = elementCount;
505
506                                const bool isEmpty = (markupChar >> 3);
507                                const bool isRoot = (fScope == 0);
508
509                                DEBUG_TRANSITION_MESSAGE
510                                (
511                                        (char*)(isEmpty ? " --- atEndOfEmptyTag: " : " --- atEndOfStartTag: ")
512                                        << element
513                                );
514
515                                XMLElementDecl * elemDecl =
516                                        fScanner->handleStartTag
517                                        (
518                                                element
519                                                , fAttributeList
520                                                , attCount
521                                                , isRoot
522                                                , isEmpty
523                                                , fReaderNum
524                                        );
525
526                                ++fCursorPtr;
527                                ++fSymbolIdx;
528
529                                addElement(elemDecl, elementGid, isRoot, isEmpty);
530
531                                retVal = (isRoot & isEmpty) ? XMLParser::EndOfDocumentSection : XMLParser::HasMoreData;
532                        }
533                        break;
534                /// ------------------------------------------------------------------------ ///
535                case EndTag:
536                        if (docStateType == XMLParser::Prolog)
537                        {
538                                fScanner->emitError(XMLErrs::MoreEndThanStartTags);
539                        }
540                        else if (docStateType == XMLParser::Miscellaneous)
541                        {
542                                fScanner->emitError(XMLErrs::ExpectedCommentOrPI);
543                        }
544                        else if (docStateType == XMLParser::Element)
545                        {
546                                const gid_t elementGid = fSymbolArray[fSymbolIdx];
547                                XMLSymbol * element = getSymbol(fSymbolIdx);
548                                // the namespace context id allows the scanner to map prefix to uris and determine what
549                                // prefixes and uris are in scope.
550                                fScanner->setContextId(fContextIdArray[fSymbolIdx]);
551
552                                DEBUG_TRANSITION_MESSAGE
553                                (
554                                        " --- atEndTag "
555                                        << element
556                                        << " idx="
557                                        << fSymbolIdx
558                                );
559
560                                unsigned int uriId = getSymbolUri(fSymbolIdx);
561
562                                element->getQName()->setURI(uriId);
563
564                                // check to be sure that we can "pop" the element off the stack
565                                if (unlikely(fScope == 0))
566                                {
567                                        fScanner->emitError(XMLErrs::MoreEndThanStartTags);
568                                        return XMLParser::EndOfDocumentSection;
569                                }
570                                else
571                                {
572                                        // we can; move back to the top element
573                                        fElementIndex -= fChildren[fScope];
574                                        --fScope;
575
576                                        const bool isRoot = (fScope == 0);
577
578                                        // get the elem decl
579                                        XMLElementDecl * elemDecl = fElement[fElementIndex];
580
581                                        // now check that this is the element we were looking for...
582                                        if (unlikely(fGidStack[fScope] != elementGid))
583                                        {
584                                                // check the uri and local parts? would that be legal?
585                                                fScanner->emitError(XMLErrs::ExpectedEndOfTagX, elemDecl->getRawName());
586                                        }
587
588                                        // swap the elem decl's qname with the element (symbol)'s qname
589                                        const QName * elementName = elemDecl->fElementName;
590
591                                        elemDecl->fElementName = element->fQName;
592
593                                        fScanner->handleEndTag
594                                        (
595                                                elemDecl
596                                                , uriId
597                                                , fReaderNum
598                                                , isRoot
599                                                , &fElement[fElementIndex + 1]
600                                                , fChildren[fScope + 1]
601                                        );
602
603                                        // swap the qname back to the grammar element
604                                        elemDecl->fElementName = elementName;
605
606                                        ++fSymbolIdx;
607                                        ++fCursorPtr;
608
609                                        retVal = (isRoot) ? XMLParser::EndOfDocumentSection : XMLParser::HasMoreData;
610                                }
611                        }
612                        break;
613                /// ------------------------------------------------------------------------ ///
614                case ProcessingInstruction:
615                        if ((docStateType == XMLParser::Prolog) || (docStateType == XMLParser::Element) || (docStateType == XMLParser::Miscellaneous))
616                        {
617                                XMLSymbol * target = getSymbol(fSymbolIdx);
618
619                                DEBUG_TRANSITION_MESSAGE
620                                (
621                                        " --- atProcessingInstruction="
622                    << target
623                                        << " idx="
624                                        << fSymbolIdx
625                                );
626
627                                // When we get a pi, the pi string will read "data?"; we adjust for this and replace the
628                                // trailing "?" with null to terminate the string so the end user only receives "data".
629
630                                const size_t length = getStringLength(++fCursorPtr, fCurrentStringEndPtr);
631                                const_cast<XMLCh*>(fCursorPtr)[length - 1] = 0x0000;
632
633
634                                // <?xml ... ?> is allowed if and only if we're in the prolog
635                                if (unlikely(target->isXML()))
636                                {
637                                        fScanner->emitError(XMLErrs::NoPIStartsWithXML);
638                                }
639                                else
640                                {
641                                        fScanner->handlePI(target, fCursorPtr, length);
642                                }
643
644                                fSymbolIdx++;
645                                fCursorPtr += length + 1;
646                        }
647                        break;
648                /// ------------------------------------------------------------------------ ///
649                case Comment:
650                        if ((docStateType == XMLParser::Prolog) || (docStateType == XMLParser::Element) || (docStateType == XMLParser::Miscellaneous))
651                        {
652                                //   v
653                                // <!--COMMENT-->
654
655                                // When we get a comment, the content string will read "--COMMENT--"; we offset the
656                                // start position and length to adjust for this and replace the first "-" in the trailing
657                                // "--" with null to terminate the string so the end user only receives "COMMENT".
658
659                const size_t length = getStringLength(++fCursorPtr, fCurrentStringEndPtr);
660
661                                const_cast<XMLCh*>(fCursorPtr)[length - 2] = chNull;
662
663                DEBUG_TRANSITION_MESSAGE(" --- atComment " << fCursorPtr);
664
665                                fScanner->handleComment(fCursorPtr, length - 2);
666
667                                fCursorPtr += length + 1;
668                        }
669                        break;
670                /// ------------------------------------------------------------------------ ///
671                case CDATA:
672                        if ((docStateType == XMLParser::Prolog) || (docStateType == XMLParser::Element) || (docStateType == XMLParser::Miscellaneous))
673                        {
674                                //   v
675                                // <![CDATA[ ... ]]>
676
677                                if (docStateType != XMLParser::Element)
678                                {
679                                        fScanner->emitError(XMLErrs::ExpectedCommentOrPI);
680                                        return XMLParser::EndOfDocumentSection;
681                                }
682
683                                if (unlikely(!XMLStringU::isCDATA(++fCursorPtr)))
684                                {
685                                        // "CDATA[" check failed
686                                        fScanner->emitError(XMLErrs::ExpectedCommentOrCDATA);
687                                        return XMLParser::EndOfDocumentSection;
688                                }
689
690                                fCursorPtr += 6;
691
692                                //                 v
693                                // <![CDATA[ ... ]]>
694                                const size_t length = getStringLength(fCursorPtr, fCurrentStringEndPtr);
695
696                                // When we get a CDATA, the string will read "[CDATA[data]]"; we offset the
697                                // start position and length to adjust for this and replace the first "[" in the trailing
698                                // "]]>" with null to terminate the string so the end user only receives "data".
699
700                                const_cast<XMLCh*>(fCursorPtr)[length - 2] = chNull;
701
702                DEBUG_TRANSITION_MESSAGE(" --- atCDATA " << fCursorPtr);
703
704                                fScanner->handleCDATA(fCursorPtr, length - 2);
705
706                                fCursorPtr += length + 1;
707                        }
708                        break;
709                default:
710                        UNREACHABLE
711        }
712
713        DEBUG_TRANSITION_MESSAGE("----------------------------------------------------------------------");
714
715        --fMarkupCount;
716        return retVal;
717}
718
719// ---------------------------------------------------------------------------------------------------------
720
721XML_PARSER_IMPL(void)::
722resolveDocumentPageNamespaces()
723{
724        const XMLCh * cursorPtr = &fContentBuf[0];
725        unsigned int markupCount = fMarkupCount;
726        unsigned int symbolIdx = 0;
727        const XMLCh ** stringEndPtr = &fStringEndPtr[0];
728        XMLCh markupChar;
729
730        DEBUG_NAMESPACE_MESSAGE("######################################################################");
731        DEBUG_NAMESPACE_MESSAGE("BEGIN NAMESPACE RESOLUTION:");
732        DEBUG_NAMESPACE_MESSAGE("######################################################################");
733
734        if (unlikely(markupCount == 0))
735        {
736                return;
737        }
738
739        // make sure there is enough room in the URI array for the symbols
740        if (unlikely(fSymbolUriArray.capacity() < fSymbolArray.capacity()))
741        {
742        DEBUG_TRANSITION_MESSAGE("RESIZING URI AND CONTEXT ID ARRAYS TO " << fSymbolArray.capacity())
743                fSymbolUriArray.resizeToFit(0, fSymbolArray.capacity());
744                fContextIdArray.resizeToFit(0, fSymbolArray.capacity());
745        }
746
747        switch (fInMarkup)
748        {
749                do
750                {
751        case 0: // skip this piece of content
752                        DEBUG_NAMESPACE_MESSAGE("==================================================================");
753            DEBUG_NAMESPACE_MESSAGE(" --- atContent " << cursorPtr)
754                        cursorPtr = *stringEndPtr++ + 1;
755        case 1: // process the next markup element
756                        markupChar = *cursorPtr;
757            #ifdef PRINT_DEBUG_MESSAGE
758                        switch (markupChar)
759                        {
760                                case StartTagWithoutAttributes:
761                                case StartTagWithAttributes:
762                                case EndTag:
763                                case ProcessingInstruction:
764                                case Comment:
765                                case CDATA:
766                                case EmptyTag:
767                                        break;
768                                default:
769                    DEBUG_TRANSITION_MESSAGE("ERROR! UNKNOWN MARKUP CHAR: " << markupChar);
770                                        exit(-1);
771                        }
772                        #endif
773                        switch (markupChar & (EmptyTag - 1))
774                        {
775                                /// ------------------------------------------------------------------------ ///
776                                case StartTagWithoutAttributes:
777                                        do {
778                                        fNamespaceResolver.enterScope();
779
780                                        // no speculation is required since new namespaces are not possible here!
781                                        const XMLSymbol * element = getSymbol(symbolIdx);
782
783                                        bool unknownPrefix = 0;
784
785                                        const unsigned int uriId = fNamespaceResolver.resolveUriId(element, false, unknownPrefix);
786
787                    DEBUG_NAMESPACE_MESSAGE(" --- atStartTag: " << element << " uriId=" << uriId << " idx=" << symbolIdx << " scope=" << fNamespaceResolver.getScope());
788
789                                        if (unlikely(unknownPrefix))
790                                        {
791                                                fScanner->emitError(XMLErrs::UnknownPrefix, element->getQName()->getPrefix());
792                                        }
793
794                                        if (unlikely(element->isXMLNS() && fScanner->fValidate))
795                                        {
796                                                fScanner->emitError(XMLErrs::NoXMLNSAsElementPrefix, element->getName());
797                                        }
798
799                                        const bool isEmpty = (markupChar >> 3);
800
801                                        storeSymbolUri(symbolIdx, uriId);
802
803                                        fContextIdArray[symbolIdx] = fNamespaceResolver.getCurrentContextId();
804
805                                        // outdent scope by one if and only if this element is an empty tag
806                                        if (isEmpty) fNamespaceResolver.leaveScope();
807
808                                        ++cursorPtr;
809                                        ++symbolIdx;
810
811                                        } while (0);
812                                        break;
813                                /// ------------------------------------------------------------------------ ///
814                                case StartTagWithAttributes:
815                                        do {
816
817                                        // a new namespaces is possible here! speculate that any unknown ones are acceptable, but
818                                        // verify after the fact if any new ones occured.
819
820                                        const XMLCh * storedCursorPtr = cursorPtr;
821                                        const unsigned int storedSymbolIdx = symbolIdx;
822                                        const XMLCh ** storedStringEndPtr = stringEndPtr;
823                                        const XMLSymbol * element = getSymbol(symbolIdx);
824
825                                        bool mispeculatedOnceAlready = 0;
826                                        bool observedXsi = 0;
827                                        bool unknownPrefix = 0;
828                                        bool speculatedCorrectly = 1;
829
830                                        fNamespaceResolver.enterScope();
831
832                                        DEBUG_NAMESPACE_MESSAGE("==================================================================");
833
834                                        for (;;)
835                                        {
836                                                unsigned int uriId = fNamespaceResolver.resolveUriId(element, false, unknownPrefix);
837
838                        DEBUG_NAMESPACE_MESSAGE(" --- atStartTag: " << element << " uriId=" << uriId << " idx=" << symbolIdx<< " scope=" << fNamespaceResolver.getScope());
839
840                                                storeSymbolUri(symbolIdx, uriId);
841
842                                                if (unlikely(element->isXMLNS() && fScanner->fValidate))
843                                                {
844                                                        fScanner->emitError(XMLErrs::NoXMLNSAsElementPrefix, element->getName());
845                                                }
846
847                                                do
848                                                {
849                                                        DEBUG_NAMESPACE_MESSAGE("------------------------------------------------------------------");
850
851                                                        // extract the next attribute ...
852                                                        XMLSymbol * attribute = getSymbol(++symbolIdx);
853
854                                                        // pull the attribute value out of the content buffer
855                                                        const size_t length = getStringLength(++cursorPtr, stringEndPtr);
856
857                                                        // is this an "xmlns" attribute? if so, then we want to update the namespace table.
858                                                        if (unlikely(attribute->isXMLNS()))
859                                                        {
860                                XMLErrs::Codes bindingError;
861
862                                uriId = fNamespaceResolver.bindNamespace(attribute, cursorPtr, length, speculatedCorrectly, bindingError);
863
864                                if (unlikely(bindingError != XMLErrs::NoError))
865                                {
866                                    fScanner->emitError(bindingError);
867                                }
868                                                        }
869                                                        else
870                                                        {
871                                                                uriId = fNamespaceResolver.resolveUriId(attribute, true, unknownPrefix);
872
873                                                                observedXsi |= (uriId == XMLNamespaceResolver::fSchemaInstanceUriId);
874                                                        }
875
876                            DEBUG_NAMESPACE_MESSAGE(" --- atAttribute: " << attribute << " uriId=" << uriId << " idx=" << symbolIdx);
877
878                                                        storeSymbolUri(symbolIdx, uriId);
879
880                                                        cursorPtr += length;
881
882                                                        // if the next markup char's value is 0 (8), then we're at the end of the start/empty tag
883                                                        markupChar = *++cursorPtr;
884
885                            #ifdef PRINT_DEBUG_MESSAGE
886                                                        switch (markupChar)
887                                                        {
888                                                                case StartTagWithAttributes:
889                                                                case StartTagWithoutAttributes:
890                                                                case EmptyTag:
891                                                                        break;
892                                                                case EndTag:
893                                                                case ProcessingInstruction:
894                                                                case Comment:
895                                                                case CDATA:
896                                    DEBUG_TRANSITION_MESSAGE("ERROR! UNEXPECTED MARKUP CHAR: " << markupChar);
897                                                                        exit(-1);
898                                                                        break;
899                                                                default:
900                                    DEBUG_TRANSITION_MESSAGE("ERROR! UNKNOWN MARKUP CHAR: " << markupChar);
901                                                                        exit(-1);
902                                                        }
903                                                        #endif
904                                                }
905                                                while ((markupChar & (EmptyTag - 1)) != 0);
906
907                                                if (likely(speculatedCorrectly))
908                                                {
909                                                        break;
910                                                }
911                                                else
912                                                {
913                                                        if (unlikely(mispeculatedOnceAlready))
914                                                        {
915                                                                // ERROR! the only way that this occured was that there are two or more
916                                                                // xmlns attributes with the same local part but different uris.
917
918                                                                const XMLCh * duplicatedAttribute = 0;
919                                                                const unsigned int firstAttribute = storedSymbolIdx + 1;
920                                                                for (unsigned int i = firstAttribute + 1; i <= symbolIdx; i++)
921                                                                {
922                                                                        const XMLSymbol * attribute = getSymbol(i);
923                                                                        for (unsigned int j = firstAttribute; j < i; j++)
924                                                                        {
925                                                                                if (getSymbol(j) == attribute)
926                                                                                {
927                                                                                        duplicatedAttribute = attribute->getName();
928                                                                                        break;
929                                                                                }
930                                                                        }
931                                                                }
932                                                                fScanner->emitError(XMLErrs::AttrAlreadyUsedInSTag, duplicatedAttribute, element->getName());
933                                                                break;
934                                                        }
935
936                                                        DEBUG_NAMESPACE_MESSAGE("------------------------------------------------------------------");
937                                                        DEBUG_NAMESPACE_MESSAGE(" *** uri speculation failed! retrying!");
938                                                        DEBUG_NAMESPACE_MESSAGE("==================================================================");
939
940                                                        mispeculatedOnceAlready = 1;
941                                                        speculatedCorrectly = 1;
942                                                        unknownPrefix = 0;
943                                                        cursorPtr = storedCursorPtr;
944                                                        symbolIdx = storedSymbolIdx;
945                                                        stringEndPtr = storedStringEndPtr;
946                                                }
947                                        }
948
949                                        if (unlikely(unknownPrefix && fScanner->fValidate))
950                                        {
951                                                unsigned int dupSymbolIdx = storedSymbolIdx;
952                                                const XMLSymbol * symbol = element;
953                                                unknownPrefix = 0;
954                                                do
955                                                {
956                                                        fNamespaceResolver.resolveUriId(symbol, false, unknownPrefix);
957                                                        if (unknownPrefix)
958                                                        {
959                                                                fScanner->emitError(XMLErrs::UnknownPrefix, symbol->getQName()->getPrefix());
960                                                        }
961                                                        symbol = getSymbol(++dupSymbolIdx);
962                                                }
963                                                while (dupSymbolIdx <= symbolIdx);
964                                        }
965
966
967                                        if (unlikely(observedXsi && fScanner->getDoSchema()))
968                                        {
969                                                cursorPtr = storedCursorPtr;
970                                                symbolIdx = storedSymbolIdx;
971                                                stringEndPtr = storedStringEndPtr;
972
973                                                do
974                                                {
975                                                        XMLSymbol * attribute = getSymbol(++symbolIdx);
976
977                                                        // pull the attribute value out of the content buffer
978                                                        const size_t length = getStringLength(++cursorPtr, stringEndPtr);
979
980                                                        if (unlikely(getSymbolUri(symbolIdx) == XMLNamespaceResolver::fSchemaInstanceUriId))
981                                                        {
982                                                                // is this an "xsi:schemaLocation" or "xsi:noNamespaceSchemaLocation" attribute? if so, then
983                                                                // tell the scanner to handle it.
984
985                                                                const XMLCh * const localPart = attribute->getQName()->getLocalPart();
986                                                                if (XMLString::equals(localPart, SchemaSymbols::fgXSI_SCHEMALOCATION))
987                                                                {
988                                                                        DEBUG_NAMESPACE_MESSAGE("##==================================================================##");
989                                                                        fScanner->parseSchemaLocation(cursorPtr, length);
990                                                                        DEBUG_NAMESPACE_MESSAGE("##==================================================================##");
991                                                                }
992                                                                else if (XMLString::equals(localPart, SchemaSymbols::fgXSI_NONAMESPACESCHEMALOCATION))
993                                                                {
994                                                                        DEBUG_NAMESPACE_MESSAGE("##==================================================================##");
995                                                                        fScanner->resolveSchemaGrammar(cursorPtr, XMLUni::fgZeroLenString);
996                                                                        DEBUG_NAMESPACE_MESSAGE("##==================================================================##");
997                                                                }
998                                                        }
999
1000                                                        cursorPtr += length;
1001                                                }
1002                                                while ((*++cursorPtr & (EmptyTag - 1)) != 0);
1003
1004                                        }
1005
1006                                        fContextIdArray[storedSymbolIdx] = fNamespaceResolver.getCurrentContextId();
1007
1008                                        const bool isEmpty = (markupChar >> 3);
1009
1010                                        // outdent scope by one if and only if this element is an empty tag
1011                                        if (isEmpty) fNamespaceResolver.leaveScope();
1012
1013                                        ++cursorPtr;
1014                                        ++symbolIdx;
1015
1016                                        } while (0);
1017                                        break;
1018
1019                                /// ------------------------------------------------------------------------ ///
1020                                case EndTag:
1021                                        do {
1022                                                // no new namespaces are possible here! no speculation required
1023                                                const XMLSymbol * element = getSymbol(symbolIdx);
1024
1025                                                const unsigned int uriId = fNamespaceResolver.resolveUriId(element, false);
1026
1027                        DEBUG_NAMESPACE_MESSAGE(" --- atEndTag: " << element << " uriId=" << uriId << " idx=" << symbolIdx << " scope=" << fNamespaceResolver.getScope());
1028
1029                                                storeSymbolUri(symbolIdx, uriId);
1030
1031                                                // should this simply be pulled from a stack?
1032                                                fContextIdArray[symbolIdx] = fNamespaceResolver.getCurrentContextId();
1033
1034                                                symbolIdx++;
1035
1036                                                fNamespaceResolver.leaveScope();
1037
1038                                                cursorPtr++;
1039                                        } while (0);
1040                                        break;
1041                                /// ------------------------------------------------------------------------ ///
1042                                case ProcessingInstruction:
1043                                        symbolIdx++;
1044                                case Comment:
1045                                case CDATA:
1046                    #ifdef PRINT_DEBUG_MESSAGE
1047                    DEBUG_TRANSITION_MESSAGE(" --- atCDCtPI " << cursorPtr);
1048                                        cursorPtr = *stringEndPtr++ + 1;
1049                                        #else
1050                                        stringEndPtr++;
1051                                        #endif
1052                                        break;
1053                                default:
1054                                        UNREACHABLE
1055                        /// ------------------------------------------------------------------------ ///
1056                        }
1057                }
1058                while (likely(--markupCount != 0));
1059                break;
1060        default:
1061                UNREACHABLE
1062        }
1063}
1064
1065// ---------------------------------------------------------------------------------------------------------
1066
1067XML_PARSER_IMPL(void)::
1068prepareForNextDocumentPage()
1069{
1070        #ifdef CALCULATE_COPY_BACK_POSITION
1071        const XMLCh * cursorPtr = fCursorEndPtr - fUnusedContent;
1072        unsigned int symbolIdx = fSymbolCount - fUnusedSymbols;
1073        // calculate how many string end pointers will be copied over
1074        unsigned int stringIndex = fStringCount;
1075        if (unlikely(cursorPtr < fCursorEndPtr))
1076        {
1077                const XMLCh * cursor = cursorPtr;
1078                for (;;)
1079                {
1080                        cursor += XMLStringU::stringLen(cursor) + 1;
1081                        if (likely(cursor > fCursorEndPtr)) break;
1082                        stringIndex--;
1083                }
1084        }
1085
1086    DEBUG_TRANSITION_MESSAGE("stringCount=" << fStringCount);
1087    DEBUG_TRANSITION_MESSAGE("cursorOffset=" << (size_t)(cursorPtr - &fContentBuf[0]) << " (" << (size_t)(fCursorPtr - &fContentBuf[0]) << ')');
1088    DEBUG_TRANSITION_MESSAGE("symbolIndex=" << symbolIdx << " (" << fSymbolIdx << ')');
1089    DEBUG_TRANSITION_MESSAGE("stringIndex=" << stringIndex << " (" << (size_t)(fCurrentStringEndPtr - &fStringEndPtr[0]) << ')');
1090
1091        assert (cursorPtr == fCursorPtr);
1092        assert (symbolIdx == fSymbolIdx);
1093        assert (stringIndex == (fCurrentStringEndPtr - &fStringEndPtr[0]));
1094
1095        #else
1096        const XMLCh * cursorPtr = fCursorPtr;
1097        const unsigned int symbolIdx = fSymbolIdx;
1098        const unsigned int stringIndex = (fCurrentStringEndPtr - &fStringEndPtr[0]);
1099        #endif
1100
1101
1102
1103        /** ------------------- BUFFER LINE/COL TRACKING STREAM --------------------- **/
1104
1105    #ifndef DISABLE_PARSER_LINE_COLUMN_CALCULATION
1106        if (likely(fIncompleteMarkupBytes != 0))
1107        {
1108                size_t index =
1109                        fLineColStartIndex
1110                        + ((fRawBytesAvail - fIncompleteMarkupBytes) >> LOG_2_BLOCK_SIZE);
1111
1112                const size_t count =
1113                        fLineColStartIndex
1114                        - (fRawDataOffset >> LOG_2_BLOCK_SIZE)
1115                        + (fRawBytesAvail >> LOG_2_BLOCK_SIZE);
1116
1117                size_t lineColStartIndex = 1;
1118
1119                // get the first block but mask off the used portion of it
1120                const BitBlock newLineOrSkipMask =
1121                        bitblock::load_aligned(&fNewLineOrSkipMaskStream[index]);
1122                const BitBlock delMask =
1123                        bitblock::load_aligned(&fDelMaskStream[index]);
1124                const BitBlock mask =
1125                        bitblock::srl(simd<1>::constant<1>(), convert((fIncompleteMarkupBytes - 1) & (BLOCK_SIZE - 1)));
1126
1127                bitblock::store_aligned(simd_andc(newLineOrSkipMask, mask), &fNewLineOrSkipMaskStream[0]);
1128                bitblock::store_aligned(simd_or(delMask, mask), &fDelMaskStream[0]);
1129
1130                // now if there are any remaining blocks to copy over, copy them over directly
1131                while (++index < count)
1132                {
1133                        // NOTE: these fences are required here or we may get arbitary data from the
1134                        // streams
1135                        const BitBlock newLineOrSkipMask =
1136                                bitblock::load_aligned(&fNewLineOrSkipMaskStream[index]);
1137                        const BitBlock delMask =
1138                                bitblock::load_aligned(&fDelMaskStream[index]);
1139
1140                        bitblock::store_aligned(newLineOrSkipMask, &fNewLineOrSkipMaskStream[lineColStartIndex]);
1141                        bitblock::store_aligned(delMask, &fDelMaskStream[lineColStartIndex]);
1142                        lineColStartIndex++;
1143                }
1144
1145                fLineColStartIndex = lineColStartIndex;
1146        }
1147        else
1148        {
1149                fLineColStartIndex = 0;
1150        }
1151    #endif
1152
1153        fCurrLineCol = fNextLineCol;
1154
1155        /** ----------------------- BUFFER CONTENT STREAM --------------------------- **/
1156
1157        // stringEndOffset is required to adjust the string end position of the unused strings
1158        ptrdiff_t cursorOffset = (cursorPtr - &fContentBuf[0]);
1159
1160        if (likely(cursorPtr < fCursorEndPtr))
1161        {
1162                const XMLCh * const contentBuf0 = &fContentBuf[0];
1163                const unsigned int unusedLength =
1164                        fContentBuf.copy_to_front(cursorOffset, (fCursorEndPtr - &fContentBuf[0]));
1165                // just incase the content buffer was expanded, adjust the string end offset
1166                cursorOffset += (contentBuf0 - &fContentBuf[0]);
1167
1168                fCursorPtr = &fContentBuf[unusedLength];
1169        }
1170        else
1171        {
1172                fCursorPtr = &fContentBuf[0];
1173        }
1174
1175        /** -------------------- MOVE STRING END POINTERS BACK ------------------------ **/
1176
1177        if (stringIndex < fStringCount)
1178        {
1179                fStringEndPtr.adjust(stringIndex, fStringCount, cursorOffset);
1180                fStringCount = fStringEndPtr.copy_to_front(stringIndex, fStringCount);
1181        }
1182        else
1183        {
1184                fStringCount = 0;
1185        }
1186
1187        /** ------------------------ BUFFER SYMBOL STREAM ------------------------------ **/
1188
1189        fSymbolUriArray.copy_to_front(symbolIdx, fSymbolCount);
1190        fContextIdArray.copy_to_front(symbolIdx, fSymbolCount);
1191        fSymbolCount = fSymbolArray.copy_to_front(symbolIdx, fSymbolCount);
1192}
1193
1194// -------------------------------------------------------------------------------------------
1195
1196XML_PARSER_IMPL(void)::
1197popReader()
1198{
1199        fScanner->fReaderMgr.popReader();
1200}
1201
1202// ---------------------------------------------------------------------------------------------------------
1203
1204XML_PARSER_IMPL(XMLSymbol *)::
1205getSymbol(const unsigned int index)
1206{
1207        const gid_t gid = fSymbolArray[index];
1208        #ifdef USE_SIMPLE_HASH_TABLE_LOOKUP
1209        XMLSymbol * symbol = fSymbolTable[gid];
1210        #else
1211        XMLSymbol * symbol = fSymbolResolver[gid];
1212        #endif
1213        return symbol;
1214}
1215
1216XML_PARSER_IMPL(const XMLSymbol *)::
1217getSymbol(const unsigned int index) const
1218{
1219        const gid_t gid = fSymbolArray[index];
1220        #ifdef USE_SIMPLE_HASH_TABLE_LOOKUP
1221        XMLSymbol * symbol = fSymbolTable[gid];
1222        #else
1223        XMLSymbol * symbol = fSymbolResolver[gid];
1224        #endif
1225        return symbol;
1226}
1227
1228// ---------------------------------------------------------------------------------------------------------
1229
1230XML_PARSER_IMPL(void)::
1231storeSymbolUri(const unsigned int index, const unsigned int uriId)
1232{
1233        fSymbolUriArray[index] = uriId;
1234}
1235
1236XML_PARSER_IMPL(unsigned int)::
1237getSymbolUri(const unsigned int index) const
1238{
1239        return fSymbolUriArray[index];
1240}
1241
1242// ---------------------------------------------------------------------------------------------------------
1243
1244XML_PARSER_IMPL(void)::
1245addElement(XMLElementDecl * elemDecl, const gid_t gid, const bool isRoot, const bool isEmpty)
1246{
1247        fChildren[fScope]++;
1248        if (unlikely(++fElementIndex == fElement.capacity()))
1249        {
1250                fElement.expand(fElement.capacity());
1251        }
1252        fElement[fElementIndex] = elemDecl;
1253        if (likely(!isEmpty))
1254        {
1255                if (unlikely(fScope == fChildren.capacity() - 1))
1256                {
1257                        fChildren.expand(fChildren.capacity());
1258                        fGidStack.expand(fGidStack.capacity());
1259                }
1260                fGidStack[fScope] = gid;
1261                fChildren[++fScope] = 0;
1262        }
1263}
1264
1265// ---------------------------------------------------------------------------------------------------------
1266
1267XML_PARSER_IMPL(ptrdiff_t)::
1268getStringLength(const XMLCh * stringStartPtr, const XMLCh ** & stringEndPtr)
1269{
1270        const XMLCh * nextStringEndPtr = *stringEndPtr++;
1271
1272    #ifdef PRINT_DEBUG_MESSAGE
1273        assert (stringStartPtr <= nextStringEndPtr);
1274        assert (&fContentBuf[0] <= nextStringEndPtr);
1275        assert (nextStringEndPtr < fContentBuf.limit());
1276        #endif
1277
1278        return nextStringEndPtr - stringStartPtr;
1279}
1280
1281#undef XML_PARSER_IMPL
1282#undef XML_PARSER_IMPL_WITH_DOCUMENT_STATE_PARAMS
1283
1284XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.