Hi,

if developing a shared library setting the external entity loader globally 
is a little inconvenient as different libraries may interefere on that 
decision.

This patch tries to fix it by adding entityLoader members on several of the 
context structs and propagating it down the chain. I'm not sure if I have 
thought about everything, so be sure to review it thoroughly.

I'll try working on something similar for libxslt next (external entity 
loader and document loader per-context). How about a document loader for 
libxml's XInclude similar to what libxslt has?

Regards,
Michael
diff --git a/include/libxml/parser.h b/include/libxml/parser.h
index a7dddb3..b7ef7a7 100644
--- a/include/libxml/parser.h
+++ b/include/libxml/parser.h
@@ -170,6 +170,20 @@ typedef enum {
 } xmlParserMode;
 
 /**
+ * xmlExternalEntityLoader:
+ * @URL: The System ID of the resource requested
+ * @ID: The Public ID of the resource requested
+ * @context: the XML parser context
+ *
+ * External entity loaders types.
+ *
+ * Returns the entity input parser.
+ */
+typedef xmlParserInputPtr (*xmlExternalEntityLoader) (const char *URL,
+                                                      const char *ID,
+                                                      xmlParserCtxtPtr context);
+
+/**
  * xmlParserCtxt:
  *
  * The parser context.
@@ -299,6 +313,8 @@ struct _xmlParserCtxt {
     xmlParserMode     parseMode;    /* the parser mode */
     unsigned long    nbentities;    /* number of entities references */
     unsigned long  sizeentities;    /* size of parsed entities */
+
+    xmlExternalEntityLoader entityLoader;   /* the external entity loader to use */
 };
 
 /**
@@ -776,21 +792,6 @@ struct _xmlSAXHandlerV1 {
     unsigned int initialized;
 };
 
-
-/**
- * xmlExternalEntityLoader:
- * @URL: The System ID of the resource requested
- * @ID: The Public ID of the resource requested
- * @context: the XML parser context 
- *
- * External entity loaders types.
- *
- * Returns the entity input parser.
- */
-typedef xmlParserInputPtr (*xmlExternalEntityLoader) (const char *URL,
-					 const char *ID,
-					 xmlParserCtxtPtr context);
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/libxml/xinclude.h b/include/libxml/xinclude.h
index ba9c9b5..7d4e2be 100644
--- a/include/libxml/xinclude.h
+++ b/include/libxml/xinclude.h
@@ -116,6 +116,12 @@ XMLPUBFUN void XMLCALL
 XMLPUBFUN int XMLCALL
 		xmlXIncludeProcessNode	(xmlXIncludeCtxtPtr ctxt,
 					 xmlNodePtr tree);
+XMLPUBFUN void XMLCALL
+    xmlXIncludeSetExternalEntityLoader (xmlXIncludeCtxtPtr ctxt,
+                                        xmlExternalEntityLoader f);
+XMLPUBFUN xmlExternalEntityLoader XMLCALL
+    xmlXIncludeGetExternalEntityLoader (xmlXIncludeCtxtPtr ctxt);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/libxml/xmlIO.h b/include/libxml/xmlIO.h
index eea9ed6..084985d 100644
--- a/include/libxml/xmlIO.h
+++ b/include/libxml/xmlIO.h
@@ -211,6 +211,12 @@ xmlParserInputBufferPtr
 	__xmlParserInputBufferCreateFilename(const char *URI,
 										xmlCharEncoding enc);
 
+XMLPUBFUN void XMLCALL
+    xmlSetContextExternalEntityLoader (xmlParserCtxtPtr ctxt,
+                                       xmlExternalEntityLoader f);
+XMLPUBFUN xmlExternalEntityLoader XMLCALL
+    xmlGetContextExternalEntityLoader (xmlParserCtxtPtr ctxt);
+
 #ifdef LIBXML_OUTPUT_ENABLED
 /*
  * Interfaces for output
diff --git a/include/libxml/xmlschemas.h b/include/libxml/xmlschemas.h
index 752bc3a..2174f5c 100644
--- a/include/libxml/xmlschemas.h
+++ b/include/libxml/xmlschemas.h
@@ -210,6 +210,17 @@ XMLPUBFUN xmlSchemaSAXPlugPtr XMLCALL
 					 void **user_data);
 XMLPUBFUN int XMLCALL
             xmlSchemaSAXUnplug		(xmlSchemaSAXPlugPtr plug);
+
+XMLPUBFUN void XMLCALL
+    xmlSchemaSetValidExternalEntityLoader(xmlSchemaValidCtxtPtr ctxt,
+                                          xmlExternalEntityLoader f);
+XMLPUBFUN xmlExternalEntityLoader XMLCALL
+    xmlSchemaGetValidExternalEntityLoader(xmlSchemaValidCtxtPtr ctxt);
+XMLPUBFUN void XMLCALL
+    xmlSchemaSetParserExternalEntityLoader(xmlSchemaParserCtxtPtr ctxt,
+                                           xmlExternalEntityLoader f);
+XMLPUBFUN xmlExternalEntityLoader XMLCALL
+    xmlSchemaGetParserExternalEntityLoader(xmlSchemaParserCtxtPtr ctxt);
 #ifdef __cplusplus
 }
 #endif
diff --git a/parser.c b/parser.c
index bd2be67..487f50d 100644
--- a/parser.c
+++ b/parser.c
@@ -13183,6 +13183,7 @@ xmlCreateEntityParserCtxtInternal(const xmlChar *URL, const xmlChar *ID,
     if (pctx != NULL) {
         ctxt->options = pctx->options;
         ctxt->_private = pctx->_private;
+        ctxt->entityLoader = pctx->entityLoader;
     }
 
     uri = xmlBuildURI(URL, base);
diff --git a/parserInternals.c b/parserInternals.c
index 758c6b3..0fa7b7c 100644
--- a/parserInternals.c
+++ b/parserInternals.c
@@ -1672,6 +1672,8 @@ xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
     ctxt->catalogs = NULL;
     ctxt->nbentities = 0;
     xmlInitNodeInfoSeq(&ctxt->node_seq);
+
+    ctxt->entityLoader = NULL;
     return(0);
 }
 
diff --git a/xinclude.c b/xinclude.c
index ae449f8..abda0fb 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -84,6 +84,8 @@ struct _xmlXIncludeCtxt {
     xmlChar *		 base; /* the current xml:base */
 
     void            *_private; /* application data */
+
+    xmlExternalEntityLoader  entityLoader;  /* external entity loader to use */
 };
 
 static int
@@ -297,6 +299,7 @@ xmlXIncludeNewContext(xmlDocPtr doc) {
     ret->incMax = 0;
     ret->incTab = NULL;
     ret->nbErrors = 0;
+    ret->entityLoader = NULL;
     return(ret);
 }
 
@@ -430,9 +433,11 @@ xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt, const char *URL) {
     }
 
     /*
-     * pass in the application data to the parser context.
+     * pass in the application data and the entity loader to the parser
+     * context.
      */
     pctxt->_private = ctxt->_private;
+    pctxt->entityLoader = ctxt->entityLoader;
     
     /*
      * try to ensure that new documents included are actually
@@ -682,9 +687,10 @@ xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
     newctxt = xmlXIncludeNewContext(doc);
     if (newctxt != NULL) {
 	/*
-	 * Copy the private user data
+	 * Copy the private user data and the entity loader
 	 */
-	newctxt->_private = ctxt->_private;	
+	newctxt->_private = ctxt->_private;
+    newctxt->entityLoader = ctxt->entityLoader;
 	/*
 	 * Copy the existing document set
 	 */
@@ -1938,6 +1944,7 @@ xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
 	if (newctxt == NULL)
 	    return (-1);
 	newctxt->_private = ctxt->_private;
+    newctxt->entityLoader = ctxt->entityLoader;
 	newctxt->base = xmlStrdup(ctxt->base);	/* Inherit the base from the existing context */
 	xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
 	ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children);
@@ -2557,6 +2564,40 @@ xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
     return(ret);
 }
 
+/**
+ * xmlXIncludeSetExternalEntityLoader:
+ * @ctxt: an existing XInclude context
+ * @f:    the entity resolver function to use
+ *
+ * Set the entity resolver function to use for loading external
+ * entities in this XInclude context.
+ */
+void
+xmlXIncludeSetExternalEntityLoader(xmlXIncludeCtxtPtr ctxt,
+                                   xmlExternalEntityLoader f) {
+    if (ctxt != NULL) {
+        ctxt->entityLoader = f;
+    }
+}
+
+/**
+ * xmlXIncludeGetExternalEntityLoader:
+ * @ctxt: an existing XInclude context
+ *
+ * Get the entity resolver function to use for loading external
+ * entities in this XInclude context.
+ *
+ * Returns the xmlExternalEntityLoader function pointer or NULL
+ * if the global default loader is being used.
+ */
+xmlExternalEntityLoader
+xmlXIncludeGetExternalEntityLoader(xmlXIncludeCtxtPtr ctxt) {
+    if (ctxt != NULL) {
+        return ctxt->entityLoader;
+    }
+    return NULL;
+}
+
 #else /* !LIBXML_XINCLUDE_ENABLED */
 #endif
 #define bottom_xinclude
diff --git a/xmlIO.c b/xmlIO.c
index e4e86f0..9380461 100644
--- a/xmlIO.c
+++ b/xmlIO.c
@@ -3891,7 +3891,10 @@ static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
  * xmlSetExternalEntityLoader:
  * @f:  the new entity resolver function
  *
- * Changes the defaultexternal entity resolver function for the application
+ * Changes the default external entity resolver function for the application.
+ *
+ * It can be overridden on a per-context base using xmlParserCtxt's
+ * entityLoader member.
  */
 void
 xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
@@ -3911,6 +3914,38 @@ xmlGetExternalEntityLoader(void) {
 }
 
 /**
+ * xmlSetContextExternalEntityLoader:
+ * @ctxt: the context for which to set the entity resolver
+ * @f:    the new entity resolver function
+ *
+ * Set the external entity resolver function for the context.
+ */
+void
+xmlSetContextExternalEntityLoader(xmlParserCtxtPtr ctxt,
+                                  xmlExternalEntityLoader f) {
+    if (ctxt != NULL) {
+        ctxt->entityLoader = f;
+    }
+}
+
+/**
+ * xmlGetContextExternalEntityLoader:
+ * @ctxt: the context from which to get the entity resolver
+ *
+ * Get the external entity resolver function used by the context.
+ *
+ * Returns the xmlExternalEntityLoader function pointer or NULL if
+ * the global default loader is being used.
+ */
+xmlExternalEntityLoader
+xmlGetContextExternalEntityLoader(xmlParserCtxtPtr ctxt) {
+    if (ctxt != NULL) {
+        return ctxt->entityLoader;
+    }
+    return NULL;
+}
+
+/**
  * xmlLoadExternalEntity:
  * @URL:  the URL for the entity to load
  * @ID:  the Public ID for the entity to load
@@ -3934,11 +3969,20 @@ xmlLoadExternalEntity(const char *URL, const char *ID,
 	    return(NULL);
 	}
 
-	ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
+    if (ctxt != NULL && ctxt->entityLoader != NULL) {
+        ret = ctxt->entityLoader(canonicFilename, ID, ctxt);
+    } else {
+        ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
+    }
 	xmlFree(canonicFilename);
 	return(ret);
     }
-    return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
+    
+    if (ctxt != NULL && ctxt->entityLoader != NULL) {
+        return (ctxt->entityLoader(URL, ID, ctxt));
+    } else {
+        return (xmlCurrentExternalEntityLoader(URL, ID, ctxt));
+    }
 }
 
 /************************************************************************
diff --git a/xmlschemas.c b/xmlschemas.c
index 96d55b8..8cbb7db 100644
--- a/xmlschemas.c
+++ b/xmlschemas.c
@@ -631,6 +631,8 @@ struct _xmlSchemaParserCtxt {
     xmlSchemaRedefPtr redef; /* Used for redefinitions. */
     int redefCounter; /* Used for redefinitions. */
     xmlSchemaItemListPtr attrProhibs;
+
+    xmlExternalEntityLoader entityLoader; /* external entity loader to us */
 };
 
 /**
@@ -1028,6 +1030,8 @@ struct _xmlSchemaValidCtxt {
     int hasKeyrefs;
     int createIDCNodeTables;
     int psviExposeIDCNodeTables;
+
+    xmlExternalEntityLoader entityLoader; /* external entity loader to us */
 };
 
 /**
@@ -9982,6 +9986,8 @@ xmlSchemaCreatePCtxtOnVCtxt(xmlSchemaValidCtxtPtr vctxt)
 	    vctxt->warning, vctxt->errCtxt);
 	xmlSchemaSetParserStructuredErrors(vctxt->pctxt, vctxt->serror,
 	    vctxt->errCtxt);
+        /* pass the external entity loader */
+        vctxt->pctxt->entityLoader = vctxt->entityLoader;
     }
     return (0);
 }
@@ -10514,6 +10520,7 @@ doc_load:
 		"allocating a parser context", NULL);
 	    goto exit_failure;
 	}
+    parserCtxt->entityLoader = pctxt->entityLoader;
 	if ((pctxt->dict != NULL) && (parserCtxt->dict != NULL)) {
 	    /*
 	    * TODO: Do we have to burden the schema parser dict with all
@@ -12436,6 +12443,7 @@ xmlSchemaNewParserCtxt(const char *URL)
 	return(NULL);
     ret->dict = xmlDictCreate();
     ret->URL = xmlDictLookup(ret->dict, (const xmlChar *) URL, -1);
+    ret->entityLoader = NULL;
     return (ret);
 }
 
@@ -15688,6 +15696,8 @@ xmlSchemaCreateVCtxtOnPCtxt(xmlSchemaParserCtxtPtr ctxt)
 	    ctxt->error, ctxt->warning, ctxt->errCtxt);
 	xmlSchemaSetValidStructuredErrors(ctxt->vctxt,
 	    ctxt->serror, ctxt->errCtxt);
+        /* Pass the external entity loader */
+        ctxt->vctxt->entityLoader = ctxt->entityLoader;
     }
     return (0);
 }
@@ -27387,6 +27397,7 @@ xmlSchemaNewValidCtxt(xmlSchemaPtr schema)
     ret->dict = xmlDictCreate();
     ret->nodeQNames = xmlSchemaItemListCreate();
     ret->schema = schema;
+    ret->entityLoader = NULL;
     return (ret);
 }
 
@@ -28609,6 +28620,7 @@ xmlSchemaValidateStream(xmlSchemaValidCtxtPtr ctxt,
     old_sax = pctxt->sax;
     pctxt->sax = sax;
     pctxt->userData = user_data;
+    pctxt->entityLoader = ctxt->entityLoader;
 #if 0
     if (options)
         xmlCtxtUseOptions(pctxt, options);
@@ -28708,6 +28720,70 @@ xmlSchemaValidCtxtGetParserCtxt(xmlSchemaValidCtxtPtr ctxt)
     return (ctxt->parserCtxt);
 }
 
+/**
+ * xmlSchemaSetValidExternalEntityLoader:
+ * @ctxt: the context for which to set the entity resolver
+ * @f:    the new entity resolver function
+ *
+ * Set the external entity resolver function for the context.
+ */
+void
+xmlSchemaSetValidExternalEntityLoader(xmlSchemaValidCtxtPtr ctxt,
+                                      xmlExternalEntityLoader f) {
+    if (ctxt != NULL) {
+        ctxt->entityLoader = f;
+    }
+}
+
+/**
+ * xmlSchemaGetValidExternalEntityLoader:
+ * @ctxt: the context from which to get the entity resolver
+ *
+ * Get the external entity resolver function used by the context.
+ *
+ * Returns the xmlExternalEntityLoader function pointer or NULL if
+ * the global default loader is being used.
+ */
+xmlExternalEntityLoader
+xmlSchemaGetValidExternalEntityLoader(xmlSchemaValidCtxtPtr ctxt) {
+    if (ctxt != NULL) {
+        return ctxt->entityLoader;
+    }
+    return NULL;
+}
+
+/**
+ * xmlSchemaSetParserExternalEntityLoader:
+ * @ctxt: the context for which to set the entity resolver
+ * @f:    the new entity resolver function
+ *
+ * Set the external entity resolver function for the context.
+ */
+void
+xmlSchemaSetParserExternalEntityLoader(xmlSchemaParserCtxtPtr ctxt,
+                                       xmlExternalEntityLoader f) {
+    if (ctxt != NULL) {
+        ctxt->entityLoader = f;
+    }
+}
+
+/**
+ * xmlSchemaGetParserExternalEntityLoader:
+ * @ctxt: the context from which to get the entity resolver
+ *
+ * Get the external entity resolver function used by the context.
+ *
+ * Returns the xmlExternalEntityLoader function pointer or NULL if
+ * the global default loader is being used.
+ */
+xmlExternalEntityLoader
+xmlSchemaGetParserExternalEntityLoader(xmlSchemaParserCtxtPtr ctxt) {
+    if (ctxt != NULL) {
+        return ctxt->entityLoader;
+    }
+    return NULL;
+}
+
 #define bottom_xmlschemas
 #include "elfgcchack.h"
 #endif /* LIBXML_SCHEMAS_ENABLED */

_______________________________________________
xml mailing list, project page  http://xmlsoft.org/
[email protected]
http://mail.gnome.org/mailman/listinfo/xml

Reply via email to