DriveHQ Start Menu
Cloud Drive Mapping
Folder Sync
Cloud Backup
True Drop Box
FTP/SFTP Hosting
Group Account
DriveHQ Start Menu
Online File Server
My Storage
|
Manage Shares
|
Publishes
|
Drop Boxes
|
Group Account
WebDAV Drive Mapping
Cloud Drive Home
|
WebDAV Guide
|
Drive Mapping Tool
|
Drive Mapping URL
Complete Data Backup
Backup Guide
|
Online Backup Tool
|
Cloud-to-Cloud Backup
FTP, Email & Web Service
FTP Home
|
FTP Hosting FAQ
|
Email Hosting
|
EmailManager
|
Web Hosting
Help & Resources
About
|
Enterprise Service
|
Partnership
|
Comparisons
|
Support
Quick Links
Security and Privacy
Download Software
Service Manual
Use Cases
Group Account
Online Help
Blog
Contact
Cloud Surveillance
Sign Up
Login
Features
Business Features
Online File Server
FTP Hosting
Cloud Drive Mapping
Cloud File Backup
Email Backup & Hosting
Cloud File Sharing
Folder Synchronization
Group Management
True Drop Box
Full-text Search
AD Integration/SSO
Mobile Access
IP Camera & DVR Solution
More...
Personal Features
Personal Cloud Drive
Backup All Devices
Mobile APPs
Personal Web Hosting
Sub-Account (for Kids)
Home/PC/Kids Monitoring
More...
Software
DriveHQ Drive Mapping Tool
DriveHQ FileManager
DriveHQ Online Backup
DriveHQ Mobile Apps
Pricing
Business Plans & Pricing
Personal Plans & Pricing
Price Comparison with Others
Feature Comparison with Others
Install Mobile App
Sign up
Creating account...
Invalid character in username! Only 0-9, a-z, A-Z, _, -, . allowed.
Username is required!
Invalid email address!
E-mail is required!
Password is required!
Password is invalid!
Password and confirmation do not match.
Confirm password is required!
I accept
Membership Agreement
Please read the Membership Agreement and check "I accept"!
Free Quick Sign-up
Sign-up Page
Log in
Signing in...
Username or e-mail address is required!
Password is required!
Keep me logged in
Quick Login
Forgot Password
Up
Upload
Download
Share
Publish
New Folder
New File
Copy
Cut
Delete
Paste
Rate
Upgrade
Rotate
Effect
Edit
Slide
History
/* * xinclude.c : Code to implement XInclude processing * * World Wide Web Consortium W3C Last Call Working Draft 10 November 2003 * http://www.w3.org/TR/2003/WD-xinclude-20031110 * * See Copyright for the status of this software. * * daniel@veillard.com */ #define IN_LIBXML #include "libxml.h" #include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef LIBXML_XINCLUDE_ENABLED #include
#define XINCLUDE_MAX_DEPTH 40 /* #define DEBUG_XINCLUDE */ #ifdef DEBUG_XINCLUDE #ifdef LIBXML_DEBUG_ENABLED #include
#endif #endif /************************************************************************ * * * XInclude context handling * * * ************************************************************************/ /* * An XInclude context */ typedef xmlChar *xmlURL; typedef struct _xmlXIncludeRef xmlXIncludeRef; typedef xmlXIncludeRef *xmlXIncludeRefPtr; struct _xmlXIncludeRef { xmlChar *URI; /* the fully resolved resource URL */ xmlChar *fragment; /* the fragment in the URI */ xmlDocPtr doc; /* the parsed document */ xmlNodePtr ref; /* the node making the reference in the source */ xmlNodePtr inc; /* the included copy */ int xml; /* xml or txt */ int count; /* how many refs use that specific doc */ xmlXPathObjectPtr xptr; /* the xpointer if needed */ int emptyFb; /* flag to show fallback empty */ }; struct _xmlXIncludeCtxt { xmlDocPtr doc; /* the source document */ int incBase; /* the first include for this document */ int incNr; /* number of includes */ int incMax; /* size of includes tab */ xmlXIncludeRefPtr *incTab; /* array of included references */ int txtNr; /* number of unparsed documents */ int txtMax; /* size of unparsed documents tab */ xmlNodePtr *txtTab; /* array of unparsed text nodes */ xmlURL *txturlTab; /* array of unparsed text URLs */ xmlChar * url; /* the current URL processed */ int urlNr; /* number of URLs stacked */ int urlMax; /* size of URL stack */ xmlChar * *urlTab; /* URL stack */ int nbErrors; /* the number of errors detected */ int legacy; /* using XINCLUDE_OLD_NS */ int parseFlags; /* the flags used for parsing XML documents */ xmlChar * base; /* the current xml:base */ }; static int xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree); /************************************************************************ * * * XInclude error handler * * * ************************************************************************/ /** * xmlXIncludeErrMemory: * @extra: extra information * * Handle an out of memory condition */ static void xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, const char *extra) { if (ctxt != NULL) ctxt->nbErrors++; __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, XML_ERR_NO_MEMORY, XML_ERR_ERROR, NULL, 0, extra, NULL, NULL, 0, 0, "Memory allocation failed : %s\n", extra); } /** * xmlXIncludeErr: * @ctxt: the XInclude context * @node: the context node * @msg: the error message * @extra: extra information * * Handle an XInclude error */ static void xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, const char *msg, const xmlChar *extra) { if (ctxt != NULL) ctxt->nbErrors++; __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, error, XML_ERR_ERROR, NULL, 0, (const char *) extra, NULL, NULL, 0, 0, msg, (const char *) extra); } #if 0 /** * xmlXIncludeWarn: * @ctxt: the XInclude context * @node: the context node * @msg: the error message * @extra: extra information * * Emit an XInclude warning. */ static void xmlXIncludeWarn(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node, int error, const char *msg, const xmlChar *extra) { __xmlRaiseError(NULL, NULL, NULL, ctxt, node, XML_FROM_XINCLUDE, error, XML_ERR_WARNING, NULL, 0, (const char *) extra, NULL, NULL, 0, 0, msg, (const char *) extra); } #endif /** * xmlXIncludeGetProp: * @ctxt: the XInclude context * @cur: the node * @name: the attribute name * * Get an XInclude attribute * * Returns the value (to be freed) or NULL if not found */ static xmlChar * xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur, const xmlChar *name) { xmlChar *ret; ret = xmlGetNsProp(cur, XINCLUDE_NS, name); if (ret != NULL) return(ret); if (ctxt->legacy != 0) { ret = xmlGetNsProp(cur, XINCLUDE_OLD_NS, name); if (ret != NULL) return(ret); } ret = xmlGetProp(cur, name); return(ret); } /** * xmlXIncludeFreeRef: * @ref: the XInclude reference * * Free an XInclude reference */ static void xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) { if (ref == NULL) return; #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "Freeing ref\n"); #endif if (ref->doc != NULL) { #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI); #endif xmlFreeDoc(ref->doc); } if (ref->URI != NULL) xmlFree(ref->URI); if (ref->fragment != NULL) xmlFree(ref->fragment); if (ref->xptr != NULL) xmlXPathFreeObject(ref->xptr); xmlFree(ref); } /** * xmlXIncludeNewRef: * @ctxt: the XInclude context * @URI: the resource URI * * Creates a new reference within an XInclude context * * Returns the new set */ static xmlXIncludeRefPtr xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI, xmlNodePtr ref) { xmlXIncludeRefPtr ret; #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI); #endif ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef)); if (ret == NULL) { xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context"); return(NULL); } memset(ret, 0, sizeof(xmlXIncludeRef)); if (URI == NULL) ret->URI = NULL; else ret->URI = xmlStrdup(URI); ret->fragment = NULL; ret->ref = ref; ret->doc = NULL; ret->count = 0; ret->xml = 0; ret->inc = NULL; if (ctxt->incMax == 0) { ctxt->incMax = 4; ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax * sizeof(ctxt->incTab[0])); if (ctxt->incTab == NULL) { xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context"); xmlXIncludeFreeRef(ret); return(NULL); } } if (ctxt->incNr >= ctxt->incMax) { ctxt->incMax *= 2; ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab, ctxt->incMax * sizeof(ctxt->incTab[0])); if (ctxt->incTab == NULL) { xmlXIncludeErrMemory(ctxt, ref, "growing XInclude context"); xmlXIncludeFreeRef(ret); return(NULL); } } ctxt->incTab[ctxt->incNr++] = ret; return(ret); } /** * xmlXIncludeNewContext: * @doc: an XML Document * * Creates a new XInclude context * * Returns the new set */ xmlXIncludeCtxtPtr xmlXIncludeNewContext(xmlDocPtr doc) { xmlXIncludeCtxtPtr ret; #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "New context\n"); #endif if (doc == NULL) return(NULL); ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt)); if (ret == NULL) { xmlXIncludeErrMemory(NULL, (xmlNodePtr) doc, "creating XInclude context"); return(NULL); } memset(ret, 0, sizeof(xmlXIncludeCtxt)); ret->doc = doc; ret->incNr = 0; ret->incBase = 0; ret->incMax = 0; ret->incTab = NULL; ret->nbErrors = 0; return(ret); } /** * xmlXIncludeURLPush: * @ctxt: the parser context * @value: the url * * Pushes a new url on top of the url stack * * Returns -1 in case of error, the index in the stack otherwise */ static int xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt, const xmlChar *value) { if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) { xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_RECURSION, "detected a recursion in %s\n", value); return(-1); } if (ctxt->urlTab == NULL) { ctxt->urlMax = 4; ctxt->urlNr = 0; ctxt->urlTab = (xmlChar * *) xmlMalloc( ctxt->urlMax * sizeof(ctxt->urlTab[0])); if (ctxt->urlTab == NULL) { xmlXIncludeErrMemory(ctxt, NULL, "adding URL"); return (-1); } } if (ctxt->urlNr >= ctxt->urlMax) { ctxt->urlMax *= 2; ctxt->urlTab = (xmlChar * *) xmlRealloc(ctxt->urlTab, ctxt->urlMax * sizeof(ctxt->urlTab[0])); if (ctxt->urlTab == NULL) { xmlXIncludeErrMemory(ctxt, NULL, "adding URL"); return (-1); } } ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value); return (ctxt->urlNr++); } /** * xmlXIncludeURLPop: * @ctxt: the parser context * * Pops the top URL from the URL stack */ static void xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt) { xmlChar * ret; if (ctxt->urlNr <= 0) return; ctxt->urlNr--; if (ctxt->urlNr > 0) ctxt->url = ctxt->urlTab[ctxt->urlNr - 1]; else ctxt->url = NULL; ret = ctxt->urlTab[ctxt->urlNr]; ctxt->urlTab[ctxt->urlNr] = NULL; if (ret != NULL) xmlFree(ret); } /** * xmlXIncludeFreeContext: * @ctxt: the XInclude context * * Free an XInclude context */ void xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) { int i; #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "Freeing context\n"); #endif if (ctxt == NULL) return; while (ctxt->urlNr > 0) xmlXIncludeURLPop(ctxt); if (ctxt->urlTab != NULL) xmlFree(ctxt->urlTab); for (i = 0;i < ctxt->incNr;i++) { if (ctxt->incTab[i] != NULL) xmlXIncludeFreeRef(ctxt->incTab[i]); } if (ctxt->txturlTab != NULL) { for (i = 0;i < ctxt->txtNr;i++) { if (ctxt->txturlTab[i] != NULL) xmlFree(ctxt->txturlTab[i]); } } if (ctxt->incTab != NULL) xmlFree(ctxt->incTab); if (ctxt->txtTab != NULL) xmlFree(ctxt->txtTab); if (ctxt->txturlTab != NULL) xmlFree(ctxt->txturlTab); if (ctxt->base != NULL) { xmlFree(ctxt->base); } xmlFree(ctxt); } /** * xmlXIncludeParseFile: * @ctxt: the XInclude context * @URL: the URL or file path * * parse a document for XInclude */ static xmlDocPtr xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) { xmlDocPtr ret; xmlParserCtxtPtr pctxt; char *directory = NULL; xmlParserInputPtr inputStream; xmlInitParser(); pctxt = xmlNewParserCtxt(); if (pctxt == NULL) { xmlXIncludeErrMemory(ctxt, NULL, "cannot allocate parser context"); return(NULL); } /* * try to ensure that new documents included are actually * built with the same dictionary as the including document. */ if ((ctxt->doc != NULL) && (ctxt->doc->dict != NULL) && (pctxt->dict != NULL)) { xmlDictFree(pctxt->dict); pctxt->dict = ctxt->doc->dict; xmlDictReference(pctxt->dict); } xmlCtxtUseOptions(pctxt, ctxt->parseFlags | XML_PARSE_DTDLOAD); inputStream = xmlLoadExternalEntity(URL, NULL, pctxt); if (inputStream == NULL) { xmlFreeParserCtxt(pctxt); return(NULL); } inputPush(pctxt, inputStream); if ((pctxt->directory == NULL) && (directory == NULL)) directory = xmlParserGetDirectory(URL); if ((pctxt->directory == NULL) && (directory != NULL)) pctxt->directory = (char *) xmlStrdup((xmlChar *) directory); pctxt->loadsubset |= XML_DETECT_IDS; xmlParseDocument(pctxt); if (pctxt->wellFormed) { ret = pctxt->myDoc; } else { ret = NULL; if (pctxt->myDoc != NULL) xmlFreeDoc(pctxt->myDoc); pctxt->myDoc = NULL; } xmlFreeParserCtxt(pctxt); return(ret); } /** * xmlXIncludeAddNode: * @ctxt: the XInclude context * @cur: the new node * * Add a new node to process to an XInclude context */ static int xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) { xmlXIncludeRefPtr ref; xmlURIPtr uri; xmlChar *URL; xmlChar *fragment = NULL; xmlChar *href; xmlChar *parse; xmlChar *base; xmlChar *URI; int xml = 1, i; /* default Issue 64 */ int local = 0; if (ctxt == NULL) return(-1); if (cur == NULL) return(-1); #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "Add node\n"); #endif /* * read the attributes */ href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF); if (href == NULL) { href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */ if (href == NULL) return(-1); local = 1; } if (href[0] == '#') local = 1; parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE); if (parse != NULL) { if (xmlStrEqual(parse, XINCLUDE_PARSE_XML)) xml = 1; else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT)) xml = 0; else { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_PARSE_VALUE, "invalid value %s for 'parse'\n", parse); if (href != NULL) xmlFree(href); if (parse != NULL) xmlFree(parse); return(-1); } } /* * compute the URI */ base = xmlNodeGetBase(ctxt->doc, cur); if (base == NULL) { URI = xmlBuildURI(href, ctxt->doc->URL); } else { URI = xmlBuildURI(href, base); } if (URI == NULL) { xmlChar *escbase; xmlChar *eschref; /* * Some escaping may be needed */ escbase = xmlURIEscape(base); eschref = xmlURIEscape(href); URI = xmlBuildURI(eschref, escbase); if (escbase != NULL) xmlFree(escbase); if (eschref != NULL) xmlFree(eschref); } if (parse != NULL) xmlFree(parse); if (href != NULL) xmlFree(href); if (base != NULL) xmlFree(base); if (URI == NULL) { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL); return(-1); } fragment = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE_XPOINTER); /* * Check the URL and remove any fragment identifier */ uri = xmlParseURI((const char *)URI); if (uri == NULL) { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", URI); if (fragment != NULL) xmlFree(fragment); xmlFree(URI); return(-1); } if (uri->fragment != NULL) { if (ctxt->legacy != 0) { if (fragment == NULL) { fragment = (xmlChar *) uri->fragment; } else { xmlFree(uri->fragment); } } else { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_FRAGMENT_ID, "Invalid fragment identifier in URI %s use the xpointer attribute\n", URI); if (fragment != NULL) xmlFree(fragment); xmlFreeURI(uri); xmlFree(URI); return(-1); } uri->fragment = NULL; } URL = xmlSaveUri(uri); xmlFreeURI(uri); xmlFree(URI); if (URL == NULL) { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", URI); if (fragment != NULL) xmlFree(fragment); return(-1); } /* * Check the URL against the stack for recursions */ if ((!local) && (xml == 1)) { for (i = 0;i < ctxt->urlNr;i++) { if (xmlStrEqual(URL, ctxt->urlTab[i])) { xmlXIncludeErr(ctxt, cur, XML_XINCLUDE_RECURSION, "detected a recursion in %s\n", URL); return(-1); } } } ref = xmlXIncludeNewRef(ctxt, URL, cur); if (ref == NULL) { return(-1); } ref->fragment = fragment; ref->doc = NULL; ref->xml = xml; ref->count = 1; xmlFree(URL); return(0); } /** * xmlXIncludeRecurseDoc: * @ctxt: the XInclude context * @doc: the new document * @url: the associated URL * * The XInclude recursive nature is handled at this point. */ static void xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const xmlURL url ATTRIBUTE_UNUSED) { xmlXIncludeCtxtPtr newctxt; int i; /* * Avoid recursion in already substitued resources for (i = 0;i < ctxt->urlNr;i++) { if (xmlStrEqual(doc->URL, ctxt->urlTab[i])) return; } */ #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL); #endif /* * Handle recursion here. */ newctxt = xmlXIncludeNewContext(doc); if (newctxt != NULL) { /* * Copy the existing document set */ newctxt->incMax = ctxt->incMax; newctxt->incNr = ctxt->incNr; newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax * sizeof(newctxt->incTab[0])); if (newctxt->incTab == NULL) { xmlXIncludeErrMemory(ctxt, (xmlNodePtr) doc, "processing doc"); xmlFree(newctxt); return; } /* * copy the urlTab */ newctxt->urlMax = ctxt->urlMax; newctxt->urlNr = ctxt->urlNr; newctxt->urlTab = ctxt->urlTab; /* * Inherit the existing base */ newctxt->base = xmlStrdup(ctxt->base); /* * Inherit the documents already in use by other includes */ newctxt->incBase = ctxt->incNr; for (i = 0;i < ctxt->incNr;i++) { newctxt->incTab[i] = ctxt->incTab[i]; newctxt->incTab[i]->count++; /* prevent the recursion from freeing it */ } /* * The new context should also inherit the Parse Flags * (bug 132597) */ newctxt->parseFlags = ctxt->parseFlags; xmlXIncludeDoProcess(newctxt, doc, xmlDocGetRootElement(doc)); for (i = 0;i < ctxt->incNr;i++) { newctxt->incTab[i]->count--; newctxt->incTab[i] = NULL; } /* urlTab may have been reallocated */ ctxt->urlTab = newctxt->urlTab; ctxt->urlMax = newctxt->urlMax; newctxt->urlMax = 0; newctxt->urlNr = 0; newctxt->urlTab = NULL; xmlXIncludeFreeContext(newctxt); } #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url); #endif } /** * xmlXIncludeAddTxt: * @ctxt: the XInclude context * @txt: the new text node * @url: the associated URL * * Add a new txtument to the list */ static void xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) { #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url); #endif if (ctxt->txtMax == 0) { ctxt->txtMax = 4; ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax * sizeof(ctxt->txtTab[0])); if (ctxt->txtTab == NULL) { xmlXIncludeErrMemory(ctxt, NULL, "processing text"); return; } ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax * sizeof(ctxt->txturlTab[0])); if (ctxt->txturlTab == NULL) { xmlXIncludeErrMemory(ctxt, NULL, "processing text"); return; } } if (ctxt->txtNr >= ctxt->txtMax) { ctxt->txtMax *= 2; ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab, ctxt->txtMax * sizeof(ctxt->txtTab[0])); if (ctxt->txtTab == NULL) { xmlXIncludeErrMemory(ctxt, NULL, "processing text"); return; } ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab, ctxt->txtMax * sizeof(ctxt->txturlTab[0])); if (ctxt->txturlTab == NULL) { xmlXIncludeErrMemory(ctxt, NULL, "processing text"); return; } } ctxt->txtTab[ctxt->txtNr] = txt; ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url); ctxt->txtNr++; } /************************************************************************ * * * Node copy with specific semantic * * * ************************************************************************/ /** * xmlXIncludeCopyNode: * @ctxt: the XInclude context * @target: the document target * @source: the document source * @elem: the element * * Make a copy of the node while preserving the XInclude semantic * of the Infoset copy */ static xmlNodePtr xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, xmlDocPtr source, xmlNodePtr elem) { xmlNodePtr result = NULL; if ((ctxt == NULL) || (target == NULL) || (source == NULL) || (elem == NULL)) return(NULL); if (elem->type == XML_DTD_NODE) return(NULL); result = xmlDocCopyNode(elem, target, 1); return(result); } /** * xmlXIncludeCopyNodeList: * @ctxt: the XInclude context * @target: the document target * @source: the document source * @elem: the element list * * Make a copy of the node list while preserving the XInclude semantic * of the Infoset copy */ static xmlNodePtr xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, xmlDocPtr source, xmlNodePtr elem) { xmlNodePtr cur, res, result = NULL, last = NULL; if ((ctxt == NULL) || (target == NULL) || (source == NULL) || (elem == NULL)) return(NULL); cur = elem; while (cur != NULL) { res = xmlXIncludeCopyNode(ctxt, target, source, cur); if (res != NULL) { if (result == NULL) { result = last = res; } else { last->next = res; res->prev = last; last = res; } } cur = cur->next; } return(result); } /** * xmlXIncludeGetNthChild: * @cur: the node * @no: the child number * * Returns the @n'th element child of @cur or NULL */ static xmlNodePtr xmlXIncludeGetNthChild(xmlNodePtr cur, int no) { int i; if (cur == NULL) return(cur); cur = cur->children; for (i = 0;i <= no;cur = cur->next) { if (cur == NULL) return(cur); if ((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_DOCUMENT_NODE) || (cur->type == XML_HTML_DOCUMENT_NODE)) { i++; if (i == no) break; } } return(cur); } xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur, int *level); /* in xpointer.c */ /** * xmlXIncludeCopyRange: * @ctxt: the XInclude context * @target: the document target * @source: the document source * @obj: the XPointer result from the evaluation. * * Build a node list tree copy of the XPointer result. * * Returns an xmlNodePtr list or NULL. * The caller has to free the node tree. */ static xmlNodePtr xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, xmlDocPtr source, xmlXPathObjectPtr range) { /* pointers to generated nodes */ xmlNodePtr list = NULL, last = NULL, listParent = NULL; xmlNodePtr tmp, tmp2; /* pointers to traversal nodes */ xmlNodePtr start, cur, end; int index1, index2; int level = 0, lastLevel = 0, endLevel = 0, endFlag = 0; if ((ctxt == NULL) || (target == NULL) || (source == NULL) || (range == NULL)) return(NULL); if (range->type != XPATH_RANGE) return(NULL); start = (xmlNodePtr) range->user; if (start == NULL) return(NULL); end = range->user2; if (end == NULL) return(xmlDocCopyNode(start, target, 1)); cur = start; index1 = range->index; index2 = range->index2; /* * level is depth of the current node under consideration * list is the pointer to the root of the output tree * listParent is a pointer to the parent of output tree (within the included file) in case we need to add another level * last is a pointer to the last node added to the output tree * lastLevel is the depth of last (relative to the root) */ while (cur != NULL) { /* * Check if our output tree needs a parent */ if (level < 0) { while (level < 0) { /* copy must include namespaces and properties */ tmp2 = xmlDocCopyNode(listParent, target, 2); xmlAddChild(tmp2, list); list = tmp2; listParent = listParent->parent; level++; } last = list; lastLevel = 0; } /* * Check whether we need to change our insertion point */ while (level < lastLevel) { last = last->parent; lastLevel --; } if (cur == end) { /* Are we at the end of the range? */ if (cur->type == XML_TEXT_NODE) { const xmlChar *content = cur->content; int len; if (content == NULL) { tmp = xmlNewTextLen(NULL, 0); } else { len = index2; if ((cur == start) && (index1 > 1)) { content += (index1 - 1); len -= (index1 - 1); index1 = 0; } else { len = index2; } tmp = xmlNewTextLen(content, len); } /* single sub text node selection */ if (list == NULL) return(tmp); /* prune and return full set */ if (level == lastLevel) xmlAddNextSibling(last, tmp); else xmlAddChild(last, tmp); return(list); } else { /* ending node not a text node */ endLevel = level; /* remember the level of the end node */ endFlag = 1; /* last node - need to take care of properties + namespaces */ tmp = xmlDocCopyNode(cur, target, 2); if (list == NULL) { list = tmp; listParent = cur->parent; } else { if (level == lastLevel) xmlAddNextSibling(last, tmp); else { xmlAddChild(last, tmp); lastLevel = level; } } last = tmp; if (index2 > 1) { end = xmlXIncludeGetNthChild(cur, index2 - 1); index2 = 0; } if ((cur == start) && (index1 > 1)) { cur = xmlXIncludeGetNthChild(cur, index1 - 1); index1 = 0; } else { cur = cur->children; } level++; /* increment level to show change */ /* * Now gather the remaining nodes from cur to end */ continue; /* while */ } } else if (cur == start) { /* Not at the end, are we at start? */ if ((cur->type == XML_TEXT_NODE) || (cur->type == XML_CDATA_SECTION_NODE)) { const xmlChar *content = cur->content; if (content == NULL) { tmp = xmlNewTextLen(NULL, 0); } else { if (index1 > 1) { content += (index1 - 1); index1 = 0; } tmp = xmlNewText(content); } last = list = tmp; listParent = cur->parent; } else { /* Not text node */ /* * start of the range - need to take care of * properties and namespaces */ tmp = xmlDocCopyNode(cur, target, 2); list = last = tmp; listParent = cur->parent; if (index1 > 1) { /* Do we need to position? */ cur = xmlXIncludeGetNthChild(cur, index1 - 1); level = lastLevel = 1; index1 = 0; /* * Now gather the remaining nodes from cur to end */ continue; /* while */ } } } else { tmp = NULL; switch (cur->type) { case XML_DTD_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_NODE: /* Do not copy DTD informations */ break; case XML_ENTITY_DECL: /* handle crossing entities -> stack needed */ break; case XML_XINCLUDE_START: case XML_XINCLUDE_END: /* don't consider it part of the tree content */ break; case XML_ATTRIBUTE_NODE: /* Humm, should not happen ! */ break; default: /* * Middle of the range - need to take care of * properties and namespaces */ tmp = xmlDocCopyNode(cur, target, 2); break; } if (tmp != NULL) { if (level == lastLevel) xmlAddNextSibling(last, tmp); else { xmlAddChild(last, tmp); lastLevel = level; } last = tmp; } } /* * Skip to next node in document order */ cur = xmlXPtrAdvanceNode(cur, &level); if (endFlag && (level >= endLevel)) break; } return(list); } /** * xmlXIncludeBuildNodeList: * @ctxt: the XInclude context * @target: the document target * @source: the document source * @obj: the XPointer result from the evaluation. * * Build a node list tree copy of the XPointer result. * This will drop Attributes and Namespace declarations. * * Returns an xmlNodePtr list or NULL. * the caller has to free the node tree. */ static xmlNodePtr xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target, xmlDocPtr source, xmlXPathObjectPtr obj) { xmlNodePtr list = NULL, last = NULL; int i; if (source == NULL) source = ctxt->doc; if ((ctxt == NULL) || (target == NULL) || (source == NULL) || (obj == NULL)) return(NULL); switch (obj->type) { case XPATH_NODESET: { xmlNodeSetPtr set = obj->nodesetval; if (set == NULL) return(NULL); for (i = 0;i < set->nodeNr;i++) { if (set->nodeTab[i] == NULL) continue; switch (set->nodeTab[i]->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ELEMENT_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: #ifdef LIBXML_DOCB_ENABLED case XML_DOCB_DOCUMENT_NODE: #endif case XML_XINCLUDE_END: break; case XML_XINCLUDE_START: { xmlNodePtr tmp, cur = set->nodeTab[i]; cur = cur->next; while (cur != NULL) { switch(cur->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ELEMENT_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: tmp = xmlXIncludeCopyNode(ctxt, target, source, cur); if (last == NULL) { list = last = tmp; } else { xmlAddNextSibling(last, tmp); last = tmp; } cur = cur->next; continue; default: break; } break; } continue; } case XML_ATTRIBUTE_NODE: case XML_NAMESPACE_DECL: case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_NOTATION_NODE: case XML_DTD_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: continue; /* for */ } if (last == NULL) list = last = xmlXIncludeCopyNode(ctxt, target, source, set->nodeTab[i]); else { xmlAddNextSibling(last, xmlXIncludeCopyNode(ctxt, target, source, set->nodeTab[i])); if (last->next != NULL) last = last->next; } } break; } case XPATH_LOCATIONSET: { xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user; if (set == NULL) return(NULL); for (i = 0;i < set->locNr;i++) { if (last == NULL) list = last = xmlXIncludeCopyXPointer(ctxt, target, source, set->locTab[i]); else xmlAddNextSibling(last, xmlXIncludeCopyXPointer(ctxt, target, source, set->locTab[i])); if (last != NULL) { while (last->next != NULL) last = last->next; } } break; } #ifdef LIBXML_XPTR_ENABLED case XPATH_RANGE: return(xmlXIncludeCopyRange(ctxt, target, source, obj)); #endif case XPATH_POINT: /* points are ignored in XInclude */ break; default: break; } return(list); } /************************************************************************ * * * XInclude I/O handling * * * ************************************************************************/ typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData; typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr; struct _xmlXIncludeMergeData { xmlDocPtr doc; xmlXIncludeCtxtPtr ctxt; }; /** * xmlXIncludeMergeOneEntity: * @ent: the entity * @doc: the including doc * @nr: the entity name * * Inplements the merge of one entity */ static void xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data, xmlChar *name ATTRIBUTE_UNUSED) { xmlEntityPtr ret, prev; xmlDocPtr doc; xmlXIncludeCtxtPtr ctxt; if ((ent == NULL) || (data == NULL)) return; ctxt = data->ctxt; doc = data->doc; if ((ctxt == NULL) || (doc == NULL)) return; switch (ent->etype) { case XML_INTERNAL_PARAMETER_ENTITY: case XML_EXTERNAL_PARAMETER_ENTITY: case XML_INTERNAL_PREDEFINED_ENTITY: return; case XML_INTERNAL_GENERAL_ENTITY: case XML_EXTERNAL_GENERAL_PARSED_ENTITY: case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: break; } ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID, ent->SystemID, ent->content); if (ret != NULL) { if (ent->URI != NULL) ret->URI = xmlStrdup(ent->URI); } else { prev = xmlGetDocEntity(doc, ent->name); if (prev != NULL) { if (ent->etype != prev->etype) goto error; if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) { if (!xmlStrEqual(ent->SystemID, prev->SystemID)) goto error; } else if ((ent->ExternalID != NULL) && (prev->ExternalID != NULL)) { if (!xmlStrEqual(ent->ExternalID, prev->ExternalID)) goto error; } else if ((ent->content != NULL) && (prev->content != NULL)) { if (!xmlStrEqual(ent->content, prev->content)) goto error; } else { goto error; } } } return; error: switch (ent->etype) { case XML_INTERNAL_PARAMETER_ENTITY: case XML_EXTERNAL_PARAMETER_ENTITY: case XML_INTERNAL_PREDEFINED_ENTITY: case XML_INTERNAL_GENERAL_ENTITY: case XML_EXTERNAL_GENERAL_PARSED_ENTITY: return; case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: break; } xmlXIncludeErr(ctxt, (xmlNodePtr) ent, XML_XINCLUDE_ENTITY_DEF_MISMATCH, "mismatch in redefinition of entity %s\n", ent->name); } /** * xmlXIncludeMergeEntities: * @ctxt: an XInclude context * @doc: the including doc * @from: the included doc * * Inplements the entity merge * * Returns 0 if merge succeeded, -1 if some processing failed */ static int xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlDocPtr from) { xmlNodePtr cur; xmlDtdPtr target, source; if (ctxt == NULL) return(-1); if ((from == NULL) || (from->intSubset == NULL)) return(0); target = doc->intSubset; if (target == NULL) { cur = xmlDocGetRootElement(doc); if (cur == NULL) return(-1); target = xmlCreateIntSubset(doc, cur->name, NULL, NULL); if (target == NULL) return(-1); } source = from->intSubset; if ((source != NULL) && (source->entities != NULL)) { xmlXIncludeMergeData data; data.ctxt = ctxt; data.doc = doc; xmlHashScan((xmlHashTablePtr) source->entities, (xmlHashScanner) xmlXIncludeMergeEntity, &data); } source = from->extSubset; if ((source != NULL) && (source->entities != NULL)) { xmlXIncludeMergeData data; data.ctxt = ctxt; data.doc = doc; /* * don't duplicate existing stuff when external subsets are the same */ if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) && (!xmlStrEqual(target->SystemID, source->SystemID))) { xmlHashScan((xmlHashTablePtr) source->entities, (xmlHashScanner) xmlXIncludeMergeEntity, &data); } } return(0); } /** * xmlXIncludeLoadDoc: * @ctxt: the XInclude context * @url: the associated URL * @nr: the xinclude node number * * Load the document, and store the result in the XInclude context * * Returns 0 in case of success, -1 in case of failure */ static int xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { xmlDocPtr doc; xmlURIPtr uri; xmlChar *URL; xmlChar *fragment = NULL; int i = 0; #ifdef LIBXML_XPTR_ENABLED int saveFlags; #endif #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr); #endif /* * Check the URL and remove any fragment identifier */ uri = xmlParseURI((const char *)url); if (uri == NULL) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", url); return(-1); } if (uri->fragment != NULL) { fragment = (xmlChar *) uri->fragment; uri->fragment = NULL; } if ((ctxt->incTab != NULL) && (ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->fragment != NULL)) { if (fragment != NULL) xmlFree(fragment); fragment = xmlStrdup(ctxt->incTab[nr]->fragment); } URL = xmlSaveUri(uri); xmlFreeURI(uri); if (URL == NULL) { if (ctxt->incTab != NULL) xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", url); else xmlXIncludeErr(ctxt, NULL, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", url); if (fragment != NULL) xmlFree(fragment); return(-1); } /* * Handling of references to the local document are done * directly through ctxt->doc. */ if ((URL[0] == 0) || (URL[0] == '#') || ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) { doc = NULL; goto loaded; } /* * Prevent reloading twice the document. */ for (i = 0; i < ctxt->incNr; i++) { if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) && (ctxt->incTab[i]->doc != NULL)) { doc = ctxt->incTab[i]->doc; #ifdef DEBUG_XINCLUDE printf("Already loaded %s\n", URL); #endif goto loaded; } } /* * Load it. */ #ifdef DEBUG_XINCLUDE printf("loading %s\n", URL); #endif #ifdef LIBXML_XPTR_ENABLED /* * If this is an XPointer evaluation, we want to assure that * all entities have been resolved prior to processing the * referenced document */ saveFlags = ctxt->parseFlags; if (fragment != NULL) { /* if this is an XPointer eval */ ctxt->parseFlags |= XML_PARSE_NOENT; } #endif doc = xmlXIncludeParseFile(ctxt, (const char *)URL); #ifdef LIBXML_XPTR_ENABLED ctxt->parseFlags = saveFlags; #endif if (doc == NULL) { xmlFree(URL); if (fragment != NULL) xmlFree(fragment); return(-1); } ctxt->incTab[nr]->doc = doc; /* * It's possible that the requested URL has been mapped to a * completely different location (e.g. through a catalog entry). * To check for this, we compare the URL with that of the doc * and change it if they disagree (bug 146988). */ if (!xmlStrEqual(URL, doc->URL)) { xmlFree(URL); URL = xmlStrdup(doc->URL); } for (i = nr + 1; i < ctxt->incNr; i++) { if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) { ctxt->incTab[nr]->count++; #ifdef DEBUG_XINCLUDE printf("Increasing %s count since reused\n", URL); #endif break; } } /* * Make sure we have all entities fixed up */ xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc); /* * We don't need the DTD anymore, free up space if (doc->intSubset != NULL) { xmlUnlinkNode((xmlNodePtr) doc->intSubset); xmlFreeNode((xmlNodePtr) doc->intSubset); doc->intSubset = NULL; } if (doc->extSubset != NULL) { xmlUnlinkNode((xmlNodePtr) doc->extSubset); xmlFreeNode((xmlNodePtr) doc->extSubset); doc->extSubset = NULL; } */ xmlXIncludeRecurseDoc(ctxt, doc, URL); loaded: if (fragment == NULL) { /* * Add the top children list as the replacement copy. */ if (doc == NULL) { /* Hopefully a DTD declaration won't be copied from * the same document */ ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children); } else { ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc, doc, doc->children); } } #ifdef LIBXML_XPTR_ENABLED else { /* * Computes the XPointer expression and make a copy used * as the replacement copy. */ xmlXPathObjectPtr xptr; xmlXPathContextPtr xptrctxt; xmlNodeSetPtr set; if (doc == NULL) { xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref, NULL); } else { xptrctxt = xmlXPtrNewContext(doc, NULL, NULL); } if (xptrctxt == NULL) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_XPTR_FAILED, "could not create XPointer context\n", NULL); xmlFree(URL); xmlFree(fragment); return(-1); } xptr = xmlXPtrEval(fragment, xptrctxt); if (xptr == NULL) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_XPTR_FAILED, "XPointer evaluation failed: #%s\n", fragment); xmlXPathFreeContext(xptrctxt); xmlFree(URL); xmlFree(fragment); return(-1); } switch (xptr->type) { case XPATH_UNDEFINED: case XPATH_BOOLEAN: case XPATH_NUMBER: case XPATH_STRING: case XPATH_POINT: case XPATH_USERS: case XPATH_XSLT_TREE: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_XPTR_RESULT, "XPointer is not a range: #%s\n", fragment); xmlXPathFreeContext(xptrctxt); xmlFree(URL); xmlFree(fragment); return(-1); case XPATH_NODESET: if ((xptr->nodesetval == NULL) || (xptr->nodesetval->nodeNr <= 0)) { xmlXPathFreeContext(xptrctxt); xmlFree(URL); xmlFree(fragment); return(-1); } case XPATH_RANGE: case XPATH_LOCATIONSET: break; } set = xptr->nodesetval; if (set != NULL) { for (i = 0;i < set->nodeNr;i++) { if (set->nodeTab[i] == NULL) continue; switch (set->nodeTab[i]->type) { case XML_TEXT_NODE: case XML_CDATA_SECTION_NODE: case XML_ENTITY_REF_NODE: case XML_ENTITY_NODE: case XML_PI_NODE: case XML_COMMENT_NODE: case XML_DOCUMENT_NODE: case XML_HTML_DOCUMENT_NODE: #ifdef LIBXML_DOCB_ENABLED case XML_DOCB_DOCUMENT_NODE: #endif continue; case XML_ELEMENT_NODE: { xmlChar *nodeBase; xmlNodePtr el = set->nodeTab[i]; nodeBase = xmlNodeGetBase(el->doc, el); if (nodeBase != NULL) { if (!xmlStrEqual(nodeBase, el->doc->URL)) xmlNodeSetBase(el, nodeBase); xmlFree(nodeBase); } continue; } case XML_ATTRIBUTE_NODE: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_XPTR_RESULT, "XPointer selects an attribute: #%s\n", fragment); set->nodeTab[i] = NULL; continue; case XML_NAMESPACE_DECL: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_XPTR_RESULT, "XPointer selects a namespace: #%s\n", fragment); set->nodeTab[i] = NULL; continue; case XML_DOCUMENT_TYPE_NODE: case XML_DOCUMENT_FRAG_NODE: case XML_NOTATION_NODE: case XML_DTD_NODE: case XML_ELEMENT_DECL: case XML_ATTRIBUTE_DECL: case XML_ENTITY_DECL: case XML_XINCLUDE_START: case XML_XINCLUDE_END: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_XPTR_RESULT, "XPointer selects unexpected nodes: #%s\n", fragment); set->nodeTab[i] = NULL; set->nodeTab[i] = NULL; continue; /* for */ } } } if (doc == NULL) { ctxt->incTab[nr]->xptr = xptr; ctxt->incTab[nr]->inc = NULL; } else { ctxt->incTab[nr]->inc = xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr); xmlXPathFreeObject(xptr); } xmlXPathFreeContext(xptrctxt); xmlFree(fragment); } #endif /* * Do the xml:base fixup if needed */ if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) { xmlNodePtr node; xmlChar *base; xmlChar *curBase; /* * The base is only adjusted if "necessary", i.e. if the xinclude node * has a base specified, or the URL is relative */ base = xmlGetNsProp(ctxt->incTab[nr]->ref, BAD_CAST "base", XML_XML_NAMESPACE); if (base == NULL) { /* * No xml:base on the xinclude node, so we check whether the * URI base is different than (relative to) the context base */ curBase = xmlBuildRelativeURI(URL, ctxt->base); if (curBase == NULL) { /* Error return */ xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, "trying to build relative URI from %s\n", URL); } else { /* If the URI doesn't contain a slash, it's not relative */ if (!xmlStrchr(curBase, (xmlChar) '/')) xmlFree(curBase); else base = curBase; } } if (base != NULL) { /* Adjustment may be needed */ node = ctxt->incTab[nr]->inc; while (node != NULL) { /* Only work on element nodes */ if (node->type == XML_ELEMENT_NODE) { curBase = xmlNodeGetBase(node->doc, node); /* If no current base, set it */ if (curBase == NULL) { xmlNodeSetBase(node, base); } else { /* * If the current base is the same as the * URL of the document, then reset it to be * the specified xml:base or the relative URI */ if (xmlStrEqual(curBase, node->doc->URL)) { xmlNodeSetBase(node, base); } else { /* * If the element already has an xml:base * set, then relativise it if necessary */ xmlChar *xmlBase; xmlBase = xmlGetNsProp(node, BAD_CAST "base", XML_XML_NAMESPACE); if (xmlBase != NULL) { xmlChar *relBase; relBase = xmlBuildURI(xmlBase, base); if (relBase == NULL) { /* error */ xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, "trying to rebuild base from %s\n", xmlBase); } else { xmlNodeSetBase(node, relBase); xmlFree(relBase); } xmlFree(xmlBase); } } xmlFree(curBase); } } node = node->next; } xmlFree(base); } } if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) && (ctxt->incTab[nr]->count <= 1)) { #ifdef DEBUG_XINCLUDE printf("freeing %s\n", ctxt->incTab[nr]->doc->URL); #endif xmlFreeDoc(ctxt->incTab[nr]->doc); ctxt->incTab[nr]->doc = NULL; } xmlFree(URL); return(0); } /** * xmlXIncludeLoadTxt: * @ctxt: the XInclude context * @url: the associated URL * @nr: the xinclude node number * * Load the content, and store the result in the XInclude context * * Returns 0 in case of success, -1 in case of failure */ static int xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) { xmlParserInputBufferPtr buf; xmlNodePtr node; xmlURIPtr uri; xmlChar *URL; int i; xmlChar *encoding = NULL; xmlCharEncoding enc = (xmlCharEncoding) 0; /* * Check the URL and remove any fragment identifier */ uri = xmlParseURI((const char *)url); if (uri == NULL) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", url); return(-1); } if (uri->fragment != NULL) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT, "fragment identifier forbidden for text: %s\n", (const xmlChar *) uri->fragment); xmlFreeURI(uri); return(-1); } URL = xmlSaveUri(uri); xmlFreeURI(uri); if (URL == NULL) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, "invalid value URI %s\n", url); return(-1); } /* * Handling of references to the local document are done * directly through ctxt->doc. */ if (URL[0] == 0) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_DOCUMENT, "text serialization of document not available\n", NULL); xmlFree(URL); return(-1); } /* * Prevent reloading twice the document. */ for (i = 0; i < ctxt->txtNr; i++) { if (xmlStrEqual(URL, ctxt->txturlTab[i])) { node = xmlCopyNode(ctxt->txtTab[i], 1); goto loaded; } } /* * Try to get the encoding if available */ if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) { encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING); } if (encoding != NULL) { /* * TODO: we should not have to remap to the xmlCharEncoding * predefined set, a better interface than * xmlParserInputBufferCreateFilename should allow any * encoding supported by iconv */ enc = xmlParseCharEncoding((const char *) encoding); if (enc == XML_CHAR_ENCODING_ERROR) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_UNKNOWN_ENCODING, "encoding %s not supported\n", encoding); xmlFree(encoding); xmlFree(URL); return(-1); } xmlFree(encoding); } /* * Load it. */ buf = xmlParserInputBufferCreateFilename((const char *)URL, enc); if (buf == NULL) { xmlFree(URL); return(-1); } node = xmlNewText(NULL); /* * Scan all chars from the resource and add the to the node */ while (xmlParserInputBufferRead(buf, 128) > 0) { int len; const xmlChar *content; content = xmlBufferContent(buf->buffer); len = xmlBufferLength(buf->buffer); for (i = 0;i < len;) { int cur; int l; cur = xmlStringCurrentChar(NULL, &content[i], &l); if (!IS_CHAR(cur)) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_INVALID_CHAR, "%s contains invalid char\n", URL); } else { xmlNodeAddContentLen(node, &content[i], l); } i += l; } xmlBufferShrink(buf->buffer, len); } xmlFreeParserInputBuffer(buf); xmlXIncludeAddTxt(ctxt, node, URL); loaded: /* * Add the element as the replacement copy. */ ctxt->incTab[nr]->inc = node; xmlFree(URL); return(0); } /** * xmlXIncludeLoadFallback: * @ctxt: the XInclude context * @fallback: the fallback node * @nr: the xinclude node number * * Load the content of the fallback node, and store the result * in the XInclude context * * Returns 0 in case of success, -1 in case of failure */ static int xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) { xmlXIncludeCtxtPtr newctxt; int ret = 0; if ((fallback == NULL) || (ctxt == NULL)) return(-1); if (fallback->children != NULL) { /* * It's possible that the fallback also has 'includes' * (Bug 129969), so we re-process the fallback just in case */ newctxt = xmlXIncludeNewContext(ctxt->doc); if (newctxt == NULL) return (-1); newctxt->base = xmlStrdup(ctxt->base); /* Inherit the base from the existing context */ xmlXIncludeSetFlags(newctxt, ctxt->parseFlags); ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children); if (ctxt->nbErrors > 0) ret = -1; else if (ret > 0) ret = 0; /* xmlXIncludeDoProcess can return +ve number */ xmlXIncludeFreeContext(newctxt); ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc, fallback->children); } else { ctxt->incTab[nr]->inc = NULL; ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */ } return(ret); } /************************************************************************ * * * XInclude Processing * * * ************************************************************************/ /** * xmlXIncludePreProcessNode: * @ctxt: an XInclude context * @node: an XInclude node * * Implement the XInclude preprocessing, currently just adding the element * for further processing. * * Returns the result list or NULL in case of error */ static xmlNodePtr xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { xmlXIncludeAddNode(ctxt, node); return(NULL); } /** * xmlXIncludeLoadNode: * @ctxt: an XInclude context * @nr: the node number * * Find and load the infoset replacement for the given node. * * Returns 0 if substitution succeeded, -1 if some processing failed */ static int xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) { xmlNodePtr cur; xmlChar *href; xmlChar *parse; xmlChar *base; xmlChar *oldBase; xmlChar *URI; int xml = 1; /* default Issue 64 */ int ret; if (ctxt == NULL) return(-1); if ((nr < 0) || (nr >= ctxt->incNr)) return(-1); cur = ctxt->incTab[nr]->ref; if (cur == NULL) return(-1); /* * read the attributes */ href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF); if (href == NULL) { href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */ if (href == NULL) return(-1); } parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE); if (parse != NULL) { if (xmlStrEqual(parse, XINCLUDE_PARSE_XML)) xml = 1; else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT)) xml = 0; else { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_PARSE_VALUE, "invalid value %s for 'parse'\n", parse); if (href != NULL) xmlFree(href); if (parse != NULL) xmlFree(parse); return(-1); } } /* * compute the URI */ base = xmlNodeGetBase(ctxt->doc, cur); if (base == NULL) { URI = xmlBuildURI(href, ctxt->doc->URL); } else { URI = xmlBuildURI(href, base); } if (URI == NULL) { xmlChar *escbase; xmlChar *eschref; /* * Some escaping may be needed */ escbase = xmlURIEscape(base); eschref = xmlURIEscape(href); URI = xmlBuildURI(eschref, escbase); if (escbase != NULL) xmlFree(escbase); if (eschref != NULL) xmlFree(eschref); } if (URI == NULL) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL); if (parse != NULL) xmlFree(parse); if (href != NULL) xmlFree(href); if (base != NULL) xmlFree(base); return(-1); } #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "parse: %s\n", xml ? "xml": "text"); xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI); #endif /* * Save the base for this include (saving the current one) */ oldBase = ctxt->base; ctxt->base = base; if (xml) { ret = xmlXIncludeLoadDoc(ctxt, URI, nr); /* xmlXIncludeGetFragment(ctxt, cur, URI); */ } else { ret = xmlXIncludeLoadTxt(ctxt, URI, nr); } /* * Restore the original base before checking for fallback */ ctxt->base = oldBase; if (ret < 0) { xmlNodePtr children; /* * Time to try a fallback if availble */ #ifdef DEBUG_XINCLUDE xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n"); #endif children = cur->children; while (children != NULL) { if ((children->type == XML_ELEMENT_NODE) && (children->ns != NULL) && (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) && ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) || (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) { ret = xmlXIncludeLoadFallback(ctxt, children, nr); if (ret == 0) break; } children = children->next; } } if (ret < 0) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_NO_FALLBACK, "could not load %s, and no fallback was found\n", URI); } /* * Cleanup */ if (URI != NULL) xmlFree(URI); if (parse != NULL) xmlFree(parse); if (href != NULL) xmlFree(href); if (base != NULL) xmlFree(base); return(0); } /** * xmlXIncludeIncludeNode: * @ctxt: an XInclude context * @nr: the node number * * Inplement the infoset replacement for the given node * * Returns 0 if substitution succeeded, -1 if some processing failed */ static int xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) { xmlNodePtr cur, end, list, tmp; if (ctxt == NULL) return(-1); if ((nr < 0) || (nr >= ctxt->incNr)) return(-1); cur = ctxt->incTab[nr]->ref; if (cur == NULL) return(-1); /* * If we stored an XPointer a late computation may be needed */ if ((ctxt->incTab[nr]->inc == NULL) && (ctxt->incTab[nr]->xptr != NULL)) { ctxt->incTab[nr]->inc = xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc, ctxt->incTab[nr]->xptr); xmlXPathFreeObject(ctxt->incTab[nr]->xptr); ctxt->incTab[nr]->xptr = NULL; } list = ctxt->incTab[nr]->inc; ctxt->incTab[nr]->inc = NULL; /* * Check against the risk of generating a multi-rooted document */ if ((cur->parent != NULL) && (cur->parent->type != XML_ELEMENT_NODE)) { int nb_elem = 0; tmp = list; while (tmp != NULL) { if (tmp->type == XML_ELEMENT_NODE) nb_elem++; tmp = tmp->next; } if (nb_elem > 1) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_MULTIPLE_ROOT, "XInclude error: would result in multiple root nodes\n", NULL); return(-1); } } if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) { /* * Add the list of nodes */ while (list != NULL) { end = list; list = list->next; xmlAddPrevSibling(cur, end); } xmlUnlinkNode(cur); xmlFreeNode(cur); } else { /* * Change the current node as an XInclude start one, and add an * XInclude end one */ cur->type = XML_XINCLUDE_START; end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL); if (end == NULL) { xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_BUILD_FAILED, "failed to build node\n", NULL); return(-1); } end->type = XML_XINCLUDE_END; xmlAddNextSibling(cur, end); /* * Add the list of nodes */ while (list != NULL) { cur = list; list = list->next; xmlAddPrevSibling(end, cur); } } return(0); } /** * xmlXIncludeTestNode: * @ctxt: the XInclude processing context * @node: an XInclude node * * test if the node is an XInclude node * * Returns 1 true, 0 otherwise */ static int xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { if (node == NULL) return(0); if (node->type != XML_ELEMENT_NODE) return(0); if (node->ns == NULL) return(0); if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) || (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) { if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) { if (ctxt->legacy == 0) { #if 0 /* wait for the XML Core Working Group to get something stable ! */ xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS, "Deprecated XInclude namespace found, use %s", XINCLUDE_NS); #endif ctxt->legacy = 1; } } if (xmlStrEqual(node->name, XINCLUDE_NODE)) { xmlNodePtr child = node->children; int nb_fallback = 0; while (child != NULL) { if ((child->type == XML_ELEMENT_NODE) && (child->ns != NULL) && ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) || (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) { if (xmlStrEqual(child->name, XINCLUDE_NODE)) { xmlXIncludeErr(ctxt, node, XML_XINCLUDE_INCLUDE_IN_INCLUDE, "%s has an 'include' child\n", XINCLUDE_NODE); return(0); } if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) { nb_fallback++; } } child = child->next; } if (nb_fallback > 1) { xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE, "%s has multiple fallback children\n", XINCLUDE_NODE); return(0); } return(1); } if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) { if ((node->parent == NULL) || (node->parent->type != XML_ELEMENT_NODE) || (node->parent->ns == NULL) || ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) && (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) || (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) { xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE, "%s is not the child of an 'include'\n", XINCLUDE_FALLBACK); } } } return(0); } /** * xmlXIncludeDoProcess: * @ctxt: the XInclude processing context * @doc: an XML document * @tree: the top of the tree to process * * Implement the XInclude substitution on the XML document @doc * * Returns 0 if no substitution were done, -1 if some processing failed * or the number of substitutions done. */ static int xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) { xmlNodePtr cur; int ret = 0; int i, start; if ((doc == NULL) || (tree == NULL)) return(-1); if (ctxt == NULL) return(-1); if (doc->URL != NULL) { ret = xmlXIncludeURLPush(ctxt, doc->URL); if (ret < 0) return(-1); } start = ctxt->incNr; /* * First phase: lookup the elements in the document */ cur = tree; if (xmlXIncludeTestNode(ctxt, cur) == 1) xmlXIncludePreProcessNode(ctxt, cur); while ((cur != NULL) && (cur != tree->parent)) { /* TODO: need to work on entities -> stack */ if ((cur->children != NULL) && (cur->children->type != XML_ENTITY_DECL) && (cur->children->type != XML_XINCLUDE_START) && (cur->children->type != XML_XINCLUDE_END)) { cur = cur->children; if (xmlXIncludeTestNode(ctxt, cur)) xmlXIncludePreProcessNode(ctxt, cur); } else if (cur->next != NULL) { cur = cur->next; if (xmlXIncludeTestNode(ctxt, cur)) xmlXIncludePreProcessNode(ctxt, cur); } else { if (cur == tree) break; do { cur = cur->parent; if ((cur == NULL) || (cur == tree->parent)) break; /* do */ if (cur->next != NULL) { cur = cur->next; if (xmlXIncludeTestNode(ctxt, cur)) xmlXIncludePreProcessNode(ctxt, cur); break; /* do */ } } while (cur != NULL); } } /* * Second Phase : collect the infosets fragments */ for (i = start;i < ctxt->incNr; i++) { xmlXIncludeLoadNode(ctxt, i); ret++; } /* * Third phase: extend the original document infoset. * * Originally we bypassed the inclusion if there were any errors * encountered on any of the XIncludes. A bug was raised (bug * 132588) requesting that we output the XIncludes without error, * so the check for inc!=NULL || xptr!=NULL was put in. This may * give some other problems in the future, but for now it seems to * work ok. * */ for (i = ctxt->incBase;i < ctxt->incNr; i++) { if ((ctxt->incTab[i]->inc != NULL) || (ctxt->incTab[i]->xptr != NULL) || (ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */ xmlXIncludeIncludeNode(ctxt, i); } if (doc->URL != NULL) xmlXIncludeURLPop(ctxt); return(ret); } /** * xmlXIncludeSetFlags: * @ctxt: an XInclude processing context * @flags: a set of xmlParserOption used for parsing XML includes * * Set the flags used for further processing of XML resources. * * Returns 0 in case of success and -1 in case of error. */ int xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) { if (ctxt == NULL) return(-1); ctxt->parseFlags = flags; return(0); } /** * xmlXIncludeProcessFlags: * @doc: an XML document * @flags: a set of xmlParserOption used for parsing XML includes * * Implement the XInclude substitution on the XML document @doc * * Returns 0 if no substitution were done, -1 if some processing failed * or the number of substitutions done. */ int xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) { xmlXIncludeCtxtPtr ctxt; xmlNodePtr tree; int ret = 0; if (doc == NULL) return(-1); tree = xmlDocGetRootElement(doc); if (tree == NULL) return(-1); ctxt = xmlXIncludeNewContext(doc); if (ctxt == NULL) return(-1); ctxt->base = xmlStrdup((xmlChar *)doc->URL); xmlXIncludeSetFlags(ctxt, flags); ret = xmlXIncludeDoProcess(ctxt, doc, tree); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1; xmlXIncludeFreeContext(ctxt); return(ret); } /** * xmlXIncludeProcess: * @doc: an XML document * * Implement the XInclude substitution on the XML document @doc * * Returns 0 if no substitution were done, -1 if some processing failed * or the number of substitutions done. */ int xmlXIncludeProcess(xmlDocPtr doc) { return(xmlXIncludeProcessFlags(doc, 0)); } /** * xmlXIncludeProcessTreeFlags: * @tree: a node in an XML document * @flags: a set of xmlParserOption used for parsing XML includes * * Implement the XInclude substitution for the given subtree * * Returns 0 if no substitution were done, -1 if some processing failed * or the number of substitutions done. */ int xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) { xmlXIncludeCtxtPtr ctxt; int ret = 0; if ((tree == NULL) || (tree->doc == NULL)) return(-1); ctxt = xmlXIncludeNewContext(tree->doc); if (ctxt == NULL) return(-1); ctxt->base = xmlNodeGetBase(tree->doc, tree); xmlXIncludeSetFlags(ctxt, flags); ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1; xmlXIncludeFreeContext(ctxt); return(ret); } /** * xmlXIncludeProcessTree: * @tree: a node in an XML document * * Implement the XInclude substitution for the given subtree * * Returns 0 if no substitution were done, -1 if some processing failed * or the number of substitutions done. */ int xmlXIncludeProcessTree(xmlNodePtr tree) { return(xmlXIncludeProcessTreeFlags(tree, 0)); } /** * xmlXIncludeProcessNode: * @ctxt: an existing XInclude context * @node: a node in an XML document * * Implement the XInclude substitution for the given subtree reusing * the informations and data coming from the given context. * * Returns 0 if no substitution were done, -1 if some processing failed * or the number of substitutions done. */ int xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) { int ret = 0; if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL)) return(-1); ret = xmlXIncludeDoProcess(ctxt, node->doc, node); if ((ret >= 0) && (ctxt->nbErrors > 0)) ret = -1; return(ret); } #else /* !LIBXML_XINCLUDE_ENABLED */ #endif #define bottom_xinclude #include "elfgcchack.h"
xinclude.c
Page URL
File URL
Prev
96/114
Next
Download
( 66 KB )
Note: The DriveHQ service banners will NOT be displayed if the file owner is a paid member.
Comments
Total ratings:
0
Average rating:
Not Rated
Would you like to comment?
Join DriveHQ
for a free account, or
Logon
if you are already a member.