source: icXML/icXML-devel/src/icxmlc/parsers/XMLNamespaceParser.hpp @ 3563

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

Update icxmlc files

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);
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    fLocalPartIds[index] = attribute.getLocalPartId();
528
529    fCursorPtr = delimiter;
530
531    return uriId;
532}
533
534/// --------------------------------------------------------------------------------------------------------------------------------
535
536template<class ScannerType>
537size_t XMLNamespaceParser<ScannerType>::
538expandEntitiesWithinAttributeValue(ContentPtrType & value, ContentPtrType & delimiter)
539{
540    fEntityContentBuffer->set(value, delimiter - value);
541    do
542    {
543        const XMLReplacementText & entity = fReferenceTable[*fReferencePtr++];
544        fEntityContentBuffer->append(entity.fContentStream, entity.fContentLength);
545        value = delimiter + 1;
546        delimiter = *fStringEndPtr++;
547        assert (value <= delimiter);
548        // append either the posterior content of this attribute value or any content between two entities
549        fEntityContentBuffer->append(value, delimiter - value);
550    }
551    while (*delimiter == Entity);
552    value = fEntityContentBuffer->getRawBuffer();
553    return fEntityContentBuffer->getLen();
554}
555
556/// --------------------------------------------------------------------------------------------------------------------------------
557
558template<class ScannerType>
559void XMLNamespaceParser<ScannerType>::
560skipPastAnyEntities(ContentPtrType & delimiter)
561{
562    while (unlikely(*delimiter == Entity))
563    {
564        assert (delimiter < *fStringEndPtr);
565        delimiter = *fStringEndPtr++;
566        assert (&fContentStream[0] < delimiter);
567        // skip this reference
568        fReferencePtr++;
569    }
570}
571
572/// --------------------------------------------------------------------------------------------------------------------------------
573
574template<class ScannerType>
575gid_t XMLNamespaceParser<ScannerType>::
576resolveEndTagUriId(SymbolPtrType symbolPtr)
577{
578    return fNamespaceResolver.resolveUriId(getSymbolByPtr(symbolPtr), false);
579}
580
581/// --------------------------------------------------------------------------------------------------------------------------------
582
583template<class ScannerType>
584void XMLNamespaceParser<ScannerType>::
585writeCurrentContextId(const gid_t contextId, const bool namespaceContextChange)
586{
587    // was the namespace context changed or is there any chance of a number overflow
588    // TODO: look into better method of the overflow test.
589    if (unlikely(namespaceContextChange))
590    {
591        assert (fNamespaceContextPtr < fNamespaceContextStream.limit() - 1);
592        fNamespaceContextPtr[0] = contextId;
593        fNamespaceContextPtr[1] = fContextCount;
594        fNamespaceContextPtr += 2;
595        fContextCount = 0;
596    }
597    fContextCount++;
598}
599
600/// --------------------------------------------------------------------------------------------------------------------------------
601/// ENTITY HANDLING FUNCTIONS
602/// --------------------------------------------------------------------------------------------------------------------------------
603
604template<class ScannerType>
605void XMLNamespaceParser<ScannerType>::
606resolveEntityNamespaces(const gid_t refId)
607{
608    const XMLReplacementText & entity = fReferenceTable[refId];
609    if (entity.getMarkupCount())
610    {
611        XMLNamespaceParser<ScannerType> parser(*this, entity);
612        parser.resolveNamespaces();
613
614        // update the internal state based on what the entity parser discovered.
615        fUriPtr = parser.fUriPtr;
616        fNamespaceContextPtr = parser.fNamespaceContextPtr;
617        fContextCount = parser.fContextCount;       
618
619        DEBUG_NAMESPACE_MESSAGE("######################################################################");
620        DEBUG_NAMESPACE_MESSAGE("END ENTITY NAMESPACE PROCESSING: " << fMarkupCount);
621        DEBUG_NAMESPACE_MESSAGE("######################################################################");
622    }
623}
624
625
626/// --------------------------------------------------------------------------------------------------------------------------------
627/// ERROR HANDLING FUNCTIONS
628/// --------------------------------------------------------------------------------------------------------------------------------
629
630template<class ScannerType>
631void XMLNamespaceParser<ScannerType>::
632scanForUnknownPrefixes(const UriPtrType uriPtr, const SymbolPtrType symbolPtr, const size_t count)
633{
634    for (size_t i = 0; i < count; i++)
635    {
636        const XMLSymbol & symbol = getSymbolByPtr(symbolPtr + i);
637        if (unlikely(uriPtr[i] == XMLNamespaceResolver::fUnknownUriId || !fNamespaceResolver.isPrefixVisible(symbol.getPrefixId())))
638        {           
639            emitError(XMLErrs::UnknownPrefix, symbol.getQName()->getPrefix());
640        }
641    }
642}
643
644/*
645    Namespaces in XML 1.0 (Third Edition)
646
647        6.3 Uniqueness of Attributes
648
649        Namespace constraint: Attributes Unique
650        In XML documents conforming to this specification, no tag may contain two attributes which:
651            have identical names, or
652            have qualified names with the same local part and with prefixes which have been bound to namespace
653            names that are identical.
654*/
655
656template<class ScannerType>
657void XMLNamespaceParser<ScannerType>::
658verifyUniqueNamespacedAttributeConstraint(SymbolPtrType elementPtr, UriPtrType uriStream, const size_t attCount)
659{
660    // should we scan all attributes in parallel by transposing the attribute gids?
661    // if M is the maximum attribute count, every element would require M attribute slots -- regardless of how
662    // many attributes the element has.
663
664    const gid_t * localPartIds = &fLocalPartIds[0];
665
666    for (size_t i = 1; i < attCount; i++)
667    {
668        const gid_t localPartId = localPartIds[i];
669
670        for (size_t j = 0; j < i; j++)
671        {
672            if (unlikely(localPartIds[j] == localPartId))
673            {
674                if (unlikely(uriStream[j] == uriStream[i]))
675                {
676                    reportDuplicateNamespacedAttribute(elementPtr, localPartId);
677                }
678            }
679        }
680    }
681}
682
683template<class ScannerType>
684void XMLNamespaceParser<ScannerType>::
685checkForXsiSchemaLocationOrNoNamespaceSchemaLocation(ContentPtrType contentStream, DelimiterPtrType delimiterStream, UriPtrType uriStream, const size_t attCount)
686{
687    DEBUG_MESSAGE("checkForXsiSchemaLocationOrNoNamespaceSchemaLocation")
688
689    // is this an "xsi:schemaLocation" or "xsi:noNamespaceSchemaLocation" attribute? if so, then
690    // record it as something to load later.
691
692    const gid_t * localPartIds = &fLocalPartIds[0];
693
694    for (size_t i = 0; i < attCount; i++)
695    {
696        // advance past the '=' and determine the length of the attribute value from the delimiter ptr
697        const size_t length = *delimiterStream - ++contentStream;
698
699        if (uriStream[i] == XMLNamespaceResolver::fSchemaInstanceUriId)
700        {
701            bool noNamespace = 1;
702            switch (localPartIds[i])
703            {
704                case XMLSymbolTable::Type:
705                case XMLSymbolTable::Nil:
706                    fContainsXsiTypeOrNil = true;
707                    break;
708                case XMLSymbolTable::SchemaLocation:
709                    noNamespace = 0;
710                case XMLSymbolTable::NoNamespaceSchemaLocation:
711                    fSchemaLoader.addSchema(contentStream, length, noNamespace);
712            }
713        }
714        contentStream = *delimiterStream++ + 1;
715    }
716}
717
718template<class ScannerType>
719void XMLNamespaceParser<ScannerType>::
720reportDuplicateNamespacedAttribute(SymbolPtrType elementPtr, const gid_t localPartId)
721{
722    emitError(XMLErrs::AttrAlreadyUsedInSTag, fSymbolTable.getNCName(localPartId), getSymbolByPtr(elementPtr).getName());
723}
724
725template<class ScannerType>
726void XMLNamespaceParser<ScannerType>::
727emitError(const XMLErrs::Codes toEmit, const XMLCh* const text1, const XMLCh* const text2)
728{
729    // count the number of passed markup location
730    XMLSize_t delimiterIdx = fBaseMarkupCount - fMarkupCount + fParser.fContentIdx;
731    // add in any bypassed general entity references locations
732    delimiterIdx += (fReferencePtr - &fReferenceStream[0]);
733
734    fLineColumnStreamPtr = fParser.calculateMarkupLocation(fLineColumnStreamPtr, &fLineColumnStreamPtr[delimiterIdx * 2], fLine, fColumn);
735
736    fScanner.emitError(toEmit, fSystemId, fPublicId, fLine, fColumn, text1, text2);
737}
738
739XERCES_CPP_NAMESPACE_END
740
741#endif // XMLNAMESPACEPARSER_HPP
Note: See TracBrowser for help on using the repository browser.