source: icXML/icXML-0.95/src/icxmlc/XMLNamespaceResolver.c @ 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: 26.3 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: XMLNamespaceResolver.c 388 2013-10-29 21:25:27Z nigelm $
10 *
11 */
12
13#include <icxmlc/XMLNamespaceResolver.hpp>
14#include <icxmlc/XMLSymbol.hpp>
15#include <icxmlc/XMLStringU.hpp>
16
17XERCES_CPP_NAMESPACE_BEGIN
18
19/// -----------------------------------------------------------------------------------------------
20// TODO: if we bind a uri to a prefix and the binding is non-canonical but the canonical entry for the prefix is
21// empty, should we move the prefix into that entry and rewrite all of the symbols? it would require storing a
22// list of symbols per prefix or having a "moved" bitset to tell the resolver to update the symbol's binding.
23// would this be worth the effort?
24
25IDISA_ALWAYS_INLINE
26gid_t
27XMLNamespaceResolver::bindNamespace(const XMLSymbol & symbol, const XMLCh * uri, const XMLSize_t length, const bool isXMLV1_1, bool & speculatedCorrectly)
28{
29        // Get the prefix id of the local part of this symbol name, e.g. the prefix id of "ogc" if the symbol is "xmlns:ogc"
30        // or fEmptyNamespaceId if the symbol is "xmlns"
31
32    const gid_t prefixId = symbol.getLocalPartId();
33
34    DEBUG_NAMESPACE_MESSAGE("prefixId=" << prefixId)
35
36    gid_t uriId = resolveUri(uri, length, prefixId);
37
38    DEBUG_NAMESPACE_MESSAGE("uriId=" << uriId)
39
40    // test if this prefix/uri pair is an error
41    if (unlikely(uriId == XMLNamespaceResolver::fEmptyUriId))
42    {
43        // in the case that an empty string is used as a URI, assume that we're dealing with an XML 1.1 document.
44        if (likely(isXMLV1_1))
45        {
46            uriId = XMLNamespaceResolver::fUnknownUriId;
47        }
48        else
49        {
50            // Namespaces in XML 1.0 (Third Edition)
51            //
52            // The empty string, though it is a legal URI reference, cannot be used as a namespace name. (2.2)
53            // The attribute's normalized value MUST be either a URI reference — the namespace name identifying the namespace — or an empty string. (3)
54            // In a namespace declaration for a prefix (i.e., where the NSAttName is a PrefixedAttName), the attribute value MUST NOT be empty. (5)
55
56            if (unlikely(prefixId != XMLNamespaceResolver::fEmptyUriId))
57            {
58                throw XMLErrs::NoEmptyStrNamespace;
59            }
60        }
61    }
62    else
63    {
64        // is the XML URI being bound to some prefix other than "xml" or vice versa?
65        if (unlikely((prefixId == fXMLUriId) ^ (uriId == fXMLUriId)))
66        {
67            throw (uriId == fXMLUriId) ? XMLErrs::XMLURINotMatchXMLPrefix : XMLErrs::PrefixXMLNotMatchXMLURI;
68        }       
69        else if (unlikely(uriId == fXMLNSUriId)) // was the XMLNS URI bound to some prefix?
70        {           
71            throw XMLErrs::NoUseOfxmlnsURI;
72        }
73    }
74
75    const int namespaceId = resolveNamespaceId(prefixId);
76
77    DEBUG_NAMESPACE_MESSAGE("namespaceId=" << namespaceId)
78
79    if (unlikely(namespaceId == -1))
80        {
81                // both the prefixId and the uriId exist, but they are not mapped to one another.
82        mapPrefixToUri(prefixId, uriId);
83
84        // since we speculated that the prefixId == globalUriId, if we find that this is not
85                // true, then we have to re-resolve everything regarding this element.
86        speculatedCorrectly &= (prefixId == uriId);
87        }
88    else
89    {
90        const gid_t storedUriId = getNamespaceUriId(namespaceId);
91
92        DEBUG_NAMESPACE_MESSAGE("storedUriId=" << storedUriId)
93
94        if (likely(storedUriId != uriId))
95        {
96            remapPrefixToUri(prefixId, uriId);
97            speculatedCorrectly = 0;
98        }
99    }
100    return XMLNamespaceResolver::fXMLNSUriId;
101}
102
103/// -----------------------------------------------------------------------------------------------
104
105IDISA_ALWAYS_INLINE
106gid_t
107XMLNamespaceResolver::resolveUriId(const XMLSymbol & symbol, const bool isAttribute) const
108{
109    bool unknown = 0;
110    return resolveUriId(symbol, isAttribute, false, unknown);
111}
112
113/// -----------------------------------------------------------------------------------------------
114
115IDISA_ALWAYS_INLINE
116gid_t
117XMLNamespaceResolver::resolveUriId(const XMLSymbol & symbol, const bool isAttribute, const bool misspeculated, bool & unknown) const
118{   
119    if (isAttribute && !symbol.isQualified())
120        {
121        return fEmptyUriId;
122        }
123    return resolveUriId(symbol.getPrefixId(), (isAttribute && likely(!misspeculated) ? symbol.getPrefixId() : fUnknownUriId), unknown);
124}
125
126/// -----------------------------------------------------------------------------------------------
127
128IDISA_ALWAYS_INLINE
129gid_t
130XMLNamespaceResolver::resolveUriId(const gid_t prefixId, const gid_t defaultUriId, bool & unknown) const
131{
132    gid_t uriId = defaultUriId;
133        // first check canonical set to see if this prefix id is also the uri id.
134        if (likely(fCanonicalBindingSet.mask_and_extract(fCurrentlyVisibleNamespaces, prefixId)))
135        {
136        uriId = prefixId;
137        }
138        else
139        {
140                // it's not canonical; resolve which of the possible uri ids this prefix id
141                // currently points to
142                const int namespaceId = resolveNamespaceId(prefixId);
143                // if this prefix has not been mapped to a namespace; assume that it will
144                // be mapped to the 'adjacent' uri.
145
146                if (likely(namespaceId != -1))
147                {
148            uriId = getNamespaceUriId(namespaceId);
149            unknown = (uriId == XMLNamespaceResolver::fUnknownUriId);
150                }
151                else
152                {
153                        unknown = true;
154                }
155        }
156        return uriId;
157}
158
159/// -----------------------------------------------------------------------------------------------
160
161IDISA_ALWAYS_INLINE
162gid_t
163XMLNamespaceResolver::resolveUriId(const XMLCh * uri) const
164{
165        if (unlikely(!uri || *uri == 0))
166        {
167                return fEmptyUriId;
168        }
169
170        XMLSize_t length = XMLStringU::stringLen(uri);
171
172    const gid_t linkId = fUriPool.find(uri, length);
173
174    gid_t uriId;
175
176    if (unlikely(linkId == XMLNamespaceResolver::fUnknownUriId))
177        {
178        XMLNamespaceResolver * const self = const_cast<XMLNamespaceResolver*>(this);
179        // no, it was already used; claim the next unused link id.
180        uriId = self->fUriPool.add(max<size_t>(fPrefixCount, fUriPool.count()), uri, length, self->fGlobalUriPool);
181        }
182    else
183    {
184        #ifdef PRINT_DEBUG_MESSAGE
185        assert (linkId < fUriPool.count());
186        assert (XMLString::compareString(fUriPool[linkId].fKey, uri) == 0);
187        #endif
188        uriId = fUriPool[linkId].getId();
189    }
190
191    return uriId;
192}
193
194/// -----------------------------------------------------------------------------------------------
195
196// get the prefix id of the prefix portion of the qName, e.g., the prefix id of "xmlns" if given "xmlns:ogc"
197// or the prefix of "" if given "xmlns".
198
199IDISA_ALWAYS_INLINE
200gid_t
201XMLNamespaceResolver::resolvePrefixId(const XMLCh * qName, int & colonPos) const
202{
203    int length = XMLStringU::stringLenOrIndexOf<chColon>(qName);
204
205    if (unlikely(qName[length] == chNull))
206    {
207        colonPos = -1;
208        }
209    else
210    {
211        colonPos = length;
212    }
213
214    const XMLPrefixEntry * entry = findPrefix(qName, length);
215    if (likely(entry != 0))
216    {
217        return entry->getId();
218    }
219
220    return XMLNamespaceResolver::fUnknownUriId;
221}
222
223/// -----------------------------------------------------------------------------------------------
224
225IDISA_ALWAYS_INLINE
226gid_t XMLNamespaceResolver::addOrFindPrefixId(const XMLCh * qName, const XMLSize_t length, int & colon)
227{
228    colon = XMLStringU::indexOf<chColon>(qName, length);
229    return (unlikely(colon == -1)) ? XMLNamespaceResolver::fEmptyUriId : addOrFindPrefixId(qName, colon);
230}
231
232/// -----------------------------------------------------------------------------------------------
233
234IDISA_ALWAYS_INLINE
235gid_t XMLNamespaceResolver::addOrFindPrefixId(const XMLCh * qName, const XMLSize_t length)
236{
237    const gid_t prefixId = addOrFindPrefix(qName, length)->getId();
238    DEBUG_NAMESPACE_MESSAGE(" -- prefixId=" << prefixId)
239    return prefixId;
240}
241
242/// -----------------------------------------------------------------------------------------------
243
244IDISA_ALWAYS_INLINE
245const XMLCh *
246XMLNamespaceResolver::addOrFindPrefix(const XMLCh * qName)
247{
248        int length = XMLStringU::stringLenOrIndexOf<chColon>(qName);
249    if (unlikely(length == -1))
250        {
251                return XMLUni::fgZeroLenString;
252        }
253        // get the prefix id of the prefix portion of the qName, e.g., the prefix id of "xmlns" if given "xmlns:ogc"
254        // or the prefix of "" if given "xmlns".
255        return addOrFindPrefix(qName, length)->getKey();
256}
257
258/// -----------------------------------------------------------------------------------------------
259
260IDISA_ALWAYS_INLINE
261const XMLPrefixEntry *
262XMLNamespaceResolver::findPrefix(const XMLCh * prefix, const int length) const
263{
264    DEBUG_NAMESPACE_MESSAGE("XMLNamespaceResolver::findPrefix(" << prefix << ',' << length << ')')
265    // resolve the prefix id from the prefix; since this will not be required
266    // very often, just iterate through a list.
267    for (gid_t index = 0; index < fPrefixCount; index++)
268    {
269        if (fPrefixList[index].equals(prefix, length))
270        {
271            DEBUG_NAMESPACE_MESSAGE(" -- found @ " << index)
272            return &fPrefixList[index];
273        }
274    }
275
276    return 0;
277}
278
279/// -----------------------------------------------------------------------------------------------
280
281IDISA_ALWAYS_INLINE
282const XMLCh *
283XMLNamespaceResolver::getPrefixForId(const gid_t prefixId) const
284{
285    DEBUG_NAMESPACE_MESSAGE("XMLNamespaceResolver::getPrefixForId(" << prefixId << ") " << fPrefixList.capacity())
286
287    assert (prefixId < fPrefixList.capacity());
288
289    if (likely(prefixId < fPrefixCount))
290    {
291        const XMLPrefixEntry & prefix = fPrefixList[prefixId];
292        DEBUG_MESSAGE(" &(prefix)=" << (size_t)(&prefix))
293        if (prefix.id == prefixId)
294        {
295            return prefix.getKey();
296        }
297    }
298
299    // resolve the prefix id from the prefix; since this will not be required
300    // very often, just iterate through a list.
301    for (gid_t index = 0; index < fPrefixCount; index++)
302    {
303        const XMLPrefixEntry & entry = fPrefixList[index];
304        DEBUG_MESSAGE("entry[" << index << "]=" << (size_t)(&entry))
305        if (entry.id == prefixId)
306        {
307            return entry.getKey();
308        }
309    }
310
311    return XMLUni::fgZeroLenString;
312}
313
314/// -----------------------------------------------------------------------------------------------
315
316IDISA_ALWAYS_INLINE
317const XMLPrefixEntry *
318XMLNamespaceResolver::addOrFindPrefix(const XMLCh * prefix, const int length)
319{
320    DEBUG_NAMESPACE_MESSAGE("addOrFindPrefix(" << prefix << ',' << length << ')')
321
322        // resolve the prefix id from the prefix; since this will not be required
323        // very often, just iterate through a list.
324    const XMLPrefixEntry * knownPrefix = findPrefix(prefix, length);
325    if (likely(knownPrefix != 0))
326    {
327        return knownPrefix;
328    }
329
330    const gid_t prefixId = max<size_t>(fPrefixCount, fUriPool.count());
331
332    DEBUG_NAMESPACE_MESSAGE(" -- new prefixId=max(" << fPrefixCount << ',' << fUriPool.count() << ")=" << prefixId)
333
334        if (unlikely(fPrefixToNamespaceBindingTable.setCapacity() <= prefixId))
335        {
336        DEBUG_NAMESPACE_MESSAGE(" *** EXPANDING PREFIX TABLES " << fPrefixToNamespaceBindingTable.setCapacity())
337                fCanonicalBindingSet.expand(prefixId);
338                fPrefixToNamespaceBindingTable.increaseSetCapacity(prefixId);
339                // fLocallyModifiedNamespaces.increaseBitCapacity(prefixId);
340        }
341
342    // if our prefix count equals our capacity, then we need to expand all of the related buffers
343    if (unlikely(fPrefixCount >= fPrefixList.capacity()))
344    {
345        DEBUG_NAMESPACE_MESSAGE(" -- resizing fPrefixList");
346        fPrefixList.resizeToFit(fPrefixList.capacity() * 2);
347    }
348
349    XMLPrefixEntry & newPrefix = fPrefixList[fPrefixCount++];
350        // QUESTION: does storing the prefixes in the string pool help or hinder? we can just point to
351        // the symbols and store only the prefix's length?
352        // NOTE: this may require modifying the TraverseSchema class to do this safely.
353    newPrefix.key = fPrefixPool.insert(prefix, length);
354    newPrefix.length = length;
355    newPrefix.id = prefixId;
356
357    DEBUG_NAMESPACE_MESSAGE(" &(newPrefix)=" << (size_t)(&newPrefix))
358
359        // add this entry to the canonical prefix set since we assume that the prefix and uri ids
360        // will match
361        fCanonicalBindingSet += prefixId;
362
363    return &newPrefix;
364}
365
366/// -----------------------------------------------------------------------------------------------
367
368IDISA_ALWAYS_INLINE
369gid_t
370XMLNamespaceResolver::resolveUri(const XMLCh * uri, const XMLSize_t length, const gid_t prefixId)
371{   
372    gid_t linkId = fUriPool.find(uri, length);
373    if (unlikely(linkId == XMLNamespaceResolver::fUnknownUriId))
374        {
375        DEBUG_MESSAGE(" -- adding new uriId (prefixId=" << prefixId << " of " << fUriPool.capacity() << ')')
376        linkId = prefixId;
377        if (unlikely(prefixId > fUriPool.capacity()))
378        {
379            fUriPool.resizeToFit(prefixId);
380        }
381                // is the reserved uri slot for this prefix still free?
382        else if (unlikely(fUriPool[prefixId].getKey() != NULL))
383                {
384                        // no, it was already used; claim the next unused uri id.
385            linkId = fUriPool.count();
386                }
387
388        return fUriPool.add(linkId, uri, length, fGlobalUriPool);
389        }
390    else
391    {
392        return fUriPool[linkId].getId();
393    }
394}
395
396/// -----------------------------------------------------------------------------------------------
397
398IDISA_ALWAYS_INLINE
399void
400XMLNamespaceResolver::mapPrefixToUri(const gid_t prefixId, const gid_t uriId)
401{
402    // both the prefixId and the uriId exist, but they are not mapped to one another.
403    const gid_t namespaceId = bindPrefixToUri(prefixId, uriId);
404
405    assert (fScope < fLocallyModifiedNamespaces.setCapacity());
406    assert (namespaceId < fLocallyModifiedNamespaces.bitCapacity());
407    assert (namespaceId < fCurrentlyVisibleNamespaces.capacity());
408
409    // add the new namespace to the namespace 'stack'
410    fLocallyModifiedNamespaces[fScope] += namespaceId;
411
412    // and mark it as visible
413    fCurrentlyVisibleNamespaces += namespaceId;
414}
415
416/// -----------------------------------------------------------------------------------------------
417
418IDISA_ALWAYS_INLINE
419void
420XMLNamespaceResolver::remapPrefixToUri(const gid_t prefixId, const gid_t uriId)
421{
422    const int namespaceId = bindPrefixToUri(prefixId, uriId);
423
424    BindingSet modified = (fCurrentlyVisibleNamespaces & fPrefixToNamespaceBindingTable[prefixId]);
425
426    modified = modified + namespaceId;
427    // mark any modified namespaces in the namespace 'stack'
428    fLocallyModifiedNamespaces[fScope] += modified;
429    // remove the old namespace/uri binding (if one exists) and add the new binding to the set of
430    // currently visible namespaces
431    fCurrentlyVisibleNamespaces ^= modified;
432}
433
434/// -----------------------------------------------------------------------------------------------
435
436IDISA_ALWAYS_INLINE
437gid_t
438XMLNamespaceResolver::bindPrefixToUri(const gid_t prefixId, const gid_t uriId)
439{
440    gid_t namespaceId = 0;
441
442    // Reserve the LOCAL uriId slot for this prefix; not the GLOBAL uriId slot!
443
444        BindingSetIterator namespaceItr(fPrefixToNamespaceBindingTable.get(prefixId), fPrefixToNamespaceBindingTable.bitCapacity());
445
446        size_t count = 0;
447
448        while (namespaceItr.next())
449        {
450                count++;
451
452        if (getNamespaceUriId(namespaceItr.pos()) == uriId)
453                {
454                        namespaceId = namespaceItr.pos();
455
456            DEBUG_NAMESPACE_MESSAGE(" --- found namespace mapping! " << namespaceId)
457
458                        goto FOUND_NAMESPACE_MAPPING;
459                }
460        }
461
462        namespaceId = fNextNamespaceId++;
463
464    DEBUG_NAMESPACE_MESSAGE(" --- created new namespace mapping! " << namespaceId)
465
466    if (unlikely(fCurrentlyVisibleNamespaces.capacity() <= namespaceId))
467        {
468                DEBUG_NAMESPACE_MESSAGE(" *** expanding namespace space due to namespaceId " << fNextNamespaceId);
469                fCurrentlyVisibleNamespaces.expand(namespaceId);
470                fCanonicalBindingSet.expand(namespaceId);               
471        fNamespaceToUriBindingTable.expand(namespaceId);
472        fNamespaceToPrefixBindingTable.expand(namespaceId);
473        fPrefixToNamespaceBindingTable.increaseBitCapacity(namespaceId);
474                fLocallyModifiedNamespaces.increaseBitCapacity(namespaceId);
475                fDistinctContextSet.increaseBitCapacity(namespaceId);
476        }
477
478FOUND_NAMESPACE_MAPPING:
479
480    // TODO: are declaring (or redeclaring) a namespace binding? or are we undeclaring it?
481
482    // map this prefix to the namespace and the URI back to the namespace
483    assert (fPrefixToNamespaceBindingTable.setCapacity() > prefixId);
484    assert (fPrefixToNamespaceBindingTable.bitCapacity() > namespaceId);
485    assert (fNamespaceToPrefixBindingTable.capacity() > namespaceId);
486    assert (fNamespaceToUriBindingTable.capacity() > namespaceId);
487
488    fPrefixToNamespaceBindingTable[prefixId] += namespaceId;
489    fNamespaceToPrefixBindingTable[namespaceId] = prefixId;   
490    fNamespaceToUriBindingTable[namespaceId] = uriId;
491
492    if (prefixId == uriId)
493        {
494        // if prefixId == uriId, then this entry is canonical
495                fCanonicalBindingSet += prefixId;
496        }
497        else
498        {
499        // else remove this prefixId from the canonical binding set
500                fCanonicalBindingSet -= prefixId;       
501        }
502
503        return namespaceId;
504}
505
506/// -----------------------------------------------------------------------------------------------
507
508IDISA_ALWAYS_INLINE
509void
510XMLNamespaceResolver::addPredefinedPrefix
511(
512    const gid_t id
513        , const XMLCh *         prefix
514        , const XMLSize_t       prefixLength
515        , const XMLCh *         uri
516        , const XMLSize_t       uriLength
517)
518{
519    DEBUG_MESSAGE("addPredefinedPrefix(" << id << ',' << prefix << ',' << uri << ')')
520
521
522    XMLPrefixEntry & entry = fPrefixList[id];
523        // QUESTION: does storing the prefixes in the string pool help or hinder? we can just point to
524        // the symbols and store only the prefix's length?
525        // NOTE: this may require modifying the TraverseSchema class to do this safely.
526    entry.key = prefix; // _prefixAndUriStringPool.insert(prefix, length);
527    entry.length = prefixLength;
528    entry.id = id;
529
530        // create the namespace entry and add it
531    const gid_t uriId = fUriPool.add(id, uri, uriLength, fGlobalUriPool);
532
533    assert (id == uriId);
534
535    mapPrefixToUri(id, id);
536}
537
538/// -----------------------------------------------------------------------------------------------
539/// NAMESPACE CONTEXT HANDLING
540/// -----------------------------------------------------------------------------------------------
541
542void XMLNamespaceResolver::enterScope()
543{
544    fScope++;
545    #ifdef ALLOW_NAMESPACE_SCOPE_SPECULATION
546    const binding_t * locallyModified = fLocallyModifiedNamespaces.get(fCurrentScope);
547    fSpeculatedNamespaces = locallyModified;
548    fCurrentlyVisibleNamespaces ^= locallyModified;
549    #endif
550    fLocallyModifiedNamespaces[fScope] = 0;
551}
552
553gid_t XMLNamespaceResolver::finalizeScope(const bool isEmpty, const bool containedXmlnsAttribute)
554{
555    size_t contextId;
556    if (unlikely(containedXmlnsAttribute))
557    {
558        for (contextId = 0; contextId < fDistinctContextCount; contextId++)
559        {
560            if (fDistinctContextSet[contextId] == fCurrentlyVisibleNamespaces)
561            {               
562                goto FoundExistingContextId;
563            }
564        }
565
566        if (unlikely(fDistinctContextCount == fDistinctContextSet.setCapacity()))
567        {
568            fDistinctContextSet.increaseSetCapacity(fDistinctContextSet.setCapacity());
569        }
570        contextId = fDistinctContextCount++;
571        fDistinctContextSet.set(contextId, fCurrentlyVisibleNamespaces);
572    }
573    else
574    {
575        contextId = fCurrentContextId;
576    }
577
578FoundExistingContextId:
579
580    if (isEmpty)
581    {
582        if (unlikely(containedXmlnsAttribute))
583        {
584            // if this empty tag did not contain any xmlns attributes, then it's impossible for
585            // it to have modified the visible namespaces.
586            fCurrentlyVisibleNamespaces ^= fLocallyModifiedNamespaces.get(fScope);           
587        }
588        fScope--;
589    }
590    else
591    {       
592        fCurrentContextId = contextId;
593        assert (fScope < fContextIdStack.capacity());
594        fContextIdStack[fScope] = contextId;
595    }
596    return contextId;
597}
598
599gid_t XMLNamespaceResolver::leaveScope(bool & namespaceContextChange)
600{
601    fCurrentlyVisibleNamespaces ^= fLocallyModifiedNamespaces.get(fScope--);
602    const gid_t contextId = fContextIdStack[fScope];
603    namespaceContextChange = (contextId != fCurrentContextId);
604    fCurrentContextId = contextId;
605    return contextId;
606}
607
608
609/// -----------------------------------------------------------------------------------------------
610
611IDISA_ALWAYS_INLINE
612BindingSetIterator XMLNamespaceResolver::getNamespaceIterator(const gid_t contextId) const
613{
614    assert (contextId < fDistinctContextSet.setCapacity());
615
616    return BindingSetIterator(fDistinctContextSet[contextId]);
617}
618
619/// -----------------------------------------------------------------------------------------------
620
621IDISA_ALWAYS_INLINE
622MaskedBindingSetIterator XMLNamespaceResolver::getNamespaceIterator(const gid_t contextId0, const gid_t contextId1) const
623{
624    assert (contextId0 < fDistinctContextSet.setCapacity());
625    assert (contextId1 < fDistinctContextSet.setCapacity());
626
627    return MaskedBindingSetIterator(fDistinctContextSet[contextId0], fDistinctContextSet[contextId1], true);
628}
629
630/// -----------------------------------------------------------------------------------------------
631
632IDISA_ALWAYS_INLINE
633gid_t
634XMLNamespaceResolver::getSchemaNamespaceId()
635{
636    if (unlikely(fSchemaNamespaceId == XMLNamespaceResolver::fUnknownUriId))
637    {
638        fSchemaNamespaceId = fGlobalUriPool->addOrFind(SchemaSymbols::fgURI_SCHEMAFORSCHEMA);
639    }
640    return fSchemaNamespaceId;
641}
642
643/// -----------------------------------------------------------------------------------------------
644
645IDISA_ALWAYS_INLINE
646gid_t
647XMLNamespaceResolver::getNamespaceUriId(const gid_t namespaceId) const
648{
649    return fNamespaceToUriBindingTable[namespaceId];
650}
651
652/// -----------------------------------------------------------------------------------------------
653
654IDISA_ALWAYS_INLINE
655const XMLCh *
656XMLNamespaceResolver::getPrefixForNamespaceId(const gid_t namespaceId) const
657{
658    assert (namespaceId < fNamespaceToPrefixBindingTable.capacity());
659    return getPrefixForId(fNamespaceToPrefixBindingTable[namespaceId]);
660}
661
662/// -----------------------------------------------------------------------------------------------
663
664IDISA_ALWAYS_INLINE
665const XMLCh *
666XMLNamespaceResolver::getUriForNamespaceId(const gid_t namespaceId) const
667{
668    assert (namespaceId < fNamespaceToUriBindingTable.capacity());
669    return getUriForId(fNamespaceToUriBindingTable[namespaceId]);
670}
671
672/// -----------------------------------------------------------------------------------------------
673
674IDISA_ALWAYS_INLINE
675bool
676XMLNamespaceResolver::isPrefixVisible(const XMLCh * prefix, const gid_t contextId) const
677{
678    int colonPos;
679    const gid_t prefixId = resolvePrefixId(prefix, colonPos);
680        return isPrefixVisible(prefixId, contextId);
681}
682
683/// -----------------------------------------------------------------------------------------------
684
685IDISA_ALWAYS_INLINE
686bool
687XMLNamespaceResolver::isPrefixVisible(const gid_t prefixId) const
688{
689    if (unlikely(prefixId == XMLNamespaceResolver::fUnknownUriId))
690    {
691        return false;
692    }   
693    const int namespaceId = resolveNamespaceId(prefixId);
694
695    if (unlikely(namespaceId == -1))
696    {
697        return false;
698    }
699    else
700    {
701        return (getNamespaceUriId(namespaceId) != XMLNamespaceResolver::fUnknownUriId);
702    }
703}
704
705/// -----------------------------------------------------------------------------------------------
706
707IDISA_ALWAYS_INLINE
708bool
709XMLNamespaceResolver::isPrefixVisible(const gid_t prefixId, const gid_t contextId) const
710{
711    if (unlikely(prefixId == XMLNamespaceResolver::fUnknownUriId))
712    {
713        return false;
714    }
715
716    const gid_t namespaceId = fPrefixToNamespaceBindingTable[prefixId].first(fDistinctContextSet[contextId]);
717    if (unlikely(namespaceId == -1))
718    {
719        return false;
720    }
721    else
722    {
723        return (getNamespaceUriId(namespaceId) != XMLNamespaceResolver::fUnknownUriId);
724    }
725}
726
727/// -----------------------------------------------------------------------------------------------
728
729IDISA_ALWAYS_INLINE
730gid_t
731XMLNamespaceResolver::getUriIdForQName(const XMLCh * prefix, const gid_t contextId, int & colonPos) const
732{
733    gid_t prefixId = resolvePrefixId(prefix, colonPos);
734    return getUriIdForPrefix(prefixId, contextId);
735}
736
737/// -----------------------------------------------------------------------------------------------
738
739IDISA_ALWAYS_INLINE
740gid_t
741XMLNamespaceResolver::getUriIdForPrefix(const XMLCh * prefix, const gid_t contextId) const
742{
743    int colonPos;
744    return getUriIdForPrefix(resolvePrefixId(prefix, colonPos), contextId);
745}
746
747/// -----------------------------------------------------------------------------------------------
748
749IDISA_ALWAYS_INLINE
750gid_t
751XMLNamespaceResolver::getUriIdForPrefix(const gid_t prefixId, const gid_t contextId) const
752{
753    if (unlikely(prefixId == fUnknownUriId))
754    {
755        return fUnknownUriId;
756    }
757    MaskedBindingSetIterator namespaceItr(fDistinctContextSet[contextId], fPrefixToNamespaceBindingTable[prefixId], false);
758        if (unlikely(!namespaceItr.first()))
759        {
760                return fUnknownUriId;
761        }
762        return fNamespaceToUriBindingTable[namespaceItr.pos()];
763}
764
765/// -----------------------------------------------------------------------------------------------
766
767IDISA_ALWAYS_INLINE
768const XMLCh *
769XMLNamespaceResolver::getUriForQName(const XMLCh * prefix, const gid_t contextId, int & colonPos) const
770{
771    gid_t uriId = getUriIdForQName(prefix, contextId, colonPos);
772    return getUriForId(uriId);
773}
774
775
776/// -----------------------------------------------------------------------------------------------
777
778IDISA_ALWAYS_INLINE
779const XMLCh *
780XMLNamespaceResolver::getUriForPrefix(const XMLCh * prefix, const gid_t contextId) const
781{
782    int colonPos;
783    return getUriForPrefix(resolvePrefixId(prefix, colonPos), contextId);
784}
785
786/// -----------------------------------------------------------------------------------------------
787
788IDISA_ALWAYS_INLINE
789const XMLCh *
790XMLNamespaceResolver::getUriForPrefix(const gid_t prefixId, const gid_t contextId) const
791{   
792    return getUriForId(getUriIdForPrefix(prefixId, contextId));
793}
794
795/// -----------------------------------------------------------------------------------------------
796
797#ifdef PRINT_DEBUG_MESSAGE
798static std::ostream & operator << (std::ostream & out, const XMLNamespaceResolver * resolver)
799{
800        if (resolver)
801        {
802                char leadingChar = '{';
803                const XMLCh * uri;
804
805        for (gid_t uriId = 0; uriId < resolver->getUriCount(); uriId++)
806                {
807                        if ((uri = (*resolver)[uriId]) != 0)
808                        {
809                                out << leadingChar << uriId << ':' << uri;
810                                leadingChar = ',';
811                        }
812                }
813                if (leadingChar != '{')
814                {
815                        out << '}';
816                }
817        }
818        return out;
819}
820#endif
821
822XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.