source: icXML/icXML-devel/src/xercesc/xinclude/XIncludeUtils.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: 36.7 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/*
19 * $Id: XIncludeUtils.cpp 933212 2010-04-12 12:17:58Z amassari $
20 */
21
22#include <xercesc/xinclude/XIncludeUtils.hpp>
23#include <xercesc/xinclude/XIncludeLocation.hpp>
24#include <xercesc/dom/DOM.hpp>
25#include <icxercesc/util/TransService.hpp>
26#include <xercesc/util/XMLUri.hpp>
27#include <xercesc/util/XMLMsgLoader.hpp>
28#include <xercesc/util/XMLResourceIdentifier.hpp>
29#include <xercesc/util/BinInputStream.hpp>
30#include <xercesc/util/OutOfMemoryException.hpp>
31#include <xercesc/internal/XMLInternalErrorHandler.hpp>
32#include <xercesc/parsers/XercesDOMParser.hpp>
33#include <xercesc/sax/InputSource.hpp>
34#include <xercesc/framework/URLInputSource.hpp>
35
36XERCES_CPP_NAMESPACE_BEGIN
37
38XIncludeUtils::XIncludeUtils(XMLErrorReporter *errorReporter){
39    fErrorReporter = errorReporter;
40    fIncludeHistoryHead = NULL;
41}
42
43XIncludeUtils::~XIncludeUtils(){
44    freeInclusionHistory();
45}
46
47// ---------------------------------------------------------------------------
48//  Generic function to parse a dom node performing any Xinclude's it ecounters,
49//   storing its results in parsedDocument, which is expected to be a real
50//   document. sourceNode is the current location in parsedDocument, and
51//   all xinclude manipulation is done in place (i.e. source is manipulated).
52// ---------------------------------------------------------------------------
53bool
54XIncludeUtils::parseDOMNodeDoingXInclude(DOMNode *sourceNode, DOMDocument *parsedDocument, XMLEntityHandler* entityResolver){
55    if (sourceNode) {
56        /* create the list of child elements here, since it gets changed during the parse */
57        RefVectorOf<DOMNode> children(10, false);
58        for (DOMNode *child = sourceNode->getFirstChild(); child != NULL; child = child->getNextSibling()){
59            children.addElement(child);
60        }
61
62        if (sourceNode->getNodeType() == DOMNode::ELEMENT_NODE){
63            if (isXIIncludeDOMNode(sourceNode)){
64                /* once we do an include on the source element, it is unsafe to do the include
65                   on the children, since they will have been changed by the top level include */
66                bool success = doDOMNodeXInclude(sourceNode, parsedDocument, entityResolver);
67
68                //popFromCurrentInclusionHistoryStack(NULL);
69                /* return here as we do not want to fall through to the parsing of the children below
70                   - they should have been replaced by the XInclude */
71                return success;
72            } else if (isXIFallbackDOMNode(sourceNode)){
73                /* This must be a fallback element that is not a child of an include element.
74                   This is defined as a fatal error */
75                XIncludeUtils::reportError(sourceNode, XMLErrs::XIncludeOrphanFallback,
76                    NULL, parsedDocument->getDocumentURI());
77                return false;
78            }
79        }
80
81        /* to have got here, we must not have found an xinclude element in the current element, so
82           need to walk the entire child list parsing for each. An xinclude in  a
83           node does not affect a peer, so we can simply parse each child in turn */
84        for (XMLSize_t i = 0; i < children.size(); i++){
85            parseDOMNodeDoingXInclude(children.elementAt(i), parsedDocument, entityResolver);
86        }
87    }
88    return false;
89}
90
91// ---------------------------------------------------------------------------
92// utility func to extract a DOMNodes Base attr value if present
93// ---------------------------------------------------------------------------
94static const XMLCh *
95getBaseAttrValue(DOMNode *node){
96    if (node->getNodeType() == DOMNode::ELEMENT_NODE){
97        DOMElement *elem = (DOMElement *)node;
98        if(elem->hasAttributes()) {
99            /* get all the attributes of the node */
100            DOMNamedNodeMap *pAttributes = elem->getAttributes();
101            XMLSize_t nSize = pAttributes->getLength();
102            for(XMLSize_t i=0;i<nSize;++i) {
103                DOMAttr *pAttributeNode = (DOMAttr*) pAttributes->item(i);
104                /* get attribute name */
105                if (XMLString::equals(pAttributeNode->getName(), XIncludeUtils::fgXIBaseAttrName)){
106                    /*if (namespace == XMLUni::fgXMLString){
107
108                    }*/
109                    return pAttributeNode->getValue();
110                }
111            }
112        }
113    }
114    return NULL;
115}
116
117// ---------------------------------------------------------------------------
118//  This method assumes that currentNode is an xinclude element and parses
119//   it accordingly, acting on what it finds.
120// ---------------------------------------------------------------------------
121bool
122XIncludeUtils::doDOMNodeXInclude(DOMNode *xincludeNode, DOMDocument *parsedDocument, XMLEntityHandler* entityResolver){
123    bool modifiedNode = false;
124    /* the relevant attributes to look for */
125    const XMLCh *href = NULL;
126    const XMLCh *parse = NULL;
127    const XMLCh *xpointer = NULL;
128    const XMLCh *encoding = NULL;
129    const XMLCh *accept = NULL;
130    const XMLCh *acceptlanguage = NULL;
131    DOMNode *includeParent = xincludeNode->getParentNode();
132
133
134    if(xincludeNode->hasAttributes()) {
135        /* get all the attributes of the node */
136        DOMNamedNodeMap *pAttributes = xincludeNode->getAttributes();
137        XMLSize_t nSize = pAttributes->getLength();
138        for(XMLSize_t i=0;i<nSize;++i) {
139            DOMAttr *pAttributeNode = (DOMAttr*) pAttributes->item(i);
140            const XMLCh *attrName = pAttributeNode->getName();
141            /* check each attribute against the potential useful names */
142            if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeHREFAttrName)){
143                href = pAttributeNode->getValue();
144            } else if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeParseAttrName)){
145                parse = pAttributeNode->getValue();
146            } else if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeXPointerAttrName)){
147                xpointer = pAttributeNode->getValue();
148            } else if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeEncodingAttrName)){
149                encoding = pAttributeNode->getValue();
150            } else if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeAcceptAttrName)){
151                accept = pAttributeNode->getValue();
152            } else if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeAcceptLanguageAttrName)){
153                acceptlanguage = pAttributeNode->getValue();
154            } else {
155                /* if any other attribute is in the xi namespace, it's an error */
156                const XMLCh *attrNamespaceURI = pAttributeNode->getNamespaceURI();
157                if (attrNamespaceURI && XMLString::equals(attrNamespaceURI, XIncludeUtils::fgXIIIncludeNamespaceURI)){
158                } else {
159                    /* ignore - any other attribute is allowed according to spec,
160                       and must be ignored */
161                }
162            }
163        }
164    }
165    // 3.1 xi:include Element
166    // The children property of the xi:include element may include a single xi:fallback element;
167    // the appearance of more than one xi:fallback element, an xi:include element,
168    // or any other element from the XInclude namespace is a fatal error.
169    DOMNode *child;
170    DOMElement *fallback = NULL;
171    for (child = xincludeNode->getFirstChild(); child != 0; child=child->getNextSibling()){
172        if(child->getNodeType()!=DOMNode::ELEMENT_NODE)
173            continue;
174        if ( isXIFallbackDOMNode(child) ){
175            if (fallback != NULL){
176                /* fatal error - there are more than one fallback children */
177                XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeMultipleFallbackElems,
178                    parsedDocument->getDocumentURI(), parsedDocument->getDocumentURI());
179                return false;
180            }
181            fallback = (DOMElement*)child;
182        }
183        else if(isXIIncludeDOMNode(child) || XMLString::equals(child->getNamespaceURI(), XIncludeUtils::fgXIIIncludeNamespaceURI)) {
184            /* fatal error - an xi element different from xi:fallback is a child of xi:include */
185            XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeDisallowedChild,
186                child->getNodeName(), parsedDocument->getDocumentURI());
187            return false;
188        }
189    }
190
191    if (href == NULL){
192        /* this is an unrecoverable error until we have xpointer support -
193           if there is an xpointer, the current document is assumed
194           however, there is no xpointer support yet */
195        XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeNoHref,
196            NULL, parsedDocument->getDocumentURI());
197        return false;
198    }
199
200    /* set up the accept and accept-language values */
201    if (accept != NULL){
202
203    }
204
205    if (parse == NULL){
206        /* use the default, as specified */
207        parse = XIncludeUtils::fgXIIncludeParseAttrXMLValue;
208    }
209
210    if (xpointer != NULL){
211        /* not supported yet */
212        /* Note that finding an xpointer attr along with parse="text" is a Fatal Error
213         *  - http://www.w3.org/TR/xinclude/#include-location */
214        XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeXPointerNotSupported,
215            NULL, href);
216        return false;
217    }
218
219    /* set up the href according to what has gone before */
220    XIncludeLocation hrefLoc(href);
221    XIncludeLocation relativeLocation(href);
222    const XMLCh *includeBase = xincludeNode->getBaseURI();
223    if (includeBase != NULL){
224        hrefLoc.prependPath(includeBase);
225    }
226
227    if (getBaseAttrValue(xincludeNode) != NULL){
228        relativeLocation.prependPath(getBaseAttrValue(xincludeNode));
229    }
230
231    /*  Take the relevant action - we need to retrieve the target as a whole before
232        we can know if it was successful or not, therefore the do* methods do
233        not modify the parsedDocument. Swapping the results in is left to the
234        caller (i.e. here) */
235    DOMText *includedText = NULL;
236    DOMDocument *includedDoc = NULL;
237    if (XMLString::equals(parse, XIncludeUtils::fgXIIncludeParseAttrXMLValue)){
238        /* including a XML element */
239        includedDoc = doXIncludeXMLFileDOM(hrefLoc.getLocation(), relativeLocation.getLocation(), xincludeNode, parsedDocument, entityResolver);
240    } else if (XMLString::equals(parse, XIncludeUtils::fgXIIncludeParseAttrTextValue)){
241        /* including a text value */
242        includedText = doXIncludeTEXTFileDOM(hrefLoc.getLocation(), relativeLocation.getLocation(), encoding, xincludeNode, parsedDocument, entityResolver);
243    } else {
244        /* invalid parse attribute value - fatal error according to the specification */
245        XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeInvalidParseVal,
246            parse, parsedDocument->getDocumentURI());
247        return false;
248    }
249
250    RefVectorOf<DOMNode> delayedProcessing(12,false);
251    if (includedDoc == NULL && includedText == NULL){
252        /* there was an error - this is now a resource error
253           let's see if there is a fallback */
254        XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeIncludeFailedResourceError,
255            hrefLoc.getLocation(), parsedDocument->getDocumentURI());
256
257        if (includeParent == NULL){
258            includeParent = parsedDocument;
259        }
260
261        // we could be getting errors trying to insert elements at the root of the document, so we should use replaceChild;
262        // in order to handle multiple nodes, add them to a document fragment and use that to replace the original node
263        if (fallback){
264            /* baseURI fixups - see http://www.w3.org/TR/xinclude/#base for details. */
265            XMLUri parentURI(includeParent->getBaseURI());
266            XMLUri includedURI(fallback->getBaseURI());
267
268            if (fallback->hasChildNodes()){
269                DOMDocumentFragment* frag = parsedDocument->createDocumentFragment();
270                DOMNode *child = fallback->getFirstChild();
271                /* add the content of the fallback element, and remove the fallback elem itself */
272                for ( ; child != NULL ; child=child->getNextSibling()){
273                    if (child->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE){
274                        continue;
275                    }
276                    DOMNode *newNode = parsedDocument->importNode(child, true);
277                    /* if the paths differ we need to add a base attribute */
278                    if (newNode->getNodeType()==DOMNode::ELEMENT_NODE && !XMLString::equals(parentURI.getPath(), includedURI.getPath())){
279                        if (getBaseAttrValue(newNode) == NULL){
280                            /* need to calculate the proper path difference to get the relativePath */
281                            ((DOMElement*)newNode)->setAttribute(fgXIBaseAttrName, getBaseAttrValue(fallback->getParentNode()));
282                        } else {
283                            /* the included node has base of its own which takes precedence */
284                            XIncludeLocation xil(getBaseAttrValue(newNode));
285                            if (getBaseAttrValue(fallback->getParentNode()) != NULL){
286                                /* prepend any specific base modification of the xinclude node */
287                                xil.prependPath(getBaseAttrValue(fallback->getParentNode()));
288                            }
289                            ((DOMElement*)newNode)->setAttribute(fgXIBaseAttrName, xil.getLocation());
290                        }
291                    }
292                    DOMNode *newChild = frag->appendChild(newNode);
293                    // don't process the node now, wait until it is placed in the final position
294                    delayedProcessing.addElement(newChild);
295                    //parseDOMNodeDoingXInclude(newChild, parsedDocument, entityResolver);
296                }
297                includeParent->replaceChild(frag, xincludeNode);
298                frag->release();
299
300                for(XMLSize_t i=0;i<delayedProcessing.size();i++)
301                {
302                    DOMNode* childNode=delayedProcessing.elementAt(i);
303                    parseDOMNodeDoingXInclude(childNode, parsedDocument, entityResolver);
304                }
305                modifiedNode = true;
306            } else {
307                /* empty fallback element - simply remove it! */
308                includeParent->removeChild(xincludeNode);
309                modifiedNode = true;
310            }
311        } else {
312            XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeIncludeFailedNoFallback,
313                parsedDocument->getDocumentURI(), parsedDocument->getDocumentURI());
314            return false;
315        }
316    } else {
317        if (includedDoc){
318            /* record the successful include while we process the children */
319            addDocumentURIToCurrentInclusionHistoryStack(hrefLoc.getLocation());
320
321            DOMDocumentFragment* frag = parsedDocument->createDocumentFragment();
322            /* need to import the document prolog here */
323            DOMNode *child = includedDoc->getFirstChild();
324            for (; child != NULL; child = child->getNextSibling()) {
325                if (child->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE)
326                    continue;
327                // check for NOTATION or ENTITY clash
328                if(child->getNodeType()==DOMNode::ELEMENT_NODE && includedDoc->getDoctype()!=NULL) {
329                    DOMNamedNodeMap *pAttributes = child->getAttributes();
330                    XMLSize_t nSize = pAttributes->getLength();
331                    for(XMLSize_t i=0;i<nSize;++i) {
332                        DOMAttr *pAttributeNode = (DOMAttr*) pAttributes->item(i);
333                        const DOMTypeInfo * typeInfo=pAttributeNode->getSchemaTypeInfo();
334                        if(typeInfo && XMLString::equals(typeInfo->getTypeNamespace(), XMLUni::fgInfosetURIName)) {
335                            if(XMLString::equals(typeInfo->getTypeName(), XMLUni::fgNotationString)) {
336                                const XMLCh* notationName=pAttributeNode->getNodeValue();
337                                DOMNotation* notat=(DOMNotation*)includedDoc->getDoctype()->getNotations()->getNamedItem(notationName);
338                                // ensure we have a DTD
339                                if(parsedDocument->getDoctype()==NULL)
340                                    parsedDocument->insertBefore(parsedDocument->createDocumentType(parsedDocument->getDocumentElement()->getNodeName(), NULL,NULL), parsedDocument->getFirstChild());
341                                DOMNotation* myNotation=(DOMNotation*)parsedDocument->getDoctype()->getNotations()->getNamedItem(notationName);
342                                if(myNotation==NULL)
343                                {
344                                    // it's missing, add it
345                                    parsedDocument->getDoctype()->getNotations()->setNamedItem(parsedDocument->importNode(notat, true));
346                                }
347                                else if(XMLString::equals(myNotation->getPublicId(), notat->getPublicId()) &&
348                                        XMLString::equals(myNotation->getSystemId(), notat->getSystemId()) &&
349                                        XMLString::equals(myNotation->getBaseURI(), notat->getBaseURI()))
350                                {
351                                    // it's duplicate, ignore it
352                                }
353                                else
354                                {
355                                    // it's a conflict, report it
356                                    XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeConflictingNotation,
357                                        notationName, parsedDocument->getDocumentURI());
358                                }
359                            }
360                            else if(XMLString::equals(typeInfo->getTypeName(), XMLUni::fgEntityString)) {
361                                const XMLCh* entityName=pAttributeNode->getNodeValue();
362                                DOMEntity* ent=(DOMEntity*)includedDoc->getDoctype()->getEntities()->getNamedItem(entityName);
363                                // ensure we have a DTD
364                                if(parsedDocument->getDoctype()==NULL)
365                                    parsedDocument->insertBefore(parsedDocument->createDocumentType(parsedDocument->getDocumentElement()->getNodeName(), NULL,NULL), parsedDocument->getFirstChild());
366                                DOMEntity* myEnt=(DOMEntity*)parsedDocument->getDoctype()->getEntities()->getNamedItem(entityName);
367                                if(myEnt==NULL)
368                                {
369                                    // it's missing, add it
370                                    parsedDocument->getDoctype()->getEntities()->setNamedItem(parsedDocument->importNode(ent, true));
371                                }
372                                else if(XMLString::equals(myEnt->getPublicId(), ent->getPublicId()) &&
373                                        XMLString::equals(myEnt->getSystemId(), ent->getSystemId()) &&
374                                        XMLString::equals(myEnt->getBaseURI(), ent->getBaseURI()))
375                                {
376                                    // it's duplicate, ignore it
377                                }
378                                else
379                                {
380                                    // it's a conflict, report it
381                                    XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeConflictingEntity,
382                                        entityName, parsedDocument->getDocumentURI());
383                                }
384                            }
385                        }
386                    }
387                }
388                DOMNode *newNode = parsedDocument->importNode(child, true);
389                DOMNode *newChild = frag->appendChild(newNode);
390                // don't process the node now, wait until it is placed in the final position
391                delayedProcessing.addElement(newChild);
392                //parseDOMNodeDoingXInclude(newChild, parsedDocument, entityResolver);
393            }
394            includeParent->replaceChild(frag, xincludeNode);
395            frag->release();
396
397            for(XMLSize_t i=0;i<delayedProcessing.size();i++)
398            {
399                DOMNode* childNode=delayedProcessing.elementAt(i);
400                parseDOMNodeDoingXInclude(childNode, parsedDocument, entityResolver);
401            }
402            popFromCurrentInclusionHistoryStack(NULL);
403            modifiedNode = true;
404        } else if (includedText){
405            includeParent->replaceChild(includedText, xincludeNode);
406            modifiedNode = true;
407        }
408    }
409
410    if (includedDoc)
411        includedDoc->release();
412
413    return modifiedNode;
414}
415
416DOMDocument *
417XIncludeUtils::doXIncludeXMLFileDOM(const XMLCh *href,
418                                    const XMLCh *relativeHref,
419                                    DOMNode *includeNode,
420                                    DOMDocument *parsedDocument,
421                                    XMLEntityHandler* entityResolver){
422    if (XIncludeUtils::isInCurrentInclusionHistoryStack(href)){
423         /* including something back up the current history */
424         XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeCircularInclusionLoop,
425              href, href);
426         return NULL;
427    }
428
429    if (XMLString::equals(href, parsedDocument->getBaseURI())){
430        /* trying to include itself */
431        XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeCircularInclusionDocIncludesSelf,
432              href, href);
433        return NULL;
434    }
435
436    /* Instantiate the DOM parser. */
437    XercesDOMParser parser;
438    parser.setDoNamespaces(true);
439    /* don't want to recurse the xi processing here */
440    parser.setDoXInclude(false);
441    /* create the schema info nodes, so that we can detect conflicting notations */
442    parser.setCreateSchemaInfo(true);
443    XMLInternalErrorHandler xierrhandler;
444    parser.setErrorHandler(&xierrhandler);
445
446    DOMDocument *includedNode = NULL;
447    try {
448        InputSource* is=NULL;
449        Janitor<InputSource> janIS(is);
450        if(entityResolver) {
451            XMLResourceIdentifier resIdentifier(XMLResourceIdentifier::ExternalEntity,
452                                                relativeHref,
453                                                NULL,
454                                                NULL,
455                                                includeNode->getBaseURI());
456            is=entityResolver->resolveEntity(&resIdentifier);
457            janIS.reset(is);
458        }
459        if(janIS.get()!=NULL)
460            parser.parse(*janIS.get());
461        else
462            parser.parse(href);
463        /* need to be able to release the parser but keep the document */
464        if (!xierrhandler.getSawError() && !xierrhandler.getSawFatal())
465            includedNode = parser.adoptDocument();
466    }
467    catch (const XMLException& /*toCatch*/)
468    {
469        XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeResourceErrorWarning,
470              href, href);
471    }
472    catch (const DOMException& /*toCatch*/)
473    {
474        XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeResourceErrorWarning,
475              href, href);
476    }
477    catch (...)
478    {
479        XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeResourceErrorWarning,
480             href, href);
481    }
482
483    //addDocumentURIToCurrentInclusionHistoryStack(href);
484
485    if(includedNode != NULL){
486        /* baseURI fixups - see http://www.w3.org/TR/xinclude/#base for details. */
487        DOMElement *topLevelElement = includedNode->getDocumentElement();
488        if (topLevelElement && topLevelElement->getNodeType() == DOMNode::ELEMENT_NODE ){
489            XMLUri parentURI(includeNode->getBaseURI());
490            XMLUri includedURI(includedNode->getBaseURI());
491
492            /* if the paths differ we need to add a base attribute */
493            if (!XMLString::equals(parentURI.getPath(), includedURI.getPath())){
494                if (getBaseAttrValue(topLevelElement) == NULL){
495                    /* need to calculate the proper path difference to get the relativePath */
496                    topLevelElement->setAttribute(fgXIBaseAttrName, relativeHref);
497                } else {
498                    /* the included node has base of its own which takes precedence */
499                    XIncludeLocation xil(getBaseAttrValue(topLevelElement));
500                    if (getBaseAttrValue(includeNode) != NULL){
501                        /* prepend any specific base modification of the xinclude node */
502                        xil.prependPath(getBaseAttrValue(includeNode));
503                    }
504                    topLevelElement->setAttribute(fgXIBaseAttrName, xil.getLocation());
505                }
506            }
507        }
508    }
509    return includedNode;
510}
511
512DOMText *
513XIncludeUtils::doXIncludeTEXTFileDOM(const XMLCh *href,
514                                     const XMLCh *relativeHref,
515                                     const XMLCh *encoding,
516                                     DOMNode *includeNode,
517                                     DOMDocument *parsedDocument,
518                                     XMLEntityHandler* entityResolver){
519    if (encoding == NULL)
520        /* "UTF-8" is stipulated default by spec */
521        encoding = XMLUni::fgUTF8EncodingString;
522
523    XMLTransService::Codes failReason;
524    XMLTranscoder* transcoder = XMLPlatformUtils::fgTransService->makeNewTranscoderFor(encoding, failReason, 16*1024);
525    Janitor<XMLTranscoder> janTranscoder(transcoder);
526    if (failReason){
527        XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeCannotOpenFile, href, href);
528        return NULL;
529    }
530
531    //addDocumentURIToCurrentInclusionHistoryStack(href);
532
533    InputSource* is=NULL;
534    Janitor<InputSource> janIS(is);
535    if(entityResolver) {
536        XMLResourceIdentifier resIdentifier(XMLResourceIdentifier::ExternalEntity,
537                                            relativeHref,
538                                            NULL,
539                                            NULL,
540                                            includeNode->getBaseURI());
541        is=entityResolver->resolveEntity(&resIdentifier);
542        janIS.reset(is);
543    }
544    if(janIS.get()==NULL)
545        janIS.reset(new URLInputSource(href));
546    if(janIS.get()==NULL) {
547        XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeCannotOpenFile,
548            href, href);
549        return NULL;
550    }
551    BinInputStream* stream=janIS.get()->makeStream();
552    if(stream==NULL) {
553        XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeCannotOpenFile,
554            href, href);
555        return NULL;
556    }
557    Janitor<BinInputStream> janStream(stream);
558    const XMLSize_t maxToRead=16*1024;
559    XMLByte* buffer=(XMLByte*)XMLPlatformUtils::fgMemoryManager->allocate(maxToRead * sizeof(XMLByte));
560    if(buffer==NULL)
561        throw OutOfMemoryException();
562    ArrayJanitor<XMLByte> janBuffer(buffer, XMLPlatformUtils::fgMemoryManager);
563    XMLCh* xmlChars=(XMLCh*)XMLPlatformUtils::fgMemoryManager->allocate(maxToRead*2*sizeof(XMLCh));
564    if(xmlChars==NULL)
565        throw OutOfMemoryException();
566    ArrayJanitor<XMLCh> janUniBuffer(xmlChars, XMLPlatformUtils::fgMemoryManager);
567    unsigned char *charSizes = (unsigned char *)XMLPlatformUtils::fgMemoryManager->allocate(maxToRead * sizeof(unsigned char));
568    if(charSizes==NULL)
569        throw OutOfMemoryException();
570    ArrayJanitor<unsigned char> janCharSizes(charSizes, XMLPlatformUtils::fgMemoryManager);
571
572    XMLSize_t nRead, nOffset=0;
573    XMLBuffer repository;
574    while((nRead=stream->readBytes(buffer+nOffset, maxToRead-nOffset))>0){
575        XMLSize_t bytesEaten=0;
576        XMLSize_t nCount = transcoder->transcodeFrom(buffer, nRead, xmlChars, maxToRead*2, bytesEaten, charSizes);
577        repository.append(xmlChars, nCount);
578        if(bytesEaten<nRead) {
579            nOffset=nRead-bytesEaten;
580            memmove(buffer, buffer+bytesEaten, nRead-bytesEaten);
581        }
582    }
583    return parsedDocument->createTextNode(repository.getRawBuffer());
584}
585
586/*static*/ bool
587XIncludeUtils::isXIIncludeDOMNode(DOMNode *node){
588    const XMLCh *nodeName = node->getLocalName();
589    const XMLCh *namespaceURI = node->getNamespaceURI();
590
591    return isXIIncludeElement(nodeName, namespaceURI);
592}
593
594/*static*/ bool
595XIncludeUtils::isXIFallbackDOMNode(DOMNode *node){
596    const XMLCh *nodeName = node->getLocalName();
597    const XMLCh *namespaceURI = node->getNamespaceURI();
598
599    return isXIFallbackElement(nodeName, namespaceURI);
600}
601
602/*static*/ bool
603XIncludeUtils::isXIIncludeElement(const XMLCh *name, const XMLCh *namespaceURI){
604    if (namespaceURI == NULL || name == NULL){
605        /* no namespaces not supported */
606        return false;
607    }
608    if (XMLString::equals(name, fgXIIncludeQName)
609        && XMLString::equals(namespaceURI, fgXIIIncludeNamespaceURI)){
610        return true;
611    }
612    return false;
613}
614
615/*static*/ bool
616XIncludeUtils::isXIFallbackElement(const XMLCh *name, const XMLCh *namespaceURI){
617    if (namespaceURI == NULL || name == NULL){
618        /* no namespaces not supported */
619        return false;
620    }
621    if (XMLString::equals(name, fgXIFallbackQName)
622        && XMLString::equals(namespaceURI, fgXIIIncludeNamespaceURI)){
623        return true;
624    }
625    return false;
626}
627
628/* 4.1.1 */
629const XMLCh *
630XIncludeUtils::getEscapedHRefAttrValue(const XMLCh * /*hrefAttrValue*/, bool & /*needsDeallocating*/){
631    XMLCh *escapedAttr = NULL;
632    return escapedAttr;
633}
634
635/* 4.1.2 */
636bool
637XIncludeUtils::setContentNegotiation(const XMLCh * /*acceptAttrValue*/, const XMLCh * /*acceptLangAttrValue*/){
638    return false;
639}
640
641bool
642XIncludeUtils::checkTextIsValidForInclude(XMLCh * /*includeChars*/){
643    return false;
644}
645
646// ========================================================
647// the stack utilities are slightly convoluted debug versions, they
648// will be pared down for the release code
649// ========================================================
650static XIncludeHistoryNode *
651getTopOfCurrentInclusionHistoryStack(XIncludeHistoryNode *head){
652    XIncludeHistoryNode *historyCursor = head;
653    if (historyCursor == NULL){
654        return NULL;
655    }
656    while (historyCursor->next != NULL){
657        historyCursor = historyCursor->next;
658    }
659    return historyCursor;
660}
661
662bool
663XIncludeUtils::addDocumentURIToCurrentInclusionHistoryStack(const XMLCh *URItoAdd){
664    XIncludeHistoryNode *newNode = (XIncludeHistoryNode *)XMLPlatformUtils::fgMemoryManager->allocate(sizeof(XIncludeHistoryNode));
665    if (newNode == NULL){
666        return false;
667    }
668    newNode->URI = XMLString::replicate(URItoAdd);
669    newNode->next = NULL;
670
671    if (fIncludeHistoryHead == NULL){
672        fIncludeHistoryHead = newNode;
673        return true;
674    }
675    XIncludeHistoryNode *topNode = getTopOfCurrentInclusionHistoryStack(fIncludeHistoryHead);
676    topNode->next = newNode;
677    return true;
678}
679
680bool
681XIncludeUtils::isInCurrentInclusionHistoryStack(const XMLCh *toFind){
682    XIncludeHistoryNode *historyCursor = fIncludeHistoryHead;
683    /* walk the list */
684    while (historyCursor != NULL){
685        if (XMLString::equals(toFind, historyCursor->URI)){
686            return true;
687        }
688        historyCursor = historyCursor->next;
689    }
690    return false;
691}
692
693XIncludeHistoryNode *
694XIncludeUtils::popFromCurrentInclusionHistoryStack(const XMLCh * /*toPop*/){
695    XIncludeHistoryNode *historyCursor = fIncludeHistoryHead;
696    XIncludeHistoryNode *penultimateCursor = historyCursor;
697
698    if (fIncludeHistoryHead == NULL){
699        return NULL;
700    }
701
702    while (historyCursor->next != NULL){
703        penultimateCursor = historyCursor;
704        historyCursor = historyCursor->next;
705    }
706
707    if (historyCursor == fIncludeHistoryHead){
708        fIncludeHistoryHead = NULL;
709    } else {
710        penultimateCursor->next = NULL;
711    }
712
713    XMLString::release(&(historyCursor->URI));
714    XMLPlatformUtils::fgMemoryManager->deallocate((void *)historyCursor);
715    return NULL;
716}
717
718void
719XIncludeUtils::freeInclusionHistory(){
720    XIncludeHistoryNode *historyCursor = XIncludeUtils::fIncludeHistoryHead;
721    while (historyCursor != NULL){
722        XIncludeHistoryNode *next = historyCursor->next;
723        XMLString::release(&(historyCursor->URI));
724        XMLPlatformUtils::fgMemoryManager->deallocate((void *)historyCursor);
725        historyCursor = next;
726    }
727    XIncludeUtils::fIncludeHistoryHead = NULL;
728}
729
730bool
731XIncludeUtils::reportError(const DOMNode* const    /*errorNode*/
732                              , XMLErrs::Codes errorType
733                              , const XMLCh*   const    errorMsg
734                              , const XMLCh * const href)
735{
736    bool toContinueProcess = true;   /* default value for no error handler */
737
738    const XMLCh* const                    systemId = href;
739    const XMLCh* const                    publicId = href;
740    /* TODO - look these up somehow? */
741    const XMLFileLoc                 lineNum = 0;
742    const XMLFileLoc                 colNum = 0;
743
744    if (fErrorReporter)
745    {
746        // Load the message into a local for display
747        const XMLSize_t msgSize = 1023;
748        XMLCh errText[msgSize + 1];
749
750        /* TODO - investigate whether this is complete */
751        XMLMsgLoader  *errMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgXMLErrDomain);
752        if (errorMsg == NULL){
753            if (errMsgLoader->loadMsg(errorType, errText, msgSize))
754            {
755                    // <TBD> Probably should load a default msg here
756            }
757        } else {
758            if (errMsgLoader->loadMsg(errorType, errText, msgSize, errorMsg))
759            {
760                    // <TBD> Probably should load a default msg here
761            }
762        }
763
764        fErrorReporter->error(errorType
765                              , XMLUni::fgXMLErrDomain    //fgXMLErrDomain
766                              , XMLErrs::errorType(errorType)
767                              , errText
768                              , systemId
769                              , publicId
770                              , lineNum
771                              , colNum);
772    }
773
774    if (XMLErrs::isFatal(errorType))
775        fErrorCount++;
776
777    return toContinueProcess;
778}
779
780/* TODO - declared in this file for convenience, prob ought to be moved out to
781   util/XMLUni.cpp before releasing */
782const XMLCh XIncludeUtils::fgXIIncludeQName[] =
783{
784    chLatin_i, chLatin_n, chLatin_c, chLatin_l, chLatin_u, chLatin_d, chLatin_e, chNull
785};
786const XMLCh XIncludeUtils::fgXIFallbackQName[] =
787{
788    chLatin_f, chLatin_a, chLatin_l, chLatin_l, chLatin_b, chLatin_a, chLatin_c, chLatin_k, chNull
789};
790const XMLCh XIncludeUtils::fgXIIncludeHREFAttrName[] =
791{
792    chLatin_h, chLatin_r, chLatin_e, chLatin_f, chNull
793};
794const XMLCh XIncludeUtils::fgXIIncludeParseAttrName[] =
795{
796    chLatin_p, chLatin_a, chLatin_r, chLatin_s, chLatin_e, chNull
797};
798const XMLCh XIncludeUtils::fgXIIncludeXPointerAttrName[] =
799{
800    chLatin_x, chLatin_p, chLatin_o, chLatin_i, chLatin_n, chLatin_t, chLatin_e, chLatin_r, chNull
801};
802const XMLCh XIncludeUtils::fgXIIncludeEncodingAttrName[] =
803{
804     chLatin_e, chLatin_n, chLatin_c, chLatin_o, chLatin_d, chLatin_i, chLatin_n, chLatin_g, chNull
805};
806const XMLCh XIncludeUtils::fgXIIncludeAcceptAttrName[] =
807{
808     chLatin_a, chLatin_c, chLatin_c, chLatin_e, chLatin_p, chLatin_t, chNull
809};
810const XMLCh XIncludeUtils::fgXIIncludeAcceptLanguageAttrName[] =
811{
812     chLatin_a, chLatin_c, chLatin_c, chLatin_e, chLatin_p, chLatin_t, chDash, chLatin_l, chLatin_a,
813         chLatin_n, chLatin_g, chLatin_u, chLatin_a, chLatin_g, chLatin_e, chNull
814};
815const XMLCh XIncludeUtils::fgXIIncludeParseAttrXMLValue[] =
816{
817    chLatin_x, chLatin_m, chLatin_l, chNull
818};
819const XMLCh XIncludeUtils::fgXIIncludeParseAttrTextValue[] =
820{
821    chLatin_t, chLatin_e, chLatin_x, chLatin_t, chNull
822};
823const XMLCh XIncludeUtils::fgXIIIncludeNamespaceURI[] =
824{
825    /* http://www.w3.org/2001/XInclude */
826    chLatin_h, chLatin_t, chLatin_t, chLatin_p, chColon, chForwardSlash
827    ,   chForwardSlash, chLatin_w, chLatin_w, chLatin_w, chPeriod
828    ,   chLatin_w, chDigit_3, chPeriod, chLatin_o, chLatin_r, chLatin_g
829    ,   chForwardSlash, chDigit_2, chDigit_0, chDigit_0, chDigit_1
830    ,    chForwardSlash, chLatin_X, chLatin_I, chLatin_n, chLatin_c, chLatin_l
831    ,    chLatin_u, chLatin_d, chLatin_e, chNull
832};
833const XMLCh XIncludeUtils::fgXIBaseAttrName[] =
834{
835    chLatin_x, chLatin_m, chLatin_l, chColon, chLatin_b, chLatin_a, chLatin_s, chLatin_e, chNull
836};
837
838XERCES_CPP_NAMESPACE_END
Note: See TracBrowser for help on using the repository browser.