source: icXML/icXML-0.95/src/icxmlc/parsers/XMLNamespaceParser.hpp @ 3602

Last change on this file since 3602 was 3602, checked in by cameron, 5 years ago

Namespace bug fix for icXML-0.95

File size: 29.2 KB
Line 
1#ifndef XMLNAMESPACEPARSER_HPP
2#define XMLNAMESPACEPARSER_HPP
3
4#include <icxmlc/XMLParserImpl.hpp>
5#include <icxmlc/parsers/XMLSchemaLoader.hpp>
6#include <icxmlc/XMLReplacementText.hpp>
7#include <icxmlc/XMLConfig.hpp>
8#include <limits>
9
10XERCES_CPP_NAMESPACE_BEGIN
11
12template<class ScannerType>
13class XMLNamespaceParser
14{
15    typedef DynamicArray<gid_t, INITIAL_ATTRIBUTE_LIST_SIZE> GidArrayType;
16
17    typedef DynamicArray<bool, INITIAL_ATTRIBUTE_LIST_SIZE> BoolArrayType;
18
19public:
20
21    inline XMLNamespaceParser
22    (
23        XMLParser &                           parser
24        , XMLNamespaceResolver &              namespaceResolver       
25        , const XMLSymbolTable &              symbolTable
26        , const XMLReferenceTable &           referenceTable
27        , XMLSchemaLoader<ScannerType> &      schemaLoader
28        , ScannerType &                       scanner
29    )         
30    : fContentStream(&parser.fContentStream[0])
31    , fCursorPtr(&parser.fContentStream[parser.fContentIdx])
32    , fCursorEndPtr(parser.fCursorEndPtr)
33    , fSymbolStream(&parser.fSymbolStream[0])
34    , fSymbolPtr(&fSymbolStream[0])
35    , fSymbolCount(parser.fSymbolCount)
36    , fReferenceStream(&parser.fReferenceStream[0])
37    , fReferencePtr(fReferenceStream)
38    , fReferenceCount(parser.fReferenceCount)
39    , fStringEndStream(&parser.fStringEndStream[0])
40    , fStringEndPtr(parser.fStringEndPtr)
41    , fStringCount(parser.fStringCount)
42    , fUriStream(parser.fUriStream)
43    , fUriPtr(&parser.fUriStream[0])
44    , fUriCount(parser.fUriCount)
45    , fNamespaceContextStream(parser.fNamespaceContextStream)
46    , fNamespaceContextPtr(&parser.fNamespaceContextStream[0])
47    , fContextCount(0)
48    , fInMarkup(parser.fInMarkup)
49    , fIsXMLV1_1(scanner.getXMLVersion() == XMLReader::XMLV1_1)
50    , fMarkupCount(parser.fMarkupCount)
51    , fMaxAttributeCount(parser.fMaxAttributeCount)
52    , fLocalPartIds(parser.fMaxAttributeCount)
53    , fNamespaceResolver(namespaceResolver)
54    , fReferenceTable(referenceTable)
55    , fSymbolTable(symbolTable)
56    , fSchemaLoader(schemaLoader)
57    , fBaseMarkupCount(parser.fMarkupCount)
58    , fSystemId(parser.fReader.getSystemId())
59    , fPublicId(parser.fReader.getPublicId())
60    , fLine(parser.fLine)
61    , fColumn(parser.fColumn)
62    , fLineColumnStreamPtr(&parser.fLineColumnStream[0])
63    , fContainsXsiTypeOrNil(parser.fContainsXsiTypeOrNil)
64    , fScanner(scanner)
65    , fEntityContentBuffer(parser.fEntityContentBuffer)
66    , fParser(parser)
67    {
68        DEBUG_NAMESPACE_MESSAGE("######################################################################");
69        DEBUG_NAMESPACE_MESSAGE("BEGIN NAMESPACE PROCESSING: fMarkupCount=" << fMarkupCount << " fUriCount=" << fUriCount << " fMaxAttributeCount=" << fMaxAttributeCount);
70        DEBUG_NAMESPACE_MESSAGE("######################################################################");
71
72        fContainsXsiTypeOrNil = false;
73        fNamespaceResolver.setMaxScope(parser.fMaxScope + 1);
74    }
75
76    inline XMLNamespaceParser
77    (
78        XMLNamespaceParser &                parser
79        , const XMLReplacementText &        entity
80    )
81    : fContentStream(entity.fContentStream)
82    , fCursorPtr(&entity.fContentStream[0])
83    , fCursorEndPtr(&entity.fContentStream[entity.fContentLength])
84    , fSymbolStream(entity.fSymbolStream)
85    , fSymbolPtr(&entity.fSymbolStream[0])
86    , fSymbolCount(entity.fSymbolCount)
87    , fReferenceStream(entity.fReferenceStream)
88    , fReferencePtr(fReferenceStream)
89    , fReferenceCount(entity.fReferenceCount)
90    , fStringEndStream(entity.fStringEndStream)
91    , fStringEndPtr(&fStringEndStream[0])
92    , fStringCount(entity.fStringEndCount)
93    , fUriStream(parser.fUriStream)
94    , fUriPtr(parser.fUriPtr)
95    , fUriCount(parser.fUriCount)
96    , fNamespaceContextStream(parser.fNamespaceContextStream)
97    , fNamespaceContextPtr(parser.fNamespaceContextPtr)
98    , fContextCount(parser.fContextCount)
99    , fInMarkup(false)
100    , fIsXMLV1_1(parser.fIsXMLV1_1) // should be in the entity!
101    , fMarkupCount(entity.fMarkupCount)
102    , fMaxAttributeCount(parser.fMaxAttributeCount)
103    , fLocalPartIds(parser.fMaxAttributeCount)
104    , fNamespaceResolver(parser.fNamespaceResolver)
105    , fReferenceTable(parser.fReferenceTable)
106    , fSymbolTable(parser.fSymbolTable)
107    , fSchemaLoader(parser.fSchemaLoader)
108    , fBaseMarkupCount(entity.fMarkupCount)
109    , fSystemId(entity.fSystemId)
110    , fPublicId(entity.fPublicId)
111    , fLine(entity.fLine)
112    , fColumn(entity.fColumn)
113    , fLineColumnStreamPtr(entity.fLineColumnStream)
114    , fContainsXsiTypeOrNil(parser.fContainsXsiTypeOrNil)
115    , fScanner(parser.fScanner)
116    , fEntityContentBuffer(parser.fEntityContentBuffer)
117    , fParser(parser.fParser)
118    {
119        DEBUG_NAMESPACE_MESSAGE("######################################################################");
120        DEBUG_NAMESPACE_MESSAGE("BEGIN ENTITY NAMESPACE PROCESSING:");
121        DEBUG_NAMESPACE_MESSAGE("######################################################################");
122    }
123
124    inline ~XMLNamespaceParser()
125    {
126        DEBUG_NAMESPACE_MESSAGE("######################################################################");
127        DEBUG_NAMESPACE_MESSAGE("END NAMESPACE PROCESSING:");
128        DEBUG_NAMESPACE_MESSAGE("######################################################################");
129    }
130
131    void resolveNamespaces();
132
133private:
134
135    void emitError(const XMLErrs::Codes toEmit, const XMLCh* const text1 = 0, const XMLCh* const text2 = 0);
136
137    IDISA_ALWAYS_INLINE
138    void verifyUniqueNamespacedAttributeConstraint(SymbolPtrType elementPtr, UriPtrType uriStream, const size_t attCount);
139
140    void scanForUnknownPrefixes(const UriPtrType uriPtr, const SymbolPtrType symbolPtr, const size_t count);
141
142    void reportDuplicateNamespacedAttribute(SymbolPtrType elementPtr, const gid_t localPartId);
143
144    /**
145     *  Recursively resolve the namespaces of the entity
146     **/
147    void resolveEntityNamespaces(const gid_t refId);
148
149    /**
150     *  Expand any entities within an attribute value
151     **/
152    size_t expandEntitiesWithinAttributeValue(ContentPtrType & value, ContentPtrType & delimiter);
153
154    IDISA_ALWAYS_INLINE
155    void skipPastAnyEntities(ContentPtrType & delimiter);
156
157    IDISA_ALWAYS_INLINE
158    const XMLSymbol & getSymbolByPtr(SymbolPtrType symbolPtr) const;
159
160    IDISA_ALWAYS_INLINE
161    gid_t resolveAttributeUriId(const size_t index, SymbolPtrType symbolPtr, const bool misspeculated, bool & isXsi, bool & containsXmlnsAttribute, bool & speculatedCorrectly, bool & unknownPrefix);
162
163    IDISA_ALWAYS_INLINE
164    gid_t resolveEndTagUriId(SymbolPtrType symbolPtr);
165
166    IDISA_ALWAYS_INLINE
167    void writeCurrentContextId(const gid_t contextId, const bool namespaceContextChange);
168
169    void checkForXsiSchemaLocationOrNoNamespaceSchemaLocation(ContentPtrType contentStream, DelimiterPtrType delimiterStream, UriPtrType uriStream, const size_t attCount);
170
171    IDISA_ALWAYS_INLINE
172    void scanContent();
173
174    IDISA_ALWAYS_INLINE
175    void scanMarkup();
176
177private:
178
179    const ContentPtrType                fContentStream;
180    ContentPtrType                      fCursorPtr;
181    ContentPtrType                      fCursorEndPtr;
182
183    const SymbolPtrType                 fSymbolStream;
184    SymbolPtrType                       fSymbolPtr;
185    const size_t                        fSymbolCount;
186
187    const ReferencePtrType              fReferenceStream;
188    ReferencePtrType                    fReferencePtr;
189    const size_t                        fReferenceCount;
190
191    const DelimiterPtrType              fStringEndStream;
192    DelimiterPtrType                    fStringEndPtr;
193    const size_t &                      fStringCount;
194
195    SymbolUriArray &                                    fUriStream;
196    WritableUriPtrType                  fUriPtr;
197    const size_t                        fUriCount;
198
199    SymbolUriArray &                                    fNamespaceContextStream;
200    WritableUriPtrType                  fNamespaceContextPtr;
201    SymbolUriArray::Type                fContextCount;
202
203    const bool                          fInMarkup;
204    const bool                          fIsXMLV1_1;
205
206    size_t                              fMarkupCount;
207    bool &                              fContainsXsiTypeOrNil;
208    const size_t                        fMaxAttributeCount;
209
210    GidArrayType                        fLocalPartIds;
211
212    XMLNamespaceResolver &              fNamespaceResolver;
213    const XMLReferenceTable &           fReferenceTable;
214    const XMLSymbolTable &              fSymbolTable;
215    XMLSchemaLoader<ScannerType> &      fSchemaLoader;
216    ScannerType &                       fScanner;
217
218    XMLBuffer * const                   fEntityContentBuffer;
219
220    size_t                              fBaseMarkupCount;
221    const XMLCh *                       fSystemId;
222    const XMLCh *                       fPublicId;
223    XMLFileLoc                          fLine;
224    XMLFileLoc                          fColumn;
225    LineColumnPtrType                   fLineColumnStreamPtr;
226
227    XMLParser &                         fParser;
228};
229
230/// --------------------------------------------------------------------------------------------------------------------------------
231
232template<class ScannerType>
233void XMLNamespaceParser<ScannerType>::resolveNamespaces()
234{
235    // this needs to record any xsi:schemaLocation | xsi:noNamespaceSchemaLocation values for the parent namespace pass to process.
236    // if there is no markup remaining, stop scanning!
237    if (unlikely(!fScanner.getDoNamespaces() || fMarkupCount == 0))
238    {
239        fContextCount = static_cast<SymbolUriArray::Type>(-1);
240        writeCurrentContextId(fNamespaceResolver.getCurrentContextId(), true);
241        return;
242    }
243
244    try
245    {
246        switch (fInMarkup)
247        {
248            for(;;)
249            {
250        case 0:     if (unlikely(fMarkupCount == 0))
251                    {
252                        break;
253                    }
254                    scanContent();
255        default:    if (unlikely(fMarkupCount == 0))
256                    {
257                        break;
258                    }
259                    scanMarkup();
260            }
261        }
262    }
263    catch (XMLErrs::Codes bindingError)
264    {
265        emitError(bindingError, getSymbolByPtr(fSymbolPtr).getQName()->getRawName());
266    }
267
268
269    writeCurrentContextId(fNamespaceResolver.getCurrentContextId(), true);
270}
271
272/// --------------------------------------------------------------------------------------------------------------------------------
273
274template<class ScannerType>
275void XMLNamespaceParser<ScannerType>::scanContent()
276{
277    DEBUG_NAMESPACE_MESSAGE("==================================================================");
278    DEBUG_NAMESPACE_MESSAGE(" -- atContent=" << fCursorPtr << " fMarkupCount=" << fMarkupCount);
279    {
280        const ContentPtrType cursorPtr = fCursorPtr;
281        fCursorPtr = *fStringEndPtr++;
282        assert (cursorPtr <= fCursorPtr);
283        assert (fCursorPtr <= fCursorEndPtr);
284
285        // if we found a reference, it's a general entity. check whether it contains markup and if not, skip it.
286        // make this another template parameter? not sure if it would be useful.
287        while (unlikely(*fCursorPtr == Entity))
288        {
289            // parse the entity and record the namespaces
290            resolveEntityNamespaces(*fReferencePtr++);
291            // skip to the next delimiter
292            fCursorPtr = *fStringEndPtr++;
293        }
294        ++fCursorPtr;
295    }
296    fMarkupCount--;
297}
298
299/// --------------------------------------------------------------------------------------------------------------------------------
300
301template<class ScannerType>
302void XMLNamespaceParser<ScannerType>::scanMarkup()
303{
304    DEBUG_NAMESPACE_MESSAGE("==================================================================");
305
306    XMLCh markupChar = *fCursorPtr;
307    bool hasAttributes = 0;
308    switch (markupChar & MarkupMask)
309    {
310        /// ------------------------------------------------------------------------ ///
311        case StartTagWithAttributes:
312            hasAttributes = 1;
313            // intentionally fall through after the hasAttributes flag is set.
314        case StartTagWithoutAttributes:
315        {
316            // a new namespaces is possible here! speculate that any unknown ones are acceptable, but
317            // verify after the fact if any new ones occured.
318            fNamespaceResolver.enterScope();
319            const SymbolPtrType elementSymbolPtr = fSymbolPtr;
320            const WritableUriPtrType elementUriPtr = fUriPtr;
321            bool unknownPrefix = 0;
322            bool containsXmlnsAttribute = 0;
323            size_t attCount = 0;
324
325            if (hasAttributes)
326            {
327                const ContentPtrType initialCursorPtr = fCursorPtr;
328                const DelimiterPtrType initialStringEndPtr = fStringEndPtr;
329                bool misspeculated = 0;
330
331                for (;;)
332                {
333                    bool observedXsi = 0;
334                    bool speculatedCorrectly = 1;
335
336                    do
337                    {
338                        /// --------------------------------------------------------------------------------------------------------------
339                        /// DOCUMENT ATTRIBUTE RESOLUTION
340                        /// --------------------------------------------------------------------------------------------------------------
341
342                        // extract the next attribute ...
343
344                        *++fUriPtr = resolveAttributeUriId(attCount++, ++fSymbolPtr, misspeculated, observedXsi, containsXmlnsAttribute, speculatedCorrectly, unknownPrefix);
345
346                        // if the next markup char's value is 0 (8), then we're at the end of the start/empty tag
347                        markupChar = *++fCursorPtr;
348                    }
349                    while ((markupChar & MarkupMask) == Attribute);
350
351                    /// --------------------------------------------------------------------------------------------------------------
352                    /// Default attribute resolution was performed in well-formedness checker
353                    /// --------------------------------------------------------------------------------------------------------------
354
355                    if (likely(speculatedCorrectly))
356                    {
357                        verifyUniqueNamespacedAttributeConstraint(elementSymbolPtr, elementUriPtr + 1, attCount);
358
359                        if (unlikely(observedXsi))
360                        {
361                            checkForXsiSchemaLocationOrNoNamespaceSchemaLocation(initialCursorPtr, initialStringEndPtr, elementUriPtr + 1, attCount);
362                        }
363
364                        break;
365                    }
366                    else // note: this code can only be entered once. it is impossible to misspeculate a second time.
367                    {
368                        DEBUG_NAMESPACE_MESSAGE("------------------------------------------------------------------");
369                        DEBUG_NAMESPACE_MESSAGE(" *** uri speculation failed! retrying!");
370                        DEBUG_NAMESPACE_MESSAGE("==================================================================");
371
372                        fNamespaceResolver.misspeculated();
373                        fCursorPtr = initialCursorPtr;
374                        fSymbolPtr = elementSymbolPtr;
375                        fUriPtr = elementUriPtr;
376                        fStringEndPtr = initialStringEndPtr;
377
378                        // note: if we speculated correctly, then any 'unknown' prefix ought to be what we predicted it would be --- provided
379                        // that the document is legal.
380                        unknownPrefix = 0;
381                        attCount = 0;
382                        misspeculated = 1;
383                    }
384                }
385
386            }
387
388            const XMLSymbol & element = getSymbolByPtr(elementSymbolPtr);
389
390            // resolve the uri of the element and test whether its prefix is known.
391
392            *elementUriPtr = fNamespaceResolver.resolveUriId(element, false, false, unknownPrefix);
393
394            if (unlikely(unknownPrefix))
395            {
396                scanForUnknownPrefixes(elementUriPtr, elementSymbolPtr, attCount + 1);
397            }
398
399            const bool isEmpty = (markupChar & EmptyTag);
400
401            ++fCursorPtr;
402            ++fSymbolPtr;
403            ++fUriPtr;
404
405            // write out the previous namespace context
406            writeCurrentContextId(fNamespaceResolver.getCurrentContextId(), containsXmlnsAttribute);
407            // if this is an empty tag, write out the 'in-scope' namespace context we're entering.
408            const gid_t contextId = fNamespaceResolver.finalizeScope(isEmpty, containsXmlnsAttribute);
409            if (isEmpty)
410            {
411                // since it's possible for a schema-derived empty element to have specified content value, it's possible
412                // that an empty tag will be transformed into a start and end tag pair in the grammar validator.
413                // To simplify the logic of the later phases, simply write out the 'out of scope' context id too.
414                writeCurrentContextId(contextId, containsXmlnsAttribute);
415            }
416
417            DEBUG_NAMESPACE_MESSAGE
418            (
419                (isEmpty ? " --- atEmptyTag: " : " --- atStartTag: ") << element
420                << " scope=" << fNamespaceResolver.getScope()
421                << " uriId=" << *elementUriPtr
422                << " unknownPrefix=" << unknownPrefix
423                << " containsXmlnsAttribute=" << containsXmlnsAttribute
424                << " contextId=" << contextId
425                << " markupCount=" << fMarkupCount
426            );
427
428            break;
429        }
430        /// ------------------------------------------------------------------------ ///
431        case EndTag:
432        {
433            *fUriPtr = resolveEndTagUriId(fSymbolPtr);
434
435            DEBUG_NAMESPACE_MESSAGE
436            (
437                " --- atEndTag: " << getSymbolByPtr(fSymbolPtr)
438                << " scope=" << fNamespaceResolver.getScope()
439                << " uriId=" << *fUriPtr
440                << " markupCount=" << fMarkupCount
441            );
442
443            fCursorPtr++;
444            fUriPtr++;
445            fSymbolPtr++;
446
447            // write out the 'in-scope' namespace context we're about to leave.
448            bool namespaceContextChange;
449            const gid_t contextId = fNamespaceResolver.getCurrentContextId();
450            fNamespaceResolver.leaveScope(namespaceContextChange);
451            writeCurrentContextId(contextId, namespaceContextChange);
452            break;
453        }
454        /// ------------------------------------------------------------------------ ///
455        case ProcessingInstruction:
456            fStringEndPtr++; // skip the target name
457        case Comment:
458        case CDATA:
459            fStringEndPtr++; // skip the value
460            break;
461        default:
462            UNREACHABLE
463    /// ------------------------------------------------------------------------ ///
464    }
465    --fMarkupCount;
466}
467
468/// --------------------------------------------------------------------------------------------------------------------------------
469
470template<class ScannerType>
471const XMLSymbol & XMLNamespaceParser<ScannerType>::getSymbolByPtr(SymbolPtrType symbolPtr) const
472{
473    return fSymbolTable[*symbolPtr];
474}
475
476/// --------------------------------------------------------------------------------------------------------------------------------
477
478template<class ScannerType>
479gid_t XMLNamespaceParser<ScannerType>::
480resolveAttributeUriId(const size_t index, SymbolPtrType symbolPtr, const bool misspeculated, bool & observedXsi, bool & containsXmlnsAttribute, bool & speculatedCorrectly, bool & unknownPrefix)
481{
482    const XMLSymbol & attribute = getSymbolByPtr(symbolPtr);
483
484    // advance past the '=' and determine the length of the attribute value from the delimiter ptr
485    ContentPtrType value = ++fCursorPtr;
486    ContentPtrType delimiter = *fStringEndPtr++;
487
488    gid_t uriId;
489    // is this an "xmlns" attribute? if so, then we want to update the namespace table.
490    if (unlikely(attribute.isXMLNS()))
491    {
492        size_t length;
493        bool expanded = false;
494        // expand any entities within the URI string.
495        if (unlikely(*delimiter == Entity))
496        {
497            length = expandEntitiesWithinAttributeValue(value, delimiter);
498            expanded = true;
499        }
500        else
501        {
502            length = delimiter - value;
503        }
504
505
506        uriId = fNamespaceResolver.bindNamespace(attribute, value, length, fIsXMLV1_1, speculatedCorrectly);
507
508        containsXmlnsAttribute = true;
509
510        if (unlikely(expanded))
511        {
512            fEntityContentBuffer->reset();
513        }
514
515        DEBUG_NAMESPACE_MESSAGE(" --- atAttribute" << (index + 1) << ' ' << getSymbolByPtr(fSymbolPtr) << '=' << value << " uriId=" << uriId << " speculatedCorrectly=" << speculatedCorrectly);
516    }
517    else // just resolve the uri gid
518    {
519        uriId = fNamespaceResolver.resolveUriId(attribute, true, misspeculated, unknownPrefix);
520        DEBUG_NAMESPACE_MESSAGE(" --- atAttribute" << (index + 1) << ' ' << getSymbolByPtr(fSymbolPtr) << '=' << value << " uriId=" << uriId << " observedXsi=" << observedXsi << " unknownPrefix=" << unknownPrefix);
521        observedXsi |= (uriId == XMLNamespaceResolver::fSchemaInstanceUriId);
522        // skip past any entity; we don't care about the actual value unless it's an URI.
523        skipPastAnyEntities(delimiter);
524    }
525
526    // record the localPartId for this attribute and its value
527    assert (index < fLocalPartIds.capacity());
528    fLocalPartIds[index] = attribute.getLocalPartId();
529
530    fCursorPtr = delimiter;
531
532    return uriId;
533}
534
535/// --------------------------------------------------------------------------------------------------------------------------------
536
537template<class ScannerType>
538size_t XMLNamespaceParser<ScannerType>::
539expandEntitiesWithinAttributeValue(ContentPtrType & value, ContentPtrType & delimiter)
540{
541    fEntityContentBuffer->set(value, delimiter - value);
542    do
543    {
544        const XMLReplacementText & entity = fReferenceTable[*fReferencePtr++];
545        fEntityContentBuffer->append(entity.fContentStream, entity.fContentLength);
546        value = delimiter + 1;
547        delimiter = *fStringEndPtr++;
548        assert (value <= delimiter);
549        // append either the posterior content of this attribute value or any content between two entities
550        fEntityContentBuffer->append(value, delimiter - value);
551    }
552    while (*delimiter == Entity);
553    value = fEntityContentBuffer->getRawBuffer();
554    return fEntityContentBuffer->getLen();
555}
556
557/// --------------------------------------------------------------------------------------------------------------------------------
558
559template<class ScannerType>
560void XMLNamespaceParser<ScannerType>::
561skipPastAnyEntities(ContentPtrType & delimiter)
562{
563    while (unlikely(*delimiter == Entity))
564    {
565        assert (delimiter < *fStringEndPtr);
566        delimiter = *fStringEndPtr++;
567        assert (&fContentStream[0] < delimiter);
568        // skip this reference
569        fReferencePtr++;
570    }
571}
572
573/// --------------------------------------------------------------------------------------------------------------------------------
574
575template<class ScannerType>
576gid_t XMLNamespaceParser<ScannerType>::
577resolveEndTagUriId(SymbolPtrType symbolPtr)
578{
579    return fNamespaceResolver.resolveUriId(getSymbolByPtr(symbolPtr), false);
580}
581
582/// --------------------------------------------------------------------------------------------------------------------------------
583
584template<class ScannerType>
585void XMLNamespaceParser<ScannerType>::
586writeCurrentContextId(const gid_t contextId, const bool namespaceContextChange)
587{
588    // was the namespace context changed or is there any chance of a number overflow
589    // TODO: look into better method of the overflow test.
590    if (unlikely(namespaceContextChange))
591    {
592        assert (fNamespaceContextPtr < fNamespaceContextStream.limit() - 1);
593        fNamespaceContextPtr[0] = contextId;
594        fNamespaceContextPtr[1] = fContextCount;
595        fNamespaceContextPtr += 2;
596        fContextCount = 0;
597    }
598    fContextCount++;
599}
600
601/// --------------------------------------------------------------------------------------------------------------------------------
602/// ENTITY HANDLING FUNCTIONS
603/// --------------------------------------------------------------------------------------------------------------------------------
604
605template<class ScannerType>
606void XMLNamespaceParser<ScannerType>::
607resolveEntityNamespaces(const gid_t refId)
608{
609    const XMLReplacementText & entity = fReferenceTable[refId];
610    if (entity.getMarkupCount())
611    {
612        XMLNamespaceParser<ScannerType> parser(*this, entity);
613        parser.resolveNamespaces();
614
615        // update the internal state based on what the entity parser discovered.
616        fUriPtr = parser.fUriPtr;
617        fNamespaceContextPtr = parser.fNamespaceContextPtr;
618        fContextCount = parser.fContextCount;       
619
620        DEBUG_NAMESPACE_MESSAGE("######################################################################");
621        DEBUG_NAMESPACE_MESSAGE("END ENTITY NAMESPACE PROCESSING: " << fMarkupCount);
622        DEBUG_NAMESPACE_MESSAGE("######################################################################");
623    }
624}
625
626
627/// --------------------------------------------------------------------------------------------------------------------------------
628/// ERROR HANDLING FUNCTIONS
629/// --------------------------------------------------------------------------------------------------------------------------------
630
631template<class ScannerType>
632void XMLNamespaceParser<ScannerType>::
633scanForUnknownPrefixes(const UriPtrType uriPtr, const SymbolPtrType symbolPtr, const size_t count)
634{
635    for (size_t i = 0; i < count; i++)
636    {
637        const XMLSymbol & symbol = getSymbolByPtr(symbolPtr + i);
638        if (unlikely(uriPtr[i] == XMLNamespaceResolver::fUnknownUriId || !fNamespaceResolver.isPrefixVisible(symbol.getPrefixId())))
639        {           
640            emitError(XMLErrs::UnknownPrefix, symbol.getQName()->getPrefix());
641        }
642    }
643}
644
645/*
646    Namespaces in XML 1.0 (Third Edition)
647
648        6.3 Uniqueness of Attributes
649
650        Namespace constraint: Attributes Unique
651        In XML documents conforming to this specification, no tag may contain two attributes which:
652            have identical names, or
653            have qualified names with the same local part and with prefixes which have been bound to namespace
654            names that are identical.
655*/
656
657template<class ScannerType>
658void XMLNamespaceParser<ScannerType>::
659verifyUniqueNamespacedAttributeConstraint(SymbolPtrType elementPtr, UriPtrType uriStream, const size_t attCount)
660{
661    // should we scan all attributes in parallel by transposing the attribute gids?
662    // if M is the maximum attribute count, every element would require M attribute slots -- regardless of how
663    // many attributes the element has.
664
665    const gid_t * localPartIds = &fLocalPartIds[0];
666
667    for (size_t i = 1; i < attCount; i++)
668    {
669        const gid_t localPartId = localPartIds[i];
670
671        for (size_t j = 0; j < i; j++)
672        {
673            if (unlikely(localPartIds[j] == localPartId))
674            {
675                if (unlikely(uriStream[j] == uriStream[i]))
676                {
677                    reportDuplicateNamespacedAttribute(elementPtr, localPartId);
678                }
679            }
680        }
681    }
682}
683
684template<class ScannerType>
685void XMLNamespaceParser<ScannerType>::
686checkForXsiSchemaLocationOrNoNamespaceSchemaLocation(ContentPtrType contentStream, DelimiterPtrType delimiterStream, UriPtrType uriStream, const size_t attCount)
687{
688    DEBUG_MESSAGE("checkForXsiSchemaLocationOrNoNamespaceSchemaLocation")
689
690    // is this an "xsi:schemaLocation" or "xsi:noNamespaceSchemaLocation" attribute? if so, then
691    // record it as something to load later.
692
693    const gid_t * localPartIds = &fLocalPartIds[0];
694
695    for (size_t i = 0; i < attCount; i++)
696    {
697        // advance past the '=' and determine the length of the attribute value from the delimiter ptr
698        const size_t length = *delimiterStream - ++contentStream;
699
700        if (uriStream[i] == XMLNamespaceResolver::fSchemaInstanceUriId)
701        {
702            bool noNamespace = 1;
703            switch (localPartIds[i])
704            {
705                case XMLSymbolTable::Type:
706                case XMLSymbolTable::Nil:
707                    fContainsXsiTypeOrNil = true;
708                    break;
709                case XMLSymbolTable::SchemaLocation:
710                    noNamespace = 0;
711                case XMLSymbolTable::NoNamespaceSchemaLocation:
712                    fSchemaLoader.addSchema(contentStream, length, noNamespace);
713            }
714        }
715        contentStream = *delimiterStream++ + 1;
716    }
717}
718
719template<class ScannerType>
720void XMLNamespaceParser<ScannerType>::
721reportDuplicateNamespacedAttribute(SymbolPtrType elementPtr, const gid_t localPartId)
722{
723    emitError(XMLErrs::AttrAlreadyUsedInSTag, fSymbolTable.getNCName(localPartId), getSymbolByPtr(elementPtr).getName());
724}
725
726template<class ScannerType>
727void XMLNamespaceParser<ScannerType>::
728emitError(const XMLErrs::Codes toEmit, const XMLCh* const text1, const XMLCh* const text2)
729{
730    // count the number of passed markup location
731    XMLSize_t delimiterIdx = fBaseMarkupCount - fMarkupCount + fParser.fContentIdx;
732    // add in any bypassed general entity references locations
733    delimiterIdx += (fReferencePtr - &fReferenceStream[0]);
734
735    fLineColumnStreamPtr = fParser.calculateMarkupLocation(fLineColumnStreamPtr, &fLineColumnStreamPtr[delimiterIdx * 2], fLine, fColumn);
736
737    fScanner.emitError(toEmit, fSystemId, fPublicId, fLine, fColumn, text1, text2);
738}
739
740XERCES_CPP_NAMESPACE_END
741
742#endif // XMLNAMESPACEPARSER_HPP
Note: See TracBrowser for help on using the repository browser.