source: icXML/icXML-0.95/src/icxmlc/XMLNamespaceResolver.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: 10.2 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.hpp 388 2013-10-29 21:25:27Z nigelm $
10 *
11 */
12
13#if !defined(XMLNAMESPACETABLE_H)
14#define XMLNAMESPACETABLE_H
15
16#include <icxmlc/HashTable.hpp>
17#include <xercesc/util/XMLUni.hpp>
18#include <icxmlc/stringpool.h>
19#include <xercesc/framework/MemoryManager.hpp>
20#include <icxercesc/util/XMLString.hpp>
21#include <xercesc/util/XMLUni.hpp>
22#include <icxercesc/util/QName.hpp>
23#include <xercesc/util/StringPool.hpp>
24#include <icxmlc/XMLNamespaceBindingSet.hpp>
25#include <icxmlc/XMLStringHash.hpp>
26#include <icxmlc/XMLStringU.hpp>
27#include <icxmlc/XMLNamespaceUriTable.hpp>
28#include <xercesc/framework/XMLErrorCodes.hpp>
29#include <icxmlc/XMLConfig.hpp>
30
31XERCES_CPP_NAMESPACE_BEGIN
32
33class XMLNamespaceResolver;
34class XMLSynchronizedNamespaceResolver;
35class XMLNamespaceIterator;
36class XMLSymbol;
37class XMLScanner;
38
39#define DEFAULT_PREFIX_POOL_SIZE 256
40#define CANONICAL_BINDS_PREFIX_TO_GLOBAL_URI_ID
41
42#ifdef PRINT_DEBUG_MESSAGE
43static std::ostream & operator << (std::ostream & out, const XMLNamespaceResolver * resolver);
44#endif
45
46/** --------------------------------------------------------------------------------------------------------- **/
47class XMLPrefixEntry
48{
49        friend class XMLNamespaceResolver;
50        friend class XMLSynchronizedNamespaceResolver;
51
52        protected:
53
54                const XMLCh *  key;
55        gid_t   length;
56        gid_t   id;
57
58                // QUESTION: should this contain a set of flags that indicates whether this prefix is XML, XMLNS, or is
59                // associated with a XSI uri? Or should this contain a list of associated symbols?
60
61        public:
62
63                XMLPrefixEntry()
64                : key(NULL)
65                , length(0)
66                , id(0)
67                {
68
69                }
70
71        ~XMLPrefixEntry()
72        {
73
74        }
75
76        const XMLCh * getKey() const
77        {
78            return key;
79        }
80
81        gid_t getLength() const { return length; }
82
83        gid_t getId() const { return id; }
84
85                XMLPrefixEntry & operator=(const XMLPrefixEntry & other)
86                {
87                        key = other.key;
88                        length = other.length;
89                        id = other.id;
90                        return *this;
91                }
92
93                IDISA_ALWAYS_INLINE
94        bool equals(const XMLCh * otherKey, const XMLSize_t length) const
95                {
96                        // QUESTION: would a length based dispatch be preferable here? prefixes are likely relatively short
97            return (getLength() == length) && (XMLStringU::equals(otherKey, getKey(), length));
98                }
99};
100
101/// ---------------------------------------------------------------------------------------------------------
102
103class XMLNamespaceResolver
104{
105        friend class XMLSynchronizedNamespaceResolver;
106        friend class XMLNamespaceIterator;
107    template<class ScannerType> friend class XMLNamespaceParser;
108
109        public:
110
111                enum PredefinedNamespaces
112                {
113                        fUnknownUriId                   = -1
114                        , fEmptyUriId                   = 0
115                        , fXMLUriId                             = 1
116                        , fXMLNSUriId                   = 2
117                        , fSchemaInstanceUriId  = 3
118
119                        , fPredefinedCount              = 4
120                };
121
122        // TODO: would adding SchemaSymbols::fgURI_SCHEMAFORSCHEMA as a predefined uri help?
123
124        XMLNamespaceResolver(XMLStringPool * globalUriPool, MemoryManager* manager)
125        : fScope(0)
126        , fNextNamespaceId(0)
127        , fPrefixCount(fPredefinedCount)
128        , fCurrentContextId(0)
129        , fDistinctContextCount(1)
130        , fGlobalUriPool(globalUriPool)
131        , fSchemaNamespaceId(fUnknownUriId)
132        , fUriPool(manager)
133        , fPrefixPool(manager)       
134                {
135                        addPredefinedPrefix(fEmptyUriId, XMLUni::fgZeroLenString, 0, XMLUni::fgZeroLenString, 0);
136                        addPredefinedPrefix(fXMLUriId, XMLUni::fgXMLString, 3, XMLUni::fgXMLURIName, 36);
137                        addPredefinedPrefix(fXMLNSUriId, XMLUni::fgXMLNSString, 5, XMLUni::fgXMLNSURIName, 29);
138                        addPredefinedPrefix(fSchemaInstanceUriId, SchemaSymbols::fgXSI, 3, SchemaSymbols::fgURI_XSI, 41);           
139
140            // mark the 'always visible' namespaces
141            fCurrentlyVisibleNamespaces.set((1 << fEmptyUriId) | (1 << fXMLUriId) | (1 << fXMLNSUriId));
142            // store this context set permanently
143            fDistinctContextSet.set(0, fCurrentlyVisibleNamespaces);
144                }
145
146                ~XMLNamespaceResolver()
147                {
148
149                }
150
151        gid_t bindNamespace(const XMLSymbol & symbol, const XMLCh * uri, const XMLSize_t length, const bool isXMLV1_1, bool & speculatedCorrectly);
152
153        gid_t resolveUriId(const XMLSymbol & symbol, const bool isAttribute) const;
154
155        gid_t resolveUriId(const XMLSymbol & symbol, const bool isAttribute, const bool misspeculated, bool & unknown) const;
156
157        gid_t resolveUriId(const XMLCh * uri) const;
158
159        // gid_t resolveUriId(const QName * qName);
160
161        size_t getMaxScope()
162        {
163            return fLocallyModifiedNamespaces.setCapacity();
164        }
165
166        void setMaxScope(const size_t maxScope)
167        {
168            if (maxScope < getMaxScope()) return;
169            fLocallyModifiedNamespaces.increaseSetCapacity(maxScope);
170            fContextIdStack.resizeToFit(fScope, getMaxScope());
171        }
172
173        IDISA_ALWAYS_INLINE
174        gid_t getSchemaNamespaceId();
175
176                IDISA_ALWAYS_INLINE
177        void enterScope();
178
179        IDISA_ALWAYS_INLINE
180        gid_t finalizeScope(const bool isEmpty, const bool containedXmlnsAttribute);
181
182                IDISA_ALWAYS_INLINE
183        gid_t leaveScope(bool & namespaceContextChange);
184
185                IDISA_ALWAYS_INLINE
186                void misspeculated()
187                {
188                        #ifdef ALLOW_NAMESPACE_SCOPE_SPECULATION
189            fCurrentlyVisibleNamespaces ^= fSpeculatedNamespaces - fLocallyModifiedNamespaces[fScope];
190                        #endif
191                }
192
193                IDISA_ALWAYS_INLINE
194                int getScope()
195                {
196            return fScope;
197                }
198
199        gid_t getNamespaceUriId(const gid_t namespaceId) const;
200
201        BindingSetIterator getNamespaceIterator(const gid_t contextId) const;
202
203        MaskedBindingSetIterator getNamespaceIterator(const gid_t contextId, const gid_t prevContextId) const;
204
205        const XMLCh * getPrefixForNamespaceId(const gid_t namespaceId) const;
206
207        const XMLCh * getUriForNamespaceId(const gid_t namespaceId) const;
208
209        bool isPrefixVisible(const XMLCh * prefix, const gid_t contextId) const;
210
211        bool isPrefixVisible(const gid_t prefixId) const;
212
213        bool isPrefixVisible(const gid_t prefixId, const gid_t contextId) const;
214
215        const XMLCh * getUriForQName(const XMLCh * prefix, const gid_t contextId, int & colonPos) const;
216
217        const XMLCh * getUriForPrefix(const XMLCh * prefix, const gid_t contextId) const;
218
219        const XMLCh * getUriForPrefix(const gid_t prefixId, const gid_t contextId) const;
220
221        gid_t getUriIdForQName(const XMLCh * prefix, const gid_t contextId, int & colonPos) const;
222
223        gid_t getUriIdForPrefix(const XMLCh * prefix, const gid_t contextId) const;
224
225        gid_t getUriIdForPrefix(const gid_t prefixId, const gid_t contextId) const;
226
227        gid_t resolvePrefixId(const XMLCh * qName, int & colonPos) const;
228
229        gid_t addOrFindPrefixId(const XMLCh * qName, const XMLSize_t length);
230
231        gid_t addOrFindPrefixId(const XMLCh * qName, const XMLSize_t length, int & colon);
232
233
234
235                const XMLCh * addOrFindPrefix(const XMLCh * qName);
236
237                IDISA_ALWAYS_INLINE
238        const XMLCh * operator[](const gid_t uriId) const
239                {
240            return fGlobalUriPool->getValueForId(uriId);
241                }
242
243                IDISA_ALWAYS_INLINE
244        const XMLCh * getUriForId(const gid_t uriId, const bool isAttribute = 0) const
245                {
246            if (unlikely((isAttribute && (uriId == fEmptyUriId)) || (uriId == (gid_t)(fUnknownUriId))))
247                        {
248                                return NULL;
249                        }
250                        const XMLCh * uri = (*this)[uriId];
251                        if (unlikely(!uri))
252                        {
253                                uri = XMLUni::fgZeroLenString;
254                        }
255                        return uri;
256                }
257
258        inline size_t getUriCount() const
259                {
260            return fGlobalUriPool->getStringCount();
261                }
262
263        inline gid_t getCurrentContextId() const
264        {
265            return fCurrentContextId;
266        }
267
268                IDISA_ALWAYS_INLINE
269        const XMLCh * getPrefixForId(const gid_t prefixId) const;
270
271                #ifdef PRINT_DEBUG_MESSAGE
272                friend std::ostream & operator << (std::ostream &, const XMLNamespaceResolver *);
273                #endif
274
275        private:
276
277        gid_t resolveUriId(const gid_t prefixId, const gid_t defaultUriId, bool & unknown) const;
278
279        const XMLPrefixEntry * findPrefix(const XMLCh * prefix, const int length) const;
280
281                const XMLPrefixEntry * addOrFindPrefix(const XMLCh * prefix, const int length);
282
283        gid_t resolveUri(const XMLCh * uri, const XMLSize_t length, const gid_t preferredUriId);
284
285        void mapPrefixToUri(const gid_t prefixId, const gid_t uriId);
286
287        void remapPrefixToUri(const gid_t prefixId, const gid_t uriId);
288
289        gid_t bindPrefixToUri(const gid_t prefixId, const gid_t uriId);
290
291                IDISA_ALWAYS_INLINE
292        int resolveNamespaceId(const gid_t prefixId) const
293                {
294            return fCurrentlyVisibleNamespaces.first(fPrefixToNamespaceBindingTable[prefixId]);
295                }
296
297        void addPredefinedPrefix(const gid_t id, const XMLCh * prefix, const XMLSize_t prefixLength, const XMLCh * uri, const XMLSize_t uriLength);
298
299        private:
300
301        size_t                                                                                                  fScope;     
302        gid_t                                                                                                   fNextNamespaceId;
303        gid_t                                                                                                   fPrefixCount;
304        gid_t                                                                                                   fCurrentContextId;
305        size_t                                                                                                  fDistinctContextCount;
306
307        XMLStringPool * const                                   fGlobalUriPool;
308
309        gid_t                                                   fSchemaNamespaceId;
310
311        BindingSet                                                                                              fCurrentlyVisibleNamespaces;
312        BindingSet                                                                                              fCanonicalBindingSet;
313                #ifdef ALLOW_NAMESPACE_SCOPE_SPECULATION
314        BindingSet                                                                                              fSpeculatedNamespaces;
315                #endif
316
317        DynamicArray<gid_t, INITIAL_MAX_SCOPE>                  fContextIdStack;
318        BindingSets<sizeof(hash_t) * 8>                                                 fPrefixToNamespaceBindingTable;       
319        DynamicArray<gid_t, sizeof(hash_t) * 8>                                 fNamespaceToUriBindingTable;       
320        DynamicArray<gid_t, sizeof(hash_t) * 8>                                 fNamespaceToPrefixBindingTable;       
321        BindingSets<INITIAL_MAX_SCOPE>                                                  fLocallyModifiedNamespaces;
322        DynamicArray<XMLPrefixEntry, sizeof(hash_t) * 8>                fPrefixList;
323        XMLNamespaceTable                                                                               fUriPool;       
324        BindingSets<INITIAL_MAX_SCOPE>                                                  fDistinctContextSet;       
325        StringPool<XMLCh, DEFAULT_PREFIX_POOL_SIZE>             fPrefixPool;
326};
327
328XERCES_CPP_NAMESPACE_END
329
330#if !defined(XERCES_TMPLSINC)
331#include <icxmlc/XMLNamespaceResolver.c>
332#endif
333
334#endif // XMLNAMESPACETABLE_H
Note: See TracBrowser for help on using the repository browser.