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 | |
---|
17 | XERCES_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 | |
---|
25 | IDISA_ALWAYS_INLINE |
---|
26 | gid_t |
---|
27 | XMLNamespaceResolver::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 | |
---|
105 | IDISA_ALWAYS_INLINE |
---|
106 | gid_t |
---|
107 | XMLNamespaceResolver::resolveUriId(const XMLSymbol & symbol, const bool isAttribute) const |
---|
108 | { |
---|
109 | bool unknown = 0; |
---|
110 | return resolveUriId(symbol, isAttribute, false, unknown); |
---|
111 | } |
---|
112 | |
---|
113 | /// ----------------------------------------------------------------------------------------------- |
---|
114 | |
---|
115 | IDISA_ALWAYS_INLINE |
---|
116 | gid_t |
---|
117 | XMLNamespaceResolver::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 | |
---|
128 | IDISA_ALWAYS_INLINE |
---|
129 | gid_t |
---|
130 | XMLNamespaceResolver::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 | |
---|
161 | IDISA_ALWAYS_INLINE |
---|
162 | gid_t |
---|
163 | XMLNamespaceResolver::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 | |
---|
199 | IDISA_ALWAYS_INLINE |
---|
200 | gid_t |
---|
201 | XMLNamespaceResolver::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 | |
---|
225 | IDISA_ALWAYS_INLINE |
---|
226 | gid_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 | |
---|
234 | IDISA_ALWAYS_INLINE |
---|
235 | gid_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 | |
---|
244 | IDISA_ALWAYS_INLINE |
---|
245 | const XMLCh * |
---|
246 | XMLNamespaceResolver::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 | |
---|
260 | IDISA_ALWAYS_INLINE |
---|
261 | const XMLPrefixEntry * |
---|
262 | XMLNamespaceResolver::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 | |
---|
281 | IDISA_ALWAYS_INLINE |
---|
282 | const XMLCh * |
---|
283 | XMLNamespaceResolver::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 | |
---|
316 | IDISA_ALWAYS_INLINE |
---|
317 | const XMLPrefixEntry * |
---|
318 | XMLNamespaceResolver::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 | |
---|
368 | IDISA_ALWAYS_INLINE |
---|
369 | gid_t |
---|
370 | XMLNamespaceResolver::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 | |
---|
398 | IDISA_ALWAYS_INLINE |
---|
399 | void |
---|
400 | XMLNamespaceResolver::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 | |
---|
418 | IDISA_ALWAYS_INLINE |
---|
419 | void |
---|
420 | XMLNamespaceResolver::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 | |
---|
436 | IDISA_ALWAYS_INLINE |
---|
437 | gid_t |
---|
438 | XMLNamespaceResolver::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 | |
---|
478 | FOUND_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 | |
---|
508 | IDISA_ALWAYS_INLINE |
---|
509 | void |
---|
510 | XMLNamespaceResolver::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 | |
---|
542 | void 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 | |
---|
553 | gid_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 | |
---|
578 | FoundExistingContextId: |
---|
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 | |
---|
599 | gid_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 | |
---|
611 | IDISA_ALWAYS_INLINE |
---|
612 | BindingSetIterator XMLNamespaceResolver::getNamespaceIterator(const gid_t contextId) const |
---|
613 | { |
---|
614 | assert (contextId < fDistinctContextSet.setCapacity()); |
---|
615 | |
---|
616 | return BindingSetIterator(fDistinctContextSet[contextId]); |
---|
617 | } |
---|
618 | |
---|
619 | /// ----------------------------------------------------------------------------------------------- |
---|
620 | |
---|
621 | IDISA_ALWAYS_INLINE |
---|
622 | MaskedBindingSetIterator 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 | |
---|
632 | IDISA_ALWAYS_INLINE |
---|
633 | gid_t |
---|
634 | XMLNamespaceResolver::getSchemaNamespaceId() |
---|
635 | { |
---|
636 | if (unlikely(fSchemaNamespaceId == XMLNamespaceResolver::fUnknownUriId)) |
---|
637 | { |
---|
638 | fSchemaNamespaceId = fGlobalUriPool->addOrFind(SchemaSymbols::fgURI_SCHEMAFORSCHEMA); |
---|
639 | } |
---|
640 | return fSchemaNamespaceId; |
---|
641 | } |
---|
642 | |
---|
643 | /// ----------------------------------------------------------------------------------------------- |
---|
644 | |
---|
645 | IDISA_ALWAYS_INLINE |
---|
646 | gid_t |
---|
647 | XMLNamespaceResolver::getNamespaceUriId(const gid_t namespaceId) const |
---|
648 | { |
---|
649 | return fNamespaceToUriBindingTable[namespaceId]; |
---|
650 | } |
---|
651 | |
---|
652 | /// ----------------------------------------------------------------------------------------------- |
---|
653 | |
---|
654 | IDISA_ALWAYS_INLINE |
---|
655 | const XMLCh * |
---|
656 | XMLNamespaceResolver::getPrefixForNamespaceId(const gid_t namespaceId) const |
---|
657 | { |
---|
658 | assert (namespaceId < fNamespaceToPrefixBindingTable.capacity()); |
---|
659 | return getPrefixForId(fNamespaceToPrefixBindingTable[namespaceId]); |
---|
660 | } |
---|
661 | |
---|
662 | /// ----------------------------------------------------------------------------------------------- |
---|
663 | |
---|
664 | IDISA_ALWAYS_INLINE |
---|
665 | const XMLCh * |
---|
666 | XMLNamespaceResolver::getUriForNamespaceId(const gid_t namespaceId) const |
---|
667 | { |
---|
668 | assert (namespaceId < fNamespaceToUriBindingTable.capacity()); |
---|
669 | return getUriForId(fNamespaceToUriBindingTable[namespaceId]); |
---|
670 | } |
---|
671 | |
---|
672 | /// ----------------------------------------------------------------------------------------------- |
---|
673 | |
---|
674 | IDISA_ALWAYS_INLINE |
---|
675 | bool |
---|
676 | XMLNamespaceResolver::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 | |
---|
685 | IDISA_ALWAYS_INLINE |
---|
686 | bool |
---|
687 | XMLNamespaceResolver::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 | |
---|
707 | IDISA_ALWAYS_INLINE |
---|
708 | bool |
---|
709 | XMLNamespaceResolver::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 | |
---|
729 | IDISA_ALWAYS_INLINE |
---|
730 | gid_t |
---|
731 | XMLNamespaceResolver::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 | |
---|
739 | IDISA_ALWAYS_INLINE |
---|
740 | gid_t |
---|
741 | XMLNamespaceResolver::getUriIdForPrefix(const XMLCh * prefix, const gid_t contextId) const |
---|
742 | { |
---|
743 | int colonPos; |
---|
744 | return getUriIdForPrefix(resolvePrefixId(prefix, colonPos), contextId); |
---|
745 | } |
---|
746 | |
---|
747 | /// ----------------------------------------------------------------------------------------------- |
---|
748 | |
---|
749 | IDISA_ALWAYS_INLINE |
---|
750 | gid_t |
---|
751 | XMLNamespaceResolver::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 | |
---|
767 | IDISA_ALWAYS_INLINE |
---|
768 | const XMLCh * |
---|
769 | XMLNamespaceResolver::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 | |
---|
778 | IDISA_ALWAYS_INLINE |
---|
779 | const XMLCh * |
---|
780 | XMLNamespaceResolver::getUriForPrefix(const XMLCh * prefix, const gid_t contextId) const |
---|
781 | { |
---|
782 | int colonPos; |
---|
783 | return getUriForPrefix(resolvePrefixId(prefix, colonPos), contextId); |
---|
784 | } |
---|
785 | |
---|
786 | /// ----------------------------------------------------------------------------------------------- |
---|
787 | |
---|
788 | IDISA_ALWAYS_INLINE |
---|
789 | const XMLCh * |
---|
790 | XMLNamespaceResolver::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 |
---|
798 | static 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 | |
---|
822 | XERCES_CPP_NAMESPACE_END |
---|