source: icXML/icXML-devel/src/xercesc/dom/impl/DOMNormalizer.cpp @ 2722

Last change on this file since 2722 was 2722, checked in by cameron, 6 years ago

Original Xerces files with import mods for icxercesc

File size: 16.4 KB
Line 
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <xercesc/dom/DOMAttr.hpp>
19#include <xercesc/dom/DOMNode.hpp>
20#include <xercesc/dom/DOMErrorHandler.hpp>
21#include <xercesc/dom/DOMError.hpp>
22#include <xercesc/dom/DOMText.hpp>
23#include <icxercesc/framework/XMLBuffer.hpp>
24
25#include <xercesc/util/Mutexes.hpp>
26#include <icxercesc/util/PlatformUtils.hpp>
27#include <xercesc/util/XMLInitializer.hpp>
28#include <xercesc/util/XMLMsgLoader.hpp>
29#include <icxercesc/util/XMLString.hpp>
30#include <xercesc/util/XMLUni.hpp>
31#include <xercesc/util/XMLUniDefs.hpp>
32
33#include "DOMConfigurationImpl.hpp"
34#include "DOMDocumentImpl.hpp"
35#include "DOMElementImpl.hpp"
36#include "DOMErrorImpl.hpp"
37#include "DOMEntityReferenceImpl.hpp"
38#include "DOMNormalizer.hpp"
39#include "DOMTextImpl.hpp"
40
41XERCES_CPP_NAMESPACE_BEGIN
42
43static XMLMsgLoader*   gMsgLoader = 0;
44
45void XMLInitializer::initializeDOMNormalizer()
46{
47    gMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgXMLErrDomain);
48
49    if (!gMsgLoader)
50      XMLPlatformUtils::panic(PanicHandler::Panic_CantLoadMsgDomain);
51}
52
53void XMLInitializer::terminateDOMNormalizer()
54{
55    delete gMsgLoader;
56    gMsgLoader = 0;
57}
58
59//
60//
61DOMNormalizer::DOMNormalizer(MemoryManager* const manager)
62    : fDocument(0)
63    , fConfiguration(0)
64    , fErrorHandler(0)
65    , fNSScope(0)
66    , fNewNamespaceCount(1)
67    , fMemoryManager(manager)
68{
69    fNSScope = new (fMemoryManager) InScopeNamespaces(fMemoryManager);
70}
71
72DOMNormalizer::~DOMNormalizer() {
73    delete fNSScope;
74}
75
76void DOMNormalizer::normalizeDocument(DOMDocumentImpl *doc) {
77
78    fDocument = doc;
79    fConfiguration = (DOMConfigurationImpl*)doc->getDOMConfig();
80    DOMConfigurationImpl *dci = (DOMConfigurationImpl*)fDocument->getDOMConfig();
81    if(dci)
82        fErrorHandler = dci->getErrorHandler();
83    else
84        fErrorHandler = 0;
85
86    DOMNode *child = 0;
87    DOMNode *next = 0;
88    ((DOMNormalizer *)this)->fNewNamespaceCount = 1;
89
90    for(child = doc->getFirstChild();child != 0; child = next) {
91        next = child->getNextSibling();
92        child = normalizeNode(child);
93        if(child != 0) {
94            next = child;
95        }
96    }
97}
98
99DOMNode * DOMNormalizer::normalizeNode(DOMNode *node) const {
100    switch(node->getNodeType()) {
101    case DOMNode::ELEMENT_NODE: {
102        fNSScope->addScope(fMemoryManager);
103        DOMNamedNodeMap *attrMap = node->getAttributes();
104
105        if(fConfiguration->featureValues & DOMConfigurationImpl::FEATURE_NAMESPACES) {
106            namespaceFixUp((DOMElementImpl*)node);
107        }
108        else {
109            //this is done in namespace fixup so no need to do it if namespace is on
110            if(attrMap) {
111                for(XMLSize_t i = 0; i < attrMap->getLength(); i++) {
112                    attrMap->item(i)->normalize();
113                }
114            }
115        }
116
117        DOMNode *child = node->getFirstChild();
118        DOMNode *next = 0;
119        for (; child != 0; child = next) {
120            next = child->getNextSibling();
121            child = normalizeNode(child);
122            if(child != 0) {
123                next = child;
124            }
125        }
126        fNSScope->removeScope();
127        break;
128    }
129    case DOMNode::COMMENT_NODE: {
130        if (!(fConfiguration->featureValues & DOMConfigurationImpl::FEATURE_COMMENTS)) {
131            DOMNode *prevSibling = node->getPreviousSibling();
132            DOMNode *parent = node->getParentNode();
133            // remove the comment node
134            parent->removeChild(node);
135            if (prevSibling != 0 && prevSibling->getNodeType() == DOMNode::TEXT_NODE) {
136                DOMNode *nextSibling = prevSibling->getNextSibling();
137                if (nextSibling != 0 && nextSibling->getNodeType() == DOMNode::TEXT_NODE) {
138                    ((DOMTextImpl*)nextSibling)->insertData(0, prevSibling->getNodeValue());
139                    parent->removeChild(prevSibling);
140                    return nextSibling;
141                }
142            }
143        }
144        break;
145    }
146    case DOMNode::CDATA_SECTION_NODE: {
147        if (!(fConfiguration->featureValues & DOMConfigurationImpl::FEATURE_CDATA_SECTIONS)) {
148            // convert CDATA to TEXT nodes
149            DOMText *text = fDocument->createTextNode(node->getNodeValue());
150            DOMNode *parent = node->getParentNode();
151            DOMNode *prevSibling = node->getPreviousSibling();
152            node = parent->replaceChild(text, node);
153            if (prevSibling != 0 && prevSibling->getNodeType() == DOMNode::TEXT_NODE) {
154                text->insertData(0, prevSibling->getNodeValue());
155                parent->removeChild(prevSibling);
156            }
157            return text; // Don't advance;
158        }
159        break;
160    }
161    case DOMNode::TEXT_NODE: {
162        DOMNode *next = node->getNextSibling();
163
164        if(next != 0 && next->getNodeType() == DOMNode::TEXT_NODE) {
165            ((DOMText*)node)->appendData(next->getNodeValue());
166            node->getParentNode()->removeChild(next);
167            return node;
168        } else {
169            const XMLCh* nv = node->getNodeValue();
170            if (nv == 0 || *nv == 0) {
171                node->getParentNode()->removeChild(node);
172            }
173        }
174    }
175    default:
176        break;
177    }
178
179    return 0;
180}
181
182
183void DOMNormalizer::namespaceFixUp(DOMElementImpl *ele) const {
184    DOMAttrMapImpl *attrMap = ele->fAttributes;
185
186    XMLSize_t len = attrMap->getLength();
187    //get the ns info from the attrs
188    for(XMLSize_t i = 0; i < len; i++) {
189        DOMAttr *at = (DOMAttr*)attrMap->item(i);
190
191        //normalize the attr whatever happens
192        at->normalize();
193
194        const XMLCh *uri = at->getNamespaceURI();
195        const XMLCh *value = at->getNodeValue();
196
197        if(XMLString::equals(XMLUni::fgXMLNSURIName, uri)) {
198            if(XMLString::equals(XMLUni::fgXMLNSURIName, value)) {
199                error(XMLErrs::NSDeclInvalid, ele);
200            }
201            else {
202                const XMLCh *prefix = at->getPrefix();
203
204                if(XMLString::equals(prefix, XMLUni::fgXMLNSString)) {
205                    fNSScope->addOrChangeBinding(at->getLocalName(), value, fMemoryManager);
206                }
207                else {
208                    fNSScope->addOrChangeBinding(XMLUni::fgZeroLenString, value, fMemoryManager);
209                }
210            }
211        }
212    }
213
214    const XMLCh* prefix = ele->getPrefix();
215    prefix ? prefix : prefix = XMLUni::fgZeroLenString;
216    const XMLCh* uri = ele->getNamespaceURI();
217    uri ? uri : uri = XMLUni::fgZeroLenString;
218
219    if(!XMLString::equals(uri, XMLUni::fgZeroLenString)) {
220        if(!fNSScope->isValidBinding(prefix, uri)) {
221            addOrChangeNamespaceDecl(prefix, uri, ele);
222            fNSScope->addOrChangeBinding(prefix, uri, fMemoryManager);
223        }
224    }
225    else {
226        if(ele->getLocalName() == 0) {
227            error(XMLErrs::DOMLevel1Node, ele);
228        }
229        else if(!fNSScope->isValidBinding(XMLUni::fgZeroLenString, XMLUni::fgZeroLenString)) {
230            addOrChangeNamespaceDecl(XMLUni::fgZeroLenString, XMLUni::fgZeroLenString, ele);
231            fNSScope->addOrChangeBinding(XMLUni::fgZeroLenString, XMLUni::fgZeroLenString, fMemoryManager);
232        }
233    }
234
235    //fix up non ns attrs
236    len = attrMap->getLength();
237
238    // hp aCC complains this i is a redefinition of the i on line 283
239    for(XMLSize_t j = 0; j < len; j++) {
240        DOMAttr *at = (DOMAttr*)attrMap->item(j);
241        const XMLCh *uri = at->getNamespaceURI();
242        const XMLCh* prefix = at->getPrefix();
243
244        if(!XMLString::equals(XMLUni::fgXMLNSURIName, uri)) {
245            if(uri != 0) {
246                if(prefix == 0 || !fNSScope->isValidBinding(prefix, uri)) {
247
248                    const XMLCh* newPrefix =  fNSScope->getPrefix(uri);
249
250                    if(newPrefix != 0) {
251                        at->setPrefix(newPrefix);
252                    }
253                    else {
254                        if(prefix != 0 && !fNSScope->getUri(prefix)) {
255                            fNSScope->addOrChangeBinding(prefix, uri, fMemoryManager);
256                            addOrChangeNamespaceDecl(prefix, uri, ele);
257                        }
258                        else {
259                            newPrefix = addCustomNamespaceDecl(uri, ele);
260                            fNSScope->addOrChangeBinding(newPrefix, uri, fMemoryManager);
261                            at->setPrefix(newPrefix);
262                        }
263                    }
264                }
265            }
266            else if(at->getLocalName() == 0) {
267                error(XMLErrs::DOMLevel1Node, at);
268            }
269        }
270    }
271}
272
273
274
275const XMLCh * DOMNormalizer::integerToXMLCh(unsigned int i) const {
276    XMLCh *buf = (XMLCh*) fMemoryManager->allocate(15 * sizeof(XMLCh));//new XMLCh[15];
277        XMLCh *pos = buf + sizeof(buf) - sizeof(XMLCh);
278        *pos = chNull;
279
280        do {
281        switch(i % 10) {
282        case 0 : *--pos = chDigit_0;break;
283        case 1 : *--pos = chDigit_1;break;
284        case 2 : *--pos = chDigit_2;break;
285        case 3 : *--pos = chDigit_3;break;
286        case 4 : *--pos = chDigit_4;break;
287        case 5 : *--pos = chDigit_5;break;
288        case 6 : *--pos = chDigit_6;break;
289        case 7 : *--pos = chDigit_7;break;
290        case 8 : *--pos = chDigit_8;break;
291        case 9 : *--pos = chDigit_9;break;
292        default:;
293        }
294                i /= 10;
295        } while (i);
296
297    const XMLCh *copy = fDocument->getPooledString(pos);
298    fMemoryManager->deallocate(buf);//delete[] buf;
299        return copy;
300}
301
302
303
304
305
306void DOMNormalizer::addOrChangeNamespaceDecl(const XMLCh* prefix, const XMLCh* uri, DOMElementImpl* element) const {
307
308    if (XMLString::equals(prefix, XMLUni::fgZeroLenString)) {
309        element->setAttributeNS(XMLUni::fgXMLNSURIName, XMLUni::fgXMLNSString, uri);
310    } else {
311        XMLBuffer buf(1023, fMemoryManager);
312        buf.set(XMLUni::fgXMLNSString);
313        buf.append(chColon);
314        buf.append(prefix);
315        element->setAttributeNS(XMLUni::fgXMLNSURIName, buf.getRawBuffer(), uri);
316    }
317}
318
319const XMLCh* DOMNormalizer::addCustomNamespaceDecl(const XMLCh* uri, DOMElementImpl *element) const {
320    XMLBuffer preBuf(1023, fMemoryManager);
321    preBuf.append(chLatin_N);
322    preBuf.append(chLatin_S);
323    preBuf.append(integerToXMLCh(fNewNamespaceCount));
324    ((DOMNormalizer *)this)->fNewNamespaceCount++;
325
326    while(fNSScope->getUri(preBuf.getRawBuffer())) {
327        preBuf.reset();
328        preBuf.append(chLatin_N);
329        preBuf.append(chLatin_S);
330        preBuf.append(integerToXMLCh(fNewNamespaceCount));
331        ((DOMNormalizer *)this)->fNewNamespaceCount++;
332    }
333
334    XMLBuffer buf(1023, fMemoryManager);
335    buf.set(XMLUni::fgXMLNSString);
336    buf.append(chColon);
337    buf.append(preBuf.getRawBuffer());
338    element->setAttributeNS(XMLUni::fgXMLNSURIName, buf.getRawBuffer(), uri);
339
340    return element->getAttributeNodeNS(XMLUni::fgXMLNSURIName, preBuf.getRawBuffer())->getLocalName();
341}
342
343XMLSize_t DOMNormalizer::InScopeNamespaces::size() {
344    return fScopes->size();
345}
346
347DOMNormalizer::InScopeNamespaces::InScopeNamespaces(MemoryManager* const manager)
348: lastScopeWithBindings(0)
349{
350    fScopes = new (manager) RefVectorOf<Scope>(10, true, manager);
351}
352
353DOMNormalizer::InScopeNamespaces::~InScopeNamespaces() {
354    delete fScopes;
355}
356
357void DOMNormalizer::InScopeNamespaces::addOrChangeBinding(const XMLCh *prefix, const XMLCh *uri,
358                                                          MemoryManager* const manager) {
359    XMLSize_t s = fScopes->size();
360
361    if(!s)
362        addScope(manager);
363
364    Scope *curScope = fScopes->elementAt(s - 1);
365    curScope->addOrChangeBinding(prefix, uri, manager);
366
367    lastScopeWithBindings = curScope;
368}
369
370void DOMNormalizer::InScopeNamespaces::addScope(MemoryManager* const manager) {
371    Scope *s = new (manager) Scope(lastScopeWithBindings);
372    fScopes->addElement(s);
373}
374
375void DOMNormalizer::InScopeNamespaces::removeScope() {
376    lastScopeWithBindings = fScopes->elementAt(fScopes->size() - 1)->fBaseScopeWithBindings;
377    Scope *s = fScopes->orphanElementAt(fScopes->size() - 1);
378    delete s;
379}
380
381bool DOMNormalizer::InScopeNamespaces::isValidBinding(const XMLCh* prefix, const XMLCh* uri) const {
382    const XMLCh* actual = fScopes->elementAt(fScopes->size() - 1)->getUri(prefix);
383    if(actual == 0 || !XMLString::equals(actual, uri))
384        return false;
385    return true;
386}
387
388const XMLCh* DOMNormalizer::InScopeNamespaces::getPrefix(const XMLCh* uri) const {
389    return fScopes->elementAt(fScopes->size() - 1)->getPrefix(uri);
390}
391
392const XMLCh* DOMNormalizer::InScopeNamespaces::getUri(const XMLCh* prefix) const {
393    return fScopes->elementAt(fScopes->size() - 1)->getUri(prefix);
394}
395
396
397
398DOMNormalizer::InScopeNamespaces::Scope::Scope(Scope *baseScopeWithBindings) : fBaseScopeWithBindings(baseScopeWithBindings), fPrefixHash(0), fUriHash(0)
399{
400}
401
402DOMNormalizer::InScopeNamespaces::Scope::~Scope() {
403    delete fPrefixHash;
404    delete fUriHash;
405}
406
407void DOMNormalizer::InScopeNamespaces::Scope::addOrChangeBinding(const XMLCh *prefix, const XMLCh *uri,
408                                                                 MemoryManager* const manager) {
409    //initialize and copy forward now we need to
410    if(!fUriHash) {
411        fPrefixHash = new (manager) RefHashTableOf<XMLCh>(10, (bool) false, manager);
412        fUriHash = new (manager) RefHashTableOf<XMLCh>(10, (bool) false, manager);
413
414        if(fBaseScopeWithBindings) {
415            RefHashTableOfEnumerator<XMLCh> preEnumer(fBaseScopeWithBindings->fPrefixHash, false, manager);
416            while(preEnumer.hasMoreElements()) {
417                const XMLCh* prefix = (XMLCh*) preEnumer.nextElementKey();
418                const XMLCh* uri  = fBaseScopeWithBindings->fPrefixHash->get((void*)prefix);
419
420                //have to cast here because otherwise we have delete problems under windows :(
421                fPrefixHash->put((void *)prefix, (XMLCh*)uri);
422            }
423
424            RefHashTableOfEnumerator<XMLCh> uriEnumer(fBaseScopeWithBindings->fUriHash, false, manager);
425            while(uriEnumer.hasMoreElements()) {
426                const XMLCh* uri = (XMLCh*) uriEnumer.nextElementKey();
427                const XMLCh* prefix  = fBaseScopeWithBindings->fUriHash->get((void*)uri);
428
429                //have to cast here because otherwise we have delete problems under windows :(
430                fUriHash->put((void *)uri, (XMLCh*)prefix);
431            }
432        }
433    }
434
435    const XMLCh *oldUri = fPrefixHash->get(prefix);
436    if(oldUri) {
437        fUriHash->removeKey(oldUri);
438    }
439
440    fPrefixHash->put((void *)prefix, (XMLCh*)uri);
441    fUriHash->put((void *)uri, (XMLCh*)prefix);
442}
443
444const XMLCh* DOMNormalizer::InScopeNamespaces::Scope::getUri(const XMLCh *prefix) const {
445    const XMLCh* uri = 0;
446
447    if(fPrefixHash) {
448        uri = fPrefixHash->get(prefix);
449    }
450    else if(fBaseScopeWithBindings) {
451        uri = fBaseScopeWithBindings->getUri(prefix);
452    }
453
454    return uri ? uri : 0;
455}
456
457const XMLCh* DOMNormalizer::InScopeNamespaces::Scope::getPrefix(const XMLCh* uri) const {
458    const XMLCh* prefix = 0;
459
460    if(fUriHash) {
461        prefix = fUriHash->get(uri);
462    }
463    else if(fBaseScopeWithBindings) {
464        prefix = fBaseScopeWithBindings->getPrefix(uri);
465    }
466    return prefix ? prefix : 0;
467}
468
469void DOMNormalizer::error(const XMLErrs::Codes code, const DOMNode *node) const
470{
471    if (fErrorHandler) {
472
473        //  Load the message into alocal and replace any tokens found in
474        //  the text.
475        const XMLSize_t maxChars = 2047;
476        XMLCh errText[maxChars + 1];
477
478        if (!gMsgLoader->loadMsg(code, errText, maxChars))
479        {
480                // <TBD> Should probably load a default message here
481        }
482
483        DOMErrorImpl domError(
484          XMLErrs::DOMErrorType (code), 0, errText, (void*)node);
485        bool toContinueProcess = true;
486        try
487        {
488            toContinueProcess = fErrorHandler->handleError(domError);
489        }
490        catch(...)
491        {
492        }
493        if (!toContinueProcess)
494            throw (XMLErrs::Codes) code;
495    }
496}
497
498
499
500XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.