GME
13
|
00001 /* 00002 * Licensed to the Apache Software Foundation (ASF) under one or more 00003 * contributor license agreements. See the NOTICE file distributed with 00004 * this work for additional information regarding copyright ownership. 00005 * The ASF licenses this file to You under the Apache License, Version 2.0 00006 * (the "License"); you may not use this file except in compliance with 00007 * the License. You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 00018 /* 00019 * $Id: XIncludeUtils.cpp 933212 2010-04-12 12:17:58Z amassari $ 00020 */ 00021 00022 #include <xercesc/xinclude/XIncludeUtils.hpp> 00023 #include <xercesc/xinclude/XIncludeLocation.hpp> 00024 #include <xercesc/dom/DOM.hpp> 00025 #include <xercesc/util/TransService.hpp> 00026 #include <xercesc/util/XMLUri.hpp> 00027 #include <xercesc/util/XMLMsgLoader.hpp> 00028 #include <xercesc/util/XMLResourceIdentifier.hpp> 00029 #include <xercesc/util/BinInputStream.hpp> 00030 #include <xercesc/util/OutOfMemoryException.hpp> 00031 #include <xercesc/internal/XMLInternalErrorHandler.hpp> 00032 #include <xercesc/parsers/XercesDOMParser.hpp> 00033 #include <xercesc/sax/InputSource.hpp> 00034 #include <xercesc/framework/URLInputSource.hpp> 00035 00036 XERCES_CPP_NAMESPACE_BEGIN 00037 00038 XIncludeUtils::XIncludeUtils(XMLErrorReporter *errorReporter){ 00039 fErrorReporter = errorReporter; 00040 fIncludeHistoryHead = NULL; 00041 } 00042 00043 XIncludeUtils::~XIncludeUtils(){ 00044 freeInclusionHistory(); 00045 } 00046 00047 // --------------------------------------------------------------------------- 00048 // Generic function to parse a dom node performing any Xinclude's it ecounters, 00049 // storing its results in parsedDocument, which is expected to be a real 00050 // document. sourceNode is the current location in parsedDocument, and 00051 // all xinclude manipulation is done in place (i.e. source is manipulated). 00052 // --------------------------------------------------------------------------- 00053 bool 00054 XIncludeUtils::parseDOMNodeDoingXInclude(DOMNode *sourceNode, DOMDocument *parsedDocument, XMLEntityHandler* entityResolver){ 00055 if (sourceNode) { 00056 /* create the list of child elements here, since it gets changed during the parse */ 00057 RefVectorOf<DOMNode> children(10, false); 00058 for (DOMNode *child = sourceNode->getFirstChild(); child != NULL; child = child->getNextSibling()){ 00059 children.addElement(child); 00060 } 00061 00062 if (sourceNode->getNodeType() == DOMNode::ELEMENT_NODE){ 00063 if (isXIIncludeDOMNode(sourceNode)){ 00064 /* once we do an include on the source element, it is unsafe to do the include 00065 on the children, since they will have been changed by the top level include */ 00066 bool success = doDOMNodeXInclude(sourceNode, parsedDocument, entityResolver); 00067 00068 //popFromCurrentInclusionHistoryStack(NULL); 00069 /* return here as we do not want to fall through to the parsing of the children below 00070 - they should have been replaced by the XInclude */ 00071 return success; 00072 } else if (isXIFallbackDOMNode(sourceNode)){ 00073 /* This must be a fallback element that is not a child of an include element. 00074 This is defined as a fatal error */ 00075 XIncludeUtils::reportError(sourceNode, XMLErrs::XIncludeOrphanFallback, 00076 NULL, parsedDocument->getDocumentURI()); 00077 return false; 00078 } 00079 } 00080 00081 /* to have got here, we must not have found an xinclude element in the current element, so 00082 need to walk the entire child list parsing for each. An xinclude in a 00083 node does not affect a peer, so we can simply parse each child in turn */ 00084 for (XMLSize_t i = 0; i < children.size(); i++){ 00085 parseDOMNodeDoingXInclude(children.elementAt(i), parsedDocument, entityResolver); 00086 } 00087 } 00088 return false; 00089 } 00090 00091 // --------------------------------------------------------------------------- 00092 // utility func to extract a DOMNodes Base attr value if present 00093 // --------------------------------------------------------------------------- 00094 static const XMLCh * 00095 getBaseAttrValue(DOMNode *node){ 00096 if (node->getNodeType() == DOMNode::ELEMENT_NODE){ 00097 DOMElement *elem = (DOMElement *)node; 00098 if(elem->hasAttributes()) { 00099 /* get all the attributes of the node */ 00100 DOMNamedNodeMap *pAttributes = elem->getAttributes(); 00101 XMLSize_t nSize = pAttributes->getLength(); 00102 for(XMLSize_t i=0;i<nSize;++i) { 00103 DOMAttr *pAttributeNode = (DOMAttr*) pAttributes->item(i); 00104 /* get attribute name */ 00105 if (XMLString::equals(pAttributeNode->getName(), XIncludeUtils::fgXIBaseAttrName)){ 00106 /*if (namespace == XMLUni::fgXMLString){ 00107 00108 }*/ 00109 return pAttributeNode->getValue(); 00110 } 00111 } 00112 } 00113 } 00114 return NULL; 00115 } 00116 00117 // --------------------------------------------------------------------------- 00118 // This method assumes that currentNode is an xinclude element and parses 00119 // it accordingly, acting on what it finds. 00120 // --------------------------------------------------------------------------- 00121 bool 00122 XIncludeUtils::doDOMNodeXInclude(DOMNode *xincludeNode, DOMDocument *parsedDocument, XMLEntityHandler* entityResolver){ 00123 bool modifiedNode = false; 00124 /* the relevant attributes to look for */ 00125 const XMLCh *href = NULL; 00126 const XMLCh *parse = NULL; 00127 const XMLCh *xpointer = NULL; 00128 const XMLCh *encoding = NULL; 00129 const XMLCh *accept = NULL; 00130 const XMLCh *acceptlanguage = NULL; 00131 DOMNode *includeParent = xincludeNode->getParentNode(); 00132 00133 00134 if(xincludeNode->hasAttributes()) { 00135 /* get all the attributes of the node */ 00136 DOMNamedNodeMap *pAttributes = xincludeNode->getAttributes(); 00137 XMLSize_t nSize = pAttributes->getLength(); 00138 for(XMLSize_t i=0;i<nSize;++i) { 00139 DOMAttr *pAttributeNode = (DOMAttr*) pAttributes->item(i); 00140 const XMLCh *attrName = pAttributeNode->getName(); 00141 /* check each attribute against the potential useful names */ 00142 if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeHREFAttrName)){ 00143 href = pAttributeNode->getValue(); 00144 } else if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeParseAttrName)){ 00145 parse = pAttributeNode->getValue(); 00146 } else if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeXPointerAttrName)){ 00147 xpointer = pAttributeNode->getValue(); 00148 } else if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeEncodingAttrName)){ 00149 encoding = pAttributeNode->getValue(); 00150 } else if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeAcceptAttrName)){ 00151 accept = pAttributeNode->getValue(); 00152 } else if (XMLString::equals(attrName, XIncludeUtils::fgXIIncludeAcceptLanguageAttrName)){ 00153 acceptlanguage = pAttributeNode->getValue(); 00154 } else { 00155 /* if any other attribute is in the xi namespace, it's an error */ 00156 const XMLCh *attrNamespaceURI = pAttributeNode->getNamespaceURI(); 00157 if (attrNamespaceURI && XMLString::equals(attrNamespaceURI, XIncludeUtils::fgXIIIncludeNamespaceURI)){ 00158 } else { 00159 /* ignore - any other attribute is allowed according to spec, 00160 and must be ignored */ 00161 } 00162 } 00163 } 00164 } 00165 // 3.1 xi:include Element 00166 // The children property of the xi:include element may include a single xi:fallback element; 00167 // the appearance of more than one xi:fallback element, an xi:include element, 00168 // or any other element from the XInclude namespace is a fatal error. 00169 DOMNode *child; 00170 DOMElement *fallback = NULL; 00171 for (child = xincludeNode->getFirstChild(); child != 0; child=child->getNextSibling()){ 00172 if(child->getNodeType()!=DOMNode::ELEMENT_NODE) 00173 continue; 00174 if ( isXIFallbackDOMNode(child) ){ 00175 if (fallback != NULL){ 00176 /* fatal error - there are more than one fallback children */ 00177 XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeMultipleFallbackElems, 00178 parsedDocument->getDocumentURI(), parsedDocument->getDocumentURI()); 00179 return false; 00180 } 00181 fallback = (DOMElement*)child; 00182 } 00183 else if(isXIIncludeDOMNode(child) || XMLString::equals(child->getNamespaceURI(), XIncludeUtils::fgXIIIncludeNamespaceURI)) { 00184 /* fatal error - an xi element different from xi:fallback is a child of xi:include */ 00185 XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeDisallowedChild, 00186 child->getNodeName(), parsedDocument->getDocumentURI()); 00187 return false; 00188 } 00189 } 00190 00191 if (href == NULL){ 00192 /* this is an unrecoverable error until we have xpointer support - 00193 if there is an xpointer, the current document is assumed 00194 however, there is no xpointer support yet */ 00195 XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeNoHref, 00196 NULL, parsedDocument->getDocumentURI()); 00197 return false; 00198 } 00199 00200 /* set up the accept and accept-language values */ 00201 if (accept != NULL){ 00202 00203 } 00204 00205 if (parse == NULL){ 00206 /* use the default, as specified */ 00207 parse = XIncludeUtils::fgXIIncludeParseAttrXMLValue; 00208 } 00209 00210 if (xpointer != NULL){ 00211 /* not supported yet */ 00212 /* Note that finding an xpointer attr along with parse="text" is a Fatal Error 00213 * - http://www.w3.org/TR/xinclude/#include-location */ 00214 XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeXPointerNotSupported, 00215 NULL, href); 00216 return false; 00217 } 00218 00219 /* set up the href according to what has gone before */ 00220 XIncludeLocation hrefLoc(href); 00221 XIncludeLocation relativeLocation(href); 00222 const XMLCh *includeBase = xincludeNode->getBaseURI(); 00223 if (includeBase != NULL){ 00224 hrefLoc.prependPath(includeBase); 00225 } 00226 00227 if (getBaseAttrValue(xincludeNode) != NULL){ 00228 relativeLocation.prependPath(getBaseAttrValue(xincludeNode)); 00229 } 00230 00231 /* Take the relevant action - we need to retrieve the target as a whole before 00232 we can know if it was successful or not, therefore the do* methods do 00233 not modify the parsedDocument. Swapping the results in is left to the 00234 caller (i.e. here) */ 00235 DOMText *includedText = NULL; 00236 DOMDocument *includedDoc = NULL; 00237 if (XMLString::equals(parse, XIncludeUtils::fgXIIncludeParseAttrXMLValue)){ 00238 /* including a XML element */ 00239 includedDoc = doXIncludeXMLFileDOM(hrefLoc.getLocation(), relativeLocation.getLocation(), xincludeNode, parsedDocument, entityResolver); 00240 } else if (XMLString::equals(parse, XIncludeUtils::fgXIIncludeParseAttrTextValue)){ 00241 /* including a text value */ 00242 includedText = doXIncludeTEXTFileDOM(hrefLoc.getLocation(), relativeLocation.getLocation(), encoding, xincludeNode, parsedDocument, entityResolver); 00243 } else { 00244 /* invalid parse attribute value - fatal error according to the specification */ 00245 XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeInvalidParseVal, 00246 parse, parsedDocument->getDocumentURI()); 00247 return false; 00248 } 00249 00250 RefVectorOf<DOMNode> delayedProcessing(12,false); 00251 if (includedDoc == NULL && includedText == NULL){ 00252 /* there was an error - this is now a resource error 00253 let's see if there is a fallback */ 00254 XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeIncludeFailedResourceError, 00255 hrefLoc.getLocation(), parsedDocument->getDocumentURI()); 00256 00257 if (includeParent == NULL){ 00258 includeParent = parsedDocument; 00259 } 00260 00261 // we could be getting errors trying to insert elements at the root of the document, so we should use replaceChild; 00262 // in order to handle multiple nodes, add them to a document fragment and use that to replace the original node 00263 if (fallback){ 00264 /* baseURI fixups - see http://www.w3.org/TR/xinclude/#base for details. */ 00265 XMLUri parentURI(includeParent->getBaseURI()); 00266 XMLUri includedURI(fallback->getBaseURI()); 00267 00268 if (fallback->hasChildNodes()){ 00269 DOMDocumentFragment* frag = parsedDocument->createDocumentFragment(); 00270 DOMNode *child = fallback->getFirstChild(); 00271 /* add the content of the fallback element, and remove the fallback elem itself */ 00272 for ( ; child != NULL ; child=child->getNextSibling()){ 00273 if (child->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE){ 00274 continue; 00275 } 00276 DOMNode *newNode = parsedDocument->importNode(child, true); 00277 /* if the paths differ we need to add a base attribute */ 00278 if (newNode->getNodeType()==DOMNode::ELEMENT_NODE && !XMLString::equals(parentURI.getPath(), includedURI.getPath())){ 00279 if (getBaseAttrValue(newNode) == NULL){ 00280 /* need to calculate the proper path difference to get the relativePath */ 00281 ((DOMElement*)newNode)->setAttribute(fgXIBaseAttrName, getBaseAttrValue(fallback->getParentNode())); 00282 } else { 00283 /* the included node has base of its own which takes precedence */ 00284 XIncludeLocation xil(getBaseAttrValue(newNode)); 00285 if (getBaseAttrValue(fallback->getParentNode()) != NULL){ 00286 /* prepend any specific base modification of the xinclude node */ 00287 xil.prependPath(getBaseAttrValue(fallback->getParentNode())); 00288 } 00289 ((DOMElement*)newNode)->setAttribute(fgXIBaseAttrName, xil.getLocation()); 00290 } 00291 } 00292 DOMNode *newChild = frag->appendChild(newNode); 00293 // don't process the node now, wait until it is placed in the final position 00294 delayedProcessing.addElement(newChild); 00295 //parseDOMNodeDoingXInclude(newChild, parsedDocument, entityResolver); 00296 } 00297 includeParent->replaceChild(frag, xincludeNode); 00298 frag->release(); 00299 00300 for(XMLSize_t i=0;i<delayedProcessing.size();i++) 00301 { 00302 DOMNode* childNode=delayedProcessing.elementAt(i); 00303 parseDOMNodeDoingXInclude(childNode, parsedDocument, entityResolver); 00304 } 00305 modifiedNode = true; 00306 } else { 00307 /* empty fallback element - simply remove it! */ 00308 includeParent->removeChild(xincludeNode); 00309 modifiedNode = true; 00310 } 00311 } else { 00312 XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeIncludeFailedNoFallback, 00313 parsedDocument->getDocumentURI(), parsedDocument->getDocumentURI()); 00314 return false; 00315 } 00316 } else { 00317 if (includedDoc){ 00318 /* record the successful include while we process the children */ 00319 addDocumentURIToCurrentInclusionHistoryStack(hrefLoc.getLocation()); 00320 00321 DOMDocumentFragment* frag = parsedDocument->createDocumentFragment(); 00322 /* need to import the document prolog here */ 00323 DOMNode *child = includedDoc->getFirstChild(); 00324 for (; child != NULL; child = child->getNextSibling()) { 00325 if (child->getNodeType() == DOMNode::DOCUMENT_TYPE_NODE) 00326 continue; 00327 // check for NOTATION or ENTITY clash 00328 if(child->getNodeType()==DOMNode::ELEMENT_NODE && includedDoc->getDoctype()!=NULL) { 00329 DOMNamedNodeMap *pAttributes = child->getAttributes(); 00330 XMLSize_t nSize = pAttributes->getLength(); 00331 for(XMLSize_t i=0;i<nSize;++i) { 00332 DOMAttr *pAttributeNode = (DOMAttr*) pAttributes->item(i); 00333 const DOMTypeInfo * typeInfo=pAttributeNode->getSchemaTypeInfo(); 00334 if(typeInfo && XMLString::equals(typeInfo->getTypeNamespace(), XMLUni::fgInfosetURIName)) { 00335 if(XMLString::equals(typeInfo->getTypeName(), XMLUni::fgNotationString)) { 00336 const XMLCh* notationName=pAttributeNode->getNodeValue(); 00337 DOMNotation* notat=(DOMNotation*)includedDoc->getDoctype()->getNotations()->getNamedItem(notationName); 00338 // ensure we have a DTD 00339 if(parsedDocument->getDoctype()==NULL) 00340 parsedDocument->insertBefore(parsedDocument->createDocumentType(parsedDocument->getDocumentElement()->getNodeName(), NULL,NULL), parsedDocument->getFirstChild()); 00341 DOMNotation* myNotation=(DOMNotation*)parsedDocument->getDoctype()->getNotations()->getNamedItem(notationName); 00342 if(myNotation==NULL) 00343 { 00344 // it's missing, add it 00345 parsedDocument->getDoctype()->getNotations()->setNamedItem(parsedDocument->importNode(notat, true)); 00346 } 00347 else if(XMLString::equals(myNotation->getPublicId(), notat->getPublicId()) && 00348 XMLString::equals(myNotation->getSystemId(), notat->getSystemId()) && 00349 XMLString::equals(myNotation->getBaseURI(), notat->getBaseURI())) 00350 { 00351 // it's duplicate, ignore it 00352 } 00353 else 00354 { 00355 // it's a conflict, report it 00356 XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeConflictingNotation, 00357 notationName, parsedDocument->getDocumentURI()); 00358 } 00359 } 00360 else if(XMLString::equals(typeInfo->getTypeName(), XMLUni::fgEntityString)) { 00361 const XMLCh* entityName=pAttributeNode->getNodeValue(); 00362 DOMEntity* ent=(DOMEntity*)includedDoc->getDoctype()->getEntities()->getNamedItem(entityName); 00363 // ensure we have a DTD 00364 if(parsedDocument->getDoctype()==NULL) 00365 parsedDocument->insertBefore(parsedDocument->createDocumentType(parsedDocument->getDocumentElement()->getNodeName(), NULL,NULL), parsedDocument->getFirstChild()); 00366 DOMEntity* myEnt=(DOMEntity*)parsedDocument->getDoctype()->getEntities()->getNamedItem(entityName); 00367 if(myEnt==NULL) 00368 { 00369 // it's missing, add it 00370 parsedDocument->getDoctype()->getEntities()->setNamedItem(parsedDocument->importNode(ent, true)); 00371 } 00372 else if(XMLString::equals(myEnt->getPublicId(), ent->getPublicId()) && 00373 XMLString::equals(myEnt->getSystemId(), ent->getSystemId()) && 00374 XMLString::equals(myEnt->getBaseURI(), ent->getBaseURI())) 00375 { 00376 // it's duplicate, ignore it 00377 } 00378 else 00379 { 00380 // it's a conflict, report it 00381 XIncludeUtils::reportError(xincludeNode, XMLErrs::XIncludeConflictingEntity, 00382 entityName, parsedDocument->getDocumentURI()); 00383 } 00384 } 00385 } 00386 } 00387 } 00388 DOMNode *newNode = parsedDocument->importNode(child, true); 00389 DOMNode *newChild = frag->appendChild(newNode); 00390 // don't process the node now, wait until it is placed in the final position 00391 delayedProcessing.addElement(newChild); 00392 //parseDOMNodeDoingXInclude(newChild, parsedDocument, entityResolver); 00393 } 00394 includeParent->replaceChild(frag, xincludeNode); 00395 frag->release(); 00396 00397 for(XMLSize_t i=0;i<delayedProcessing.size();i++) 00398 { 00399 DOMNode* childNode=delayedProcessing.elementAt(i); 00400 parseDOMNodeDoingXInclude(childNode, parsedDocument, entityResolver); 00401 } 00402 popFromCurrentInclusionHistoryStack(NULL); 00403 modifiedNode = true; 00404 } else if (includedText){ 00405 includeParent->replaceChild(includedText, xincludeNode); 00406 modifiedNode = true; 00407 } 00408 } 00409 00410 if (includedDoc) 00411 includedDoc->release(); 00412 00413 return modifiedNode; 00414 } 00415 00416 DOMDocument * 00417 XIncludeUtils::doXIncludeXMLFileDOM(const XMLCh *href, 00418 const XMLCh *relativeHref, 00419 DOMNode *includeNode, 00420 DOMDocument *parsedDocument, 00421 XMLEntityHandler* entityResolver){ 00422 if (XIncludeUtils::isInCurrentInclusionHistoryStack(href)){ 00423 /* including something back up the current history */ 00424 XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeCircularInclusionLoop, 00425 href, href); 00426 return NULL; 00427 } 00428 00429 if (XMLString::equals(href, parsedDocument->getBaseURI())){ 00430 /* trying to include itself */ 00431 XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeCircularInclusionDocIncludesSelf, 00432 href, href); 00433 return NULL; 00434 } 00435 00436 /* Instantiate the DOM parser. */ 00437 XercesDOMParser parser; 00438 parser.setDoNamespaces(true); 00439 /* don't want to recurse the xi processing here */ 00440 parser.setDoXInclude(false); 00441 /* create the schema info nodes, so that we can detect conflicting notations */ 00442 parser.setCreateSchemaInfo(true); 00443 XMLInternalErrorHandler xierrhandler; 00444 parser.setErrorHandler(&xierrhandler); 00445 00446 DOMDocument *includedNode = NULL; 00447 try { 00448 InputSource* is=NULL; 00449 Janitor<InputSource> janIS(is); 00450 if(entityResolver) { 00451 XMLResourceIdentifier resIdentifier(XMLResourceIdentifier::ExternalEntity, 00452 relativeHref, 00453 NULL, 00454 NULL, 00455 includeNode->getBaseURI()); 00456 is=entityResolver->resolveEntity(&resIdentifier); 00457 janIS.reset(is); 00458 } 00459 if(janIS.get()!=NULL) 00460 parser.parse(*janIS.get()); 00461 else 00462 parser.parse(href); 00463 /* need to be able to release the parser but keep the document */ 00464 if (!xierrhandler.getSawError() && !xierrhandler.getSawFatal()) 00465 includedNode = parser.adoptDocument(); 00466 } 00467 catch (const XMLException& /*toCatch*/) 00468 { 00469 XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeResourceErrorWarning, 00470 href, href); 00471 } 00472 catch (const DOMException& /*toCatch*/) 00473 { 00474 XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeResourceErrorWarning, 00475 href, href); 00476 } 00477 catch (...) 00478 { 00479 XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeResourceErrorWarning, 00480 href, href); 00481 } 00482 00483 //addDocumentURIToCurrentInclusionHistoryStack(href); 00484 00485 if(includedNode != NULL){ 00486 /* baseURI fixups - see http://www.w3.org/TR/xinclude/#base for details. */ 00487 DOMElement *topLevelElement = includedNode->getDocumentElement(); 00488 if (topLevelElement && topLevelElement->getNodeType() == DOMNode::ELEMENT_NODE ){ 00489 XMLUri parentURI(includeNode->getBaseURI()); 00490 XMLUri includedURI(includedNode->getBaseURI()); 00491 00492 /* if the paths differ we need to add a base attribute */ 00493 if (!XMLString::equals(parentURI.getPath(), includedURI.getPath())){ 00494 if (getBaseAttrValue(topLevelElement) == NULL){ 00495 /* need to calculate the proper path difference to get the relativePath */ 00496 topLevelElement->setAttribute(fgXIBaseAttrName, relativeHref); 00497 } else { 00498 /* the included node has base of its own which takes precedence */ 00499 XIncludeLocation xil(getBaseAttrValue(topLevelElement)); 00500 if (getBaseAttrValue(includeNode) != NULL){ 00501 /* prepend any specific base modification of the xinclude node */ 00502 xil.prependPath(getBaseAttrValue(includeNode)); 00503 } 00504 topLevelElement->setAttribute(fgXIBaseAttrName, xil.getLocation()); 00505 } 00506 } 00507 } 00508 } 00509 return includedNode; 00510 } 00511 00512 DOMText * 00513 XIncludeUtils::doXIncludeTEXTFileDOM(const XMLCh *href, 00514 const XMLCh *relativeHref, 00515 const XMLCh *encoding, 00516 DOMNode *includeNode, 00517 DOMDocument *parsedDocument, 00518 XMLEntityHandler* entityResolver){ 00519 if (encoding == NULL) 00520 /* "UTF-8" is stipulated default by spec */ 00521 encoding = XMLUni::fgUTF8EncodingString; 00522 00523 XMLTransService::Codes failReason; 00524 XMLTranscoder* transcoder = XMLPlatformUtils::fgTransService->makeNewTranscoderFor(encoding, failReason, 16*1024); 00525 Janitor<XMLTranscoder> janTranscoder(transcoder); 00526 if (failReason){ 00527 XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeCannotOpenFile, href, href); 00528 return NULL; 00529 } 00530 00531 //addDocumentURIToCurrentInclusionHistoryStack(href); 00532 00533 InputSource* is=NULL; 00534 Janitor<InputSource> janIS(is); 00535 if(entityResolver) { 00536 XMLResourceIdentifier resIdentifier(XMLResourceIdentifier::ExternalEntity, 00537 relativeHref, 00538 NULL, 00539 NULL, 00540 includeNode->getBaseURI()); 00541 is=entityResolver->resolveEntity(&resIdentifier); 00542 janIS.reset(is); 00543 } 00544 if(janIS.get()==NULL) 00545 janIS.reset(new URLInputSource(href)); 00546 if(janIS.get()==NULL) { 00547 XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeCannotOpenFile, 00548 href, href); 00549 return NULL; 00550 } 00551 BinInputStream* stream=janIS.get()->makeStream(); 00552 if(stream==NULL) { 00553 XIncludeUtils::reportError(parsedDocument, XMLErrs::XIncludeCannotOpenFile, 00554 href, href); 00555 return NULL; 00556 } 00557 Janitor<BinInputStream> janStream(stream); 00558 const XMLSize_t maxToRead=16*1024; 00559 XMLByte* buffer=(XMLByte*)XMLPlatformUtils::fgMemoryManager->allocate(maxToRead * sizeof(XMLByte)); 00560 if(buffer==NULL) 00561 throw OutOfMemoryException(); 00562 ArrayJanitor<XMLByte> janBuffer(buffer, XMLPlatformUtils::fgMemoryManager); 00563 XMLCh* xmlChars=(XMLCh*)XMLPlatformUtils::fgMemoryManager->allocate(maxToRead*2*sizeof(XMLCh)); 00564 if(xmlChars==NULL) 00565 throw OutOfMemoryException(); 00566 ArrayJanitor<XMLCh> janUniBuffer(xmlChars, XMLPlatformUtils::fgMemoryManager); 00567 unsigned char *charSizes = (unsigned char *)XMLPlatformUtils::fgMemoryManager->allocate(maxToRead * sizeof(unsigned char)); 00568 if(charSizes==NULL) 00569 throw OutOfMemoryException(); 00570 ArrayJanitor<unsigned char> janCharSizes(charSizes, XMLPlatformUtils::fgMemoryManager); 00571 00572 XMLSize_t nRead, nOffset=0; 00573 XMLBuffer repository; 00574 while((nRead=stream->readBytes(buffer+nOffset, maxToRead-nOffset))>0){ 00575 XMLSize_t bytesEaten=0; 00576 XMLSize_t nCount = transcoder->transcodeFrom(buffer, nRead, xmlChars, maxToRead*2, bytesEaten, charSizes); 00577 repository.append(xmlChars, nCount); 00578 if(bytesEaten<nRead) { 00579 nOffset=nRead-bytesEaten; 00580 memmove(buffer, buffer+bytesEaten, nRead-bytesEaten); 00581 } 00582 } 00583 return parsedDocument->createTextNode(repository.getRawBuffer()); 00584 } 00585 00586 /*static*/ bool 00587 XIncludeUtils::isXIIncludeDOMNode(DOMNode *node){ 00588 const XMLCh *nodeName = node->getLocalName(); 00589 const XMLCh *namespaceURI = node->getNamespaceURI(); 00590 00591 return isXIIncludeElement(nodeName, namespaceURI); 00592 } 00593 00594 /*static*/ bool 00595 XIncludeUtils::isXIFallbackDOMNode(DOMNode *node){ 00596 const XMLCh *nodeName = node->getLocalName(); 00597 const XMLCh *namespaceURI = node->getNamespaceURI(); 00598 00599 return isXIFallbackElement(nodeName, namespaceURI); 00600 } 00601 00602 /*static*/ bool 00603 XIncludeUtils::isXIIncludeElement(const XMLCh *name, const XMLCh *namespaceURI){ 00604 if (namespaceURI == NULL || name == NULL){ 00605 /* no namespaces not supported */ 00606 return false; 00607 } 00608 if (XMLString::equals(name, fgXIIncludeQName) 00609 && XMLString::equals(namespaceURI, fgXIIIncludeNamespaceURI)){ 00610 return true; 00611 } 00612 return false; 00613 } 00614 00615 /*static*/ bool 00616 XIncludeUtils::isXIFallbackElement(const XMLCh *name, const XMLCh *namespaceURI){ 00617 if (namespaceURI == NULL || name == NULL){ 00618 /* no namespaces not supported */ 00619 return false; 00620 } 00621 if (XMLString::equals(name, fgXIFallbackQName) 00622 && XMLString::equals(namespaceURI, fgXIIIncludeNamespaceURI)){ 00623 return true; 00624 } 00625 return false; 00626 } 00627 00628 /* 4.1.1 */ 00629 const XMLCh * 00630 XIncludeUtils::getEscapedHRefAttrValue(const XMLCh * /*hrefAttrValue*/, bool & /*needsDeallocating*/){ 00631 XMLCh *escapedAttr = NULL; 00632 return escapedAttr; 00633 } 00634 00635 /* 4.1.2 */ 00636 bool 00637 XIncludeUtils::setContentNegotiation(const XMLCh * /*acceptAttrValue*/, const XMLCh * /*acceptLangAttrValue*/){ 00638 return false; 00639 } 00640 00641 bool 00642 XIncludeUtils::checkTextIsValidForInclude(XMLCh * /*includeChars*/){ 00643 return false; 00644 } 00645 00646 // ======================================================== 00647 // the stack utilities are slightly convoluted debug versions, they 00648 // will be pared down for the release code 00649 // ======================================================== 00650 static XIncludeHistoryNode * 00651 getTopOfCurrentInclusionHistoryStack(XIncludeHistoryNode *head){ 00652 XIncludeHistoryNode *historyCursor = head; 00653 if (historyCursor == NULL){ 00654 return NULL; 00655 } 00656 while (historyCursor->next != NULL){ 00657 historyCursor = historyCursor->next; 00658 } 00659 return historyCursor; 00660 } 00661 00662 bool 00663 XIncludeUtils::addDocumentURIToCurrentInclusionHistoryStack(const XMLCh *URItoAdd){ 00664 XIncludeHistoryNode *newNode = (XIncludeHistoryNode *)XMLPlatformUtils::fgMemoryManager->allocate(sizeof(XIncludeHistoryNode)); 00665 if (newNode == NULL){ 00666 return false; 00667 } 00668 newNode->URI = XMLString::replicate(URItoAdd); 00669 newNode->next = NULL; 00670 00671 if (fIncludeHistoryHead == NULL){ 00672 fIncludeHistoryHead = newNode; 00673 return true; 00674 } 00675 XIncludeHistoryNode *topNode = getTopOfCurrentInclusionHistoryStack(fIncludeHistoryHead); 00676 topNode->next = newNode; 00677 return true; 00678 } 00679 00680 bool 00681 XIncludeUtils::isInCurrentInclusionHistoryStack(const XMLCh *toFind){ 00682 XIncludeHistoryNode *historyCursor = fIncludeHistoryHead; 00683 /* walk the list */ 00684 while (historyCursor != NULL){ 00685 if (XMLString::equals(toFind, historyCursor->URI)){ 00686 return true; 00687 } 00688 historyCursor = historyCursor->next; 00689 } 00690 return false; 00691 } 00692 00693 XIncludeHistoryNode * 00694 XIncludeUtils::popFromCurrentInclusionHistoryStack(const XMLCh * /*toPop*/){ 00695 XIncludeHistoryNode *historyCursor = fIncludeHistoryHead; 00696 XIncludeHistoryNode *penultimateCursor = historyCursor; 00697 00698 if (fIncludeHistoryHead == NULL){ 00699 return NULL; 00700 } 00701 00702 while (historyCursor->next != NULL){ 00703 penultimateCursor = historyCursor; 00704 historyCursor = historyCursor->next; 00705 } 00706 00707 if (historyCursor == fIncludeHistoryHead){ 00708 fIncludeHistoryHead = NULL; 00709 } else { 00710 penultimateCursor->next = NULL; 00711 } 00712 00713 XMLString::release(&(historyCursor->URI)); 00714 XMLPlatformUtils::fgMemoryManager->deallocate((void *)historyCursor); 00715 return NULL; 00716 } 00717 00718 void 00719 XIncludeUtils::freeInclusionHistory(){ 00720 XIncludeHistoryNode *historyCursor = XIncludeUtils::fIncludeHistoryHead; 00721 while (historyCursor != NULL){ 00722 XIncludeHistoryNode *next = historyCursor->next; 00723 XMLString::release(&(historyCursor->URI)); 00724 XMLPlatformUtils::fgMemoryManager->deallocate((void *)historyCursor); 00725 historyCursor = next; 00726 } 00727 XIncludeUtils::fIncludeHistoryHead = NULL; 00728 } 00729 00730 bool 00731 XIncludeUtils::reportError(const DOMNode* const /*errorNode*/ 00732 , XMLErrs::Codes errorType 00733 , const XMLCh* const errorMsg 00734 , const XMLCh * const href) 00735 { 00736 bool toContinueProcess = true; /* default value for no error handler */ 00737 00738 const XMLCh* const systemId = href; 00739 const XMLCh* const publicId = href; 00740 /* TODO - look these up somehow? */ 00741 const XMLFileLoc lineNum = 0; 00742 const XMLFileLoc colNum = 0; 00743 00744 if (fErrorReporter) 00745 { 00746 // Load the message into a local for display 00747 const XMLSize_t msgSize = 1023; 00748 XMLCh errText[msgSize + 1]; 00749 00750 /* TODO - investigate whether this is complete */ 00751 XMLMsgLoader *errMsgLoader = XMLPlatformUtils::loadMsgSet(XMLUni::fgXMLErrDomain); 00752 if (errorMsg == NULL){ 00753 if (errMsgLoader->loadMsg(errorType, errText, msgSize)) 00754 { 00755 // <TBD> Probably should load a default msg here 00756 } 00757 } else { 00758 if (errMsgLoader->loadMsg(errorType, errText, msgSize, errorMsg)) 00759 { 00760 // <TBD> Probably should load a default msg here 00761 } 00762 } 00763 00764 fErrorReporter->error(errorType 00765 , XMLUni::fgXMLErrDomain //fgXMLErrDomain 00766 , XMLErrs::errorType(errorType) 00767 , errText 00768 , systemId 00769 , publicId 00770 , lineNum 00771 , colNum); 00772 } 00773 00774 if (XMLErrs::isFatal(errorType)) 00775 fErrorCount++; 00776 00777 return toContinueProcess; 00778 } 00779 00780 /* TODO - declared in this file for convenience, prob ought to be moved out to 00781 util/XMLUni.cpp before releasing */ 00782 const XMLCh XIncludeUtils::fgXIIncludeQName[] = 00783 { 00784 chLatin_i, chLatin_n, chLatin_c, chLatin_l, chLatin_u, chLatin_d, chLatin_e, chNull 00785 }; 00786 const XMLCh XIncludeUtils::fgXIFallbackQName[] = 00787 { 00788 chLatin_f, chLatin_a, chLatin_l, chLatin_l, chLatin_b, chLatin_a, chLatin_c, chLatin_k, chNull 00789 }; 00790 const XMLCh XIncludeUtils::fgXIIncludeHREFAttrName[] = 00791 { 00792 chLatin_h, chLatin_r, chLatin_e, chLatin_f, chNull 00793 }; 00794 const XMLCh XIncludeUtils::fgXIIncludeParseAttrName[] = 00795 { 00796 chLatin_p, chLatin_a, chLatin_r, chLatin_s, chLatin_e, chNull 00797 }; 00798 const XMLCh XIncludeUtils::fgXIIncludeXPointerAttrName[] = 00799 { 00800 chLatin_x, chLatin_p, chLatin_o, chLatin_i, chLatin_n, chLatin_t, chLatin_e, chLatin_r, chNull 00801 }; 00802 const XMLCh XIncludeUtils::fgXIIncludeEncodingAttrName[] = 00803 { 00804 chLatin_e, chLatin_n, chLatin_c, chLatin_o, chLatin_d, chLatin_i, chLatin_n, chLatin_g, chNull 00805 }; 00806 const XMLCh XIncludeUtils::fgXIIncludeAcceptAttrName[] = 00807 { 00808 chLatin_a, chLatin_c, chLatin_c, chLatin_e, chLatin_p, chLatin_t, chNull 00809 }; 00810 const XMLCh XIncludeUtils::fgXIIncludeAcceptLanguageAttrName[] = 00811 { 00812 chLatin_a, chLatin_c, chLatin_c, chLatin_e, chLatin_p, chLatin_t, chDash, chLatin_l, chLatin_a, 00813 chLatin_n, chLatin_g, chLatin_u, chLatin_a, chLatin_g, chLatin_e, chNull 00814 }; 00815 const XMLCh XIncludeUtils::fgXIIncludeParseAttrXMLValue[] = 00816 { 00817 chLatin_x, chLatin_m, chLatin_l, chNull 00818 }; 00819 const XMLCh XIncludeUtils::fgXIIncludeParseAttrTextValue[] = 00820 { 00821 chLatin_t, chLatin_e, chLatin_x, chLatin_t, chNull 00822 }; 00823 const XMLCh XIncludeUtils::fgXIIIncludeNamespaceURI[] = 00824 { 00825 /* http://www.w3.org/2001/XInclude */ 00826 chLatin_h, chLatin_t, chLatin_t, chLatin_p, chColon, chForwardSlash 00827 , chForwardSlash, chLatin_w, chLatin_w, chLatin_w, chPeriod 00828 , chLatin_w, chDigit_3, chPeriod, chLatin_o, chLatin_r, chLatin_g 00829 , chForwardSlash, chDigit_2, chDigit_0, chDigit_0, chDigit_1 00830 , chForwardSlash, chLatin_X, chLatin_I, chLatin_n, chLatin_c, chLatin_l 00831 , chLatin_u, chLatin_d, chLatin_e, chNull 00832 }; 00833 const XMLCh XIncludeUtils::fgXIBaseAttrName[] = 00834 { 00835 chLatin_x, chLatin_m, chLatin_l, chColon, chLatin_b, chLatin_a, chLatin_s, chLatin_e, chNull 00836 }; 00837 00838 XERCES_CPP_NAMESPACE_END