updated the python bindings, added code for easier File I/O, and the

* python/generator.py python/libxml.c python/libxml.py
  python/libxml2-python-api.xml python/libxml2class.txt
  python/libxml_wrap.h python/types.c: updated the python
  bindings, added code for easier File I/O, and the ability to
  define a resolver from Python fixing bug #91635
* python/tests/Makefile.am python/tests/inbuf.py
  python/tests/outbuf.py python/tests/pushSAXhtml.py
  python/tests/resolver.py python/tests/serialize.py: updated
  and augmented the set of Python tests.
Daniel
diff --git a/ChangeLog b/ChangeLog
index 909397f..3d4f217 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+Thu Sep 12 16:57:45 CEST 2002 Daniel Veillard <daniel@veillard.com>
+
+	* python/generator.py python/libxml.c python/libxml.py
+	  python/libxml2-python-api.xml python/libxml2class.txt
+	  python/libxml_wrap.h python/types.c: updated the python
+	  bindings, added code for easier File I/O, and the ability to
+	  define a resolver from Python fixing bug #91635
+	* python/tests/Makefile.am python/tests/inbuf.py
+	  python/tests/outbuf.py python/tests/pushSAXhtml.py
+	  python/tests/resolver.py python/tests/serialize.py: updated
+	  and augmented the set of Python tests.
+
 Tue Sep 10 21:05:28 CEST 2002 Igor Zlatkovic <igor@stud.fh-frankfurt.de>
 
 	* win32/configure.js: added more readme info for the binary
diff --git a/python/generator.py b/python/generator.py
index c34949e..e2a4204 100755
--- a/python/generator.py
+++ b/python/generator.py
@@ -268,6 +268,8 @@
     'xmlCatalogPtr': ('O', "catalog", "xmlCatalogPtr", "xmlCatalogPtr"),
     'FILE *': ('O', "File", "FILEPtr", "FILE *"),
     'xmlURIPtr': ('O', "URI", "xmlURIPtr", "xmlURIPtr"),
+    'xmlOutputBufferPtr': ('O', "outputBuffer", "xmlOutputBufferPtr", "xmlOutputBufferPtr"),
+    'xmlParserInputBufferPtr': ('O', "inputBuffer", "xmlParserInputBufferPtr", "xmlParserInputBufferPtr"),
 }
 
 py_return_types = {
@@ -583,6 +585,8 @@
     "htmlParserCtxt *": ("._o", "parserCtxt(_obj=%s)", "parserCtxt"),
     "xmlCatalogPtr": ("._o", "catalog(_obj=%s)", "catalog"),
     "xmlURIPtr": ("._o", "URI(_obj=%s)", "URI"),
+    "xmlOutputBufferPtr": ("._o", "outputBuffer(_obj=%s)", "outputBuffer"),
+    "xmlParserInputBufferPtr": ("._o", "inputBuffer(_obj=%s)", "inputBuffer"),
 }
 
 converter_type = {
@@ -600,11 +604,15 @@
     "xmlEntity" : "xmlNode",
     "xmlElement" : "xmlNode",
     "xmlAttribute" : "xmlNode",
+    "outputBuffer": "ioWriteWrapper",
+    "inputBuffer": "ioReadWrapper",
 }
 classes_destructors = {
     "parserCtxt": "xmlFreeParserCtxt",
     "catalog": "xmlFreeCatalog",
     "URI": "xmlFreeURI",
+#    "outputBuffer": "xmlOutputBufferClose",
+    "inputBuffer": "xmlFreeParserInputBuffer",
 }
 
 functions_noexcept = {
@@ -647,6 +655,12 @@
     elif name[0:11] == "xmlXPathSet" and file == "python_accessor":
         func = name[8:]
         func = string.lower(func[0:1]) + func[1:]
+    elif name[0:15] == "xmlOutputBuffer" and file != "python":
+        func = name[15:]
+        func = string.lower(func[0:1]) + func[1:]
+    elif name[0:20] == "xmlParserInputBuffer" and file != "python":
+        func = name[20:]
+        func = string.lower(func[0:1]) + func[1:]
     elif name[0:11] == "xmlACatalog":
         func = name[11:]
         func = string.lower(func[0:1]) + func[1:]
diff --git a/python/libxml.c b/python/libxml.c
index 0072c31..fd76ea8 100644
--- a/python/libxml.c
+++ b/python/libxml.c
@@ -12,6 +12,7 @@
  * daniel@veillard.com
  */
 #include <Python.h>
+#include <fileobject.h>
 #include "config.h"
 #include <libxml/xmlmemory.h>
 #include <libxml/parser.h>
@@ -20,21 +21,30 @@
 #include <libxml/xmlerror.h>
 #include <libxml/xpathInternals.h>
 #include <libxml/xmlmemory.h>
+#include <libxml/xmlIO.h>
 #include "libxml_wrap.h"
 #include "libxml2-py.h"
 
 /* #define DEBUG */
-
 /* #define DEBUG_SAX */
-
 /* #define DEBUG_XPATH */
-
 /* #define DEBUG_ERROR */
-
 /* #define DEBUG_MEMORY */
+/* #define DEBUG_FILES */
+/* #define DEBUG_LOADER */
 
 void initlibxml2mod(void);
 
+/**
+ * TODO:
+ *
+ * macro to flag unimplemented blocks
+ */
+#define TODO 								\
+    xmlGenericError(xmlGenericErrorContext,				\
+	    "Unimplemented block at %s:%d\n",				\
+            __FILE__, __LINE__);
+
 /************************************************************************
  *									*
  *		Memory debug interface					*
@@ -125,6 +135,363 @@
 
 /************************************************************************
  *									*
+ *		Handling Python FILE I/O at the C level			*
+ *	The raw I/O attack diectly the File objects, while the		*
+ *	other routines address the ioWrapper instance instead		*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlPythonFileCloseUnref:
+ * @context:  the I/O context
+ *
+ * Close an I/O channel
+ */
+static int
+xmlPythonFileCloseRaw (void * context) {
+    PyObject *file, *ret;
+
+#ifdef DEBUG_FILES
+    printf("xmlPythonFileCloseUnref\n");
+#endif
+    file = (PyObject *) context;
+    if (file == NULL) return(-1);
+    ret = PyEval_CallMethod(file, "close", "()");
+    if (ret != NULL) {
+	Py_DECREF(ret);
+    }
+    Py_DECREF(file);
+    return(0);
+}
+
+/**
+ * xmlPythonFileReadRaw:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Read @len bytes to @buffer from the Python file in the I/O channel
+ *
+ * Returns the number of bytes read
+ */
+static int
+xmlPythonFileReadRaw (void * context, char * buffer, int len) {
+    PyObject *file;
+    PyObject *ret;
+    int lenread = -1;
+    char *data;
+
+#ifdef DEBUG_FILES
+    printf("xmlPythonFileReadRaw: %d\n", len);
+#endif
+    file = (PyObject *) context;
+    if (file == NULL) return(-1);
+    ret = PyEval_CallMethod(file, "read", "(i)", len);
+    if (ret == NULL) {
+	printf("xmlPythonFileReadRaw: result is NULL\n");
+	return(-1);
+    } else if (PyString_Check(ret)) {
+	lenread = PyString_Size(ret);
+	data = PyString_AsString(ret);
+	if (lenread > len)
+	    memcpy(buffer, data, len);
+	else
+	    memcpy(buffer, data, lenread);
+	Py_DECREF(ret);
+    } else {
+	printf("xmlPythonFileReadRaw: result is not a String\n");
+	Py_DECREF(ret);
+    }
+    return(lenread);
+}
+
+/**
+ * xmlPythonFileRead:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Read @len bytes to @buffer from the I/O channel.
+ *
+ * Returns the number of bytes read
+ */
+static int
+xmlPythonFileRead (void * context, char * buffer, int len) {
+    PyObject *file;
+    PyObject *ret;
+    int lenread = -1;
+    char *data;
+
+#ifdef DEBUG_FILES
+    printf("xmlPythonFileRead: %d\n", len);
+#endif
+    file = (PyObject *) context;
+    if (file == NULL) return(-1);
+    ret = PyEval_CallMethod(file, "io_read", "(i)", len);
+    if (ret == NULL) {
+	printf("xmlPythonFileRead: result is NULL\n");
+	return(-1);
+    } else if (PyString_Check(ret)) {
+	lenread = PyString_Size(ret);
+	data = PyString_AsString(ret);
+	if (lenread > len)
+	    memcpy(buffer, data, len);
+	else
+	    memcpy(buffer, data, lenread);
+	Py_DECREF(ret);
+    } else {
+	printf("xmlPythonFileRead: result is not a String\n");
+	Py_DECREF(ret);
+    }
+    return(lenread);
+}
+
+/**
+ * xmlFileWrite:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Write @len bytes from @buffer to the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+static int
+xmlPythonFileWrite (void * context, const char * buffer, int len) {
+    PyObject *file;
+    PyObject *string;
+    PyObject *ret;
+    int written = -1;
+
+#ifdef DEBUG_FILES
+    printf("xmlPythonFileWrite: %d\n", len);
+#endif
+    file = (PyObject *) context;
+    if (file == NULL) return(-1);
+    string = PyString_FromStringAndSize(buffer, len);
+    if (string == NULL) return(-1);
+    ret = PyEval_CallMethod(file, "io_write", "(O)", string);
+    Py_DECREF(string);
+    if (ret == NULL) {
+	printf("xmlPythonFileWrite: result is NULL\n");
+	return(-1);
+    } else if (PyInt_Check(ret)) {
+	written = (int) PyInt_AsLong(ret);
+	Py_DECREF(ret);
+    } else if (ret == Py_None) {
+	written = len;
+	Py_DECREF(ret);
+    } else {
+	printf("xmlPythonFileWrite: result is not an Int nor None\n");
+	Py_DECREF(ret);
+    }
+    return(written);
+}
+
+/**
+ * xmlPythonFileClose:
+ * @context:  the I/O context
+ *
+ * Close an I/O channel
+ */
+static int
+xmlPythonFileClose (void * context) {
+    PyObject *file, *ret;
+
+#ifdef DEBUG_FILES
+    printf("xmlPythonFileClose\n");
+#endif
+    file = (PyObject *) context;
+    if (file == NULL) return(-1);
+    ret = PyEval_CallMethod(file, "io_close", "()");
+    if (ret != NULL) {
+	Py_DECREF(ret);
+    }
+    return(0);
+}
+
+/**
+ * xmlOutputBufferCreatePythonFile:
+ * @file:  a PyFile_Type
+ * @encoder:  the encoding converter or NULL
+ *
+ * Create a buffered output for the progressive saving to a PyFile_Type
+ * buffered C I/O
+ *
+ * Returns the new parser output or NULL
+ */
+xmlOutputBufferPtr
+xmlOutputBufferCreatePythonFile(PyObject *file, 
+	                        xmlCharEncodingHandlerPtr encoder) {
+    xmlOutputBufferPtr ret;
+
+    if (file == NULL) return(NULL);
+
+    ret = xmlAllocOutputBuffer(encoder);
+    if (ret != NULL) {
+        ret->context = file;
+	/* Py_INCREF(file); */
+	ret->writecallback = xmlPythonFileWrite;
+	ret->closecallback = xmlPythonFileClose;
+    }
+
+    return(ret);
+}
+
+PyObject *
+libxml_xmlCreateOutputBuffer(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) {
+    PyObject *py_retval;
+    PyObject *file;
+    xmlChar  *encoding;
+    xmlCharEncodingHandlerPtr handler = NULL;
+    xmlOutputBufferPtr buffer;
+
+
+    if (!PyArg_ParseTuple(args, (char *)"Oz:xmlOutputBufferCreate",
+		&file, &encoding))
+	return(NULL);
+    if ((encoding != NULL) && (encoding[0] != 0)) {
+	handler = xmlFindCharEncodingHandler(encoding);
+    }
+    buffer = xmlOutputBufferCreatePythonFile(file, handler);
+    if (buffer == NULL)
+	printf("libxml_xmlCreateOutputBuffer: buffer == NULL\n");
+    py_retval = libxml_xmlOutputBufferPtrWrap(buffer);
+    return(py_retval);
+}
+
+
+/**
+ * xmlParserInputBufferCreatePythonFile:
+ * @file:  a PyFile_Type
+ * @encoder:  the encoding converter or NULL
+ *
+ * Create a buffered output for the progressive saving to a PyFile_Type
+ * buffered C I/O
+ *
+ * Returns the new parser output or NULL
+ */
+xmlParserInputBufferPtr
+xmlParserInputBufferCreatePythonFile(PyObject *file, 
+	                        xmlCharEncoding encoding) {
+    xmlParserInputBufferPtr ret;
+
+    if (file == NULL) return(NULL);
+
+    ret = xmlAllocParserInputBuffer(encoding);
+    if (ret != NULL) {
+        ret->context = file;
+	/* Py_INCREF(file); */
+	ret->readcallback = xmlPythonFileRead;
+	ret->closecallback = xmlPythonFileClose;
+    }
+
+    return(ret);
+}
+
+PyObject *
+libxml_xmlCreateInputBuffer(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) {
+    PyObject *py_retval;
+    PyObject *file;
+    xmlChar  *encoding;
+    xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
+    xmlParserInputBufferPtr buffer;
+
+
+    if (!PyArg_ParseTuple(args, (char *)"Oz:xmlParserInputBufferCreate",
+		&file, &encoding))
+	return(NULL);
+    if ((encoding != NULL) && (encoding[0] != 0)) {
+	enc = xmlParseCharEncoding(encoding);
+    }
+    buffer = xmlParserInputBufferCreatePythonFile(file, enc);
+    if (buffer == NULL)
+	printf("libxml_xmlParserInputBufferCreate: buffer == NULL\n");
+    py_retval = libxml_xmlParserInputBufferPtrWrap(buffer);
+    return(py_retval);
+}
+
+/************************************************************************
+ *									*
+ *		Providing the resolver at the Python level		*
+ *									*
+ ************************************************************************/
+
+static xmlExternalEntityLoader defaultExternalEntityLoader = NULL;
+static PyObject *pythonExternalEntityLoaderObjext;
+
+static xmlParserInputPtr
+pythonExternalEntityLoader(const char *URL, const char *ID,
+			   xmlParserCtxtPtr ctxt) {
+    xmlParserInputPtr result = NULL;
+    if (pythonExternalEntityLoaderObjext != NULL) {
+	PyObject *ret;
+	PyObject *ctxtobj;
+
+	ctxtobj = libxml_xmlParserCtxtPtrWrap(ctxt);
+#ifdef DEBUG_LOADER
+	printf("pythonExternalEntityLoader: ready to call\n");
+#endif
+
+	ret = PyObject_CallFunction(pythonExternalEntityLoaderObjext,
+		      "(ssO)", URL, ID, ctxtobj);
+#ifdef DEBUG_LOADER
+	printf("pythonExternalEntityLoader: result ");
+	PyObject_Print(ret, stdout, 0);
+	printf("\n");
+#endif
+
+	if (ret != NULL) {
+	    if (PyObject_HasAttrString(ret, "read")) {
+		xmlParserInputBufferPtr buf;
+
+		buf = xmlAllocParserInputBuffer(XML_CHAR_ENCODING_NONE);
+		if (buf != NULL) {
+		    buf->context = ret;
+		    buf->readcallback = xmlPythonFileReadRaw;
+		    buf->closecallback = xmlPythonFileCloseRaw;
+		    result = xmlNewIOInputStream(ctxt, buf,
+			                         XML_CHAR_ENCODING_NONE);
+		}
+	    } else {
+		printf("pythonExternalEntityLoader: can't read\n");
+	    }
+	    if (result == NULL) {
+		Py_DECREF(ret);
+	    }
+	}
+    }
+    if ((result == NULL) && (defaultExternalEntityLoader != NULL)) {
+	result = defaultExternalEntityLoader(URL, ID, ctxt);
+    }
+    return(result);
+}
+
+PyObject *
+libxml_xmlSetEntityLoader(ATTRIBUTE_UNUSED PyObject *self, PyObject *args) {
+    PyObject *py_retval;
+    PyObject *loader;
+
+    if (!PyArg_ParseTuple(args, (char *)"O:libxml_xmlSetEntityLoader",
+		&loader))
+	return(NULL);
+
+#ifdef DEBUG_LOADER
+    printf("libxml_xmlSetEntityLoader\n");
+#endif
+    if (defaultExternalEntityLoader == NULL) 
+	defaultExternalEntityLoader = xmlGetExternalEntityLoader();
+
+    pythonExternalEntityLoaderObjext = loader;
+    xmlSetExternalEntityLoader(pythonExternalEntityLoader);
+
+    py_retval = PyInt_FromLong(0);
+    return(py_retval);
+}
+
+
+/************************************************************************
+ *									*
  *		Handling SAX/xmllib/sgmlop callback interfaces		*
  *									*
  ************************************************************************/
@@ -1821,6 +2188,9 @@
     {(char *) "xmlNewNode", libxml_xmlNewNode, METH_VARARGS, NULL},
     {(char *) "serializeNode", libxml_serializeNode, METH_VARARGS, NULL},
     {(char *) "saveNodeTo", libxml_saveNodeTo, METH_VARARGS, NULL},
+    {(char *) "outputBufferCreate", libxml_xmlCreateOutputBuffer, METH_VARARGS, NULL},
+    {(char *) "inputBufferCreate", libxml_xmlCreateInputBuffer, METH_VARARGS, NULL},
+    {(char *) "setEntityLoader", libxml_xmlSetEntityLoader, METH_VARARGS, NULL},
     {NULL, NULL, 0, NULL}
 };
 
@@ -1836,6 +2206,8 @@
 
     if (initialized != 0)
         return;
+    xmlRegisterDefaultOutputCallbacks();
+    xmlRegisterDefaultInputCallbacks();
     m = Py_InitModule((char *) "libxml2mod", libxmlMethods);
     initialized = 1;
     libxml_xmlErrorInitialize();
diff --git a/python/libxml.py b/python/libxml.py
index dd8cf77..73c54a6 100644
--- a/python/libxml.py
+++ b/python/libxml.py
@@ -27,6 +27,74 @@
     def __str__(self):
         return self.msg
 
+class ioWrapper:
+    def __init__(self, _obj):
+        self.__io = _obj
+        self._o = None
+
+    def io_close(self):
+        if self.__io == None:
+	    return(-1)
+	self.__io.close()
+	self.__io = None
+	return(0)
+
+    def io_flush(self):
+        if self.__io == None:
+	    return(-1)
+	self.__io.flush()
+	return(0)
+
+    def io_read(self, len = -1):
+        if self.__io == None:
+	    return(-1)
+        if len < 0:
+	    return(self.__io.read())
+	return(self.__io.read(len))
+
+    def io_write(self, str, len = -1):
+        if self.__io == None:
+	    return(-1)
+        if len < 0:
+	    return(self.__io.write(str))
+	return(self.__io.write(str, len))
+
+class ioReadWrapper(ioWrapper):
+    def __init__(self, _obj, enc = ""):
+        ioWrapper.__init__(self, _obj)
+        self._o = libxml2mod.xmlCreateInputBuffer(self, enc)
+
+    def __del__(self):
+        print "__del__"
+        self.io_close()
+        if self._o != None:
+            libxml2mod.xmlFreeParserInputBuffer(self._o)
+        self._o = None
+
+    def close(self):
+        self.io_close()
+        if self._o != None:
+            libxml2mod.xmlFreeParserInputBuffer(self._o)
+        self._o = None
+
+class ioWriteWrapper(ioWrapper):
+    def __init__(self, _obj, enc = ""):
+        ioWrapper.__init__(self, _obj)
+        self._o = libxml2mod.xmlCreateOutputBuffer(self, enc)
+
+    def __del__(self):
+        print "__del__"
+        self.io_close()
+        if self._o != None:
+            libxml2mod.xmlOutputBufferClose(self._o)
+        self._o = None
+
+    def close(self):
+        self.io_close()
+        if self._o != None:
+            libxml2mod.xmlOutputBufferClose(self._o)
+        self._o = None
+
 #
 # Example of a class to handle SAX events
 #
diff --git a/python/libxml2-python-api.xml b/python/libxml2-python-api.xml
index 938d968..739b066 100644
--- a/python/libxml2-python-api.xml
+++ b/python/libxml2-python-api.xml
@@ -50,6 +50,23 @@
       <arg name='URI' type='xmlChar *' info='The URI of the resource'/>
       <arg name='encoding' type='const char *' info='encoding or None'/>
     </function>
+    <function name='xmlCreateOutputBuffer' file='python'>
+      <info>Create a libxml2 output buffer from a Python file</info>
+      <return type='xmlOutputBufferPtr' info="the output buffer"/>
+      <arg name='file' type='pythonObject' info='the Python file'/>
+      <arg name='encoding' type='xmlChar *' info='an optionnal encoding'/>
+    </function>
+    <function name='xmlCreateInputBuffer' file='python'>
+      <info>Create a libxml2 input buffer from a Python file</info>
+      <return type='xmlParserInputBufferPtr' info="the input buffer"/>
+      <arg name='file' type='pythonObject' info='the Python file'/>
+      <arg name='encoding' type='xmlChar *' info='an optionnal encoding'/>
+    </function>
+    <function name='xmlSetEntityLoader' file='python'>
+      <info>Set the entity resolver as a python function</info>
+      <return type='int' info="0 in case of success, -1 for error"/>
+      <arg name='resolver' type='pythonObject' info='the Python function'/>
+    </function>
     <!-- xmlParserCtxtPtr accessors -->
     <function name='xmlParserGetDoc' file='python_accessor'>
       <info>Get the document tree from a parser context.</info>
diff --git a/python/libxml2class.txt b/python/libxml2class.txt
index 30838a0..0aaa7fb 100644
--- a/python/libxml2class.txt
+++ b/python/libxml2class.txt
@@ -114,6 +114,8 @@
 
 # functions from module python
 SAXParseFile()
+createInputBuffer()
+createOutputBuffer()
 createPushParser()
 debugMemory()
 dumpMemory()
@@ -121,6 +123,7 @@
 htmlSAXParseFile()
 newNode()
 registerErrorHandler()
+setEntityLoader()
 
 # functions from module tree
 compressMode()
@@ -276,10 +279,13 @@
     htmlIsAutoClosed()
 
     # functions from module HTMLtree
+    htmlDocContentDumpFormatOutput()
+    htmlDocContentDumpOutput()
     htmlDocDump()
     htmlGetMetaEncoding()
     htmlNodeDumpFile()
     htmlNodeDumpFileFormat()
+    htmlNodeDumpFormatOutput()
     htmlSaveFile()
     htmlSaveFileEnc()
     htmlSaveFileFormat()
@@ -323,10 +329,13 @@
     newDtd()
     newGlobalNs()
     newReference()
+    nodeDumpOutput()
     saveFile()
     saveFileEnc()
+    saveFileTo()
     saveFormatFile()
     saveFormatFileEnc()
+    saveFormatFileTo()
     setDocCompressMode()
     stringGetNodeList()
     stringLenGetNodeList()
@@ -510,6 +519,15 @@
     stringDecodeEntities()
 
 
+Class outputBuffer(ioWriteWrapper)
+
+    # functions from module xmlIO
+    close()
+    flush()
+    write()
+    writeString()
+
+
 Class xmlElement(xmlNode)
 
 
@@ -584,3 +602,12 @@
     xpathRegisteredVariablesCleanup()
     xpathVariableLookup()
     xpathVariableLookupNS()
+
+
+Class inputBuffer(ioReadWrapper)
+
+    # functions from module xmlIO
+    freeParserInputBuffer()
+    grow()
+    push()
+    read()
diff --git a/python/libxml_wrap.h b/python/libxml_wrap.h
index 1877deb..7202c32 100644
--- a/python/libxml_wrap.h
+++ b/python/libxml_wrap.h
@@ -60,6 +60,22 @@
 
 typedef struct {
     PyObject_HEAD
+    xmlOutputBufferPtr obj;
+} PyoutputBuffer_Object;
+
+#define PyoutputBuffer_Get(v) (((v) == Py_None) ? NULL : \
+	(((PyURI_Object *)(v))->obj))
+
+typedef struct {
+    PyObject_HEAD
+    xmlParserInputBufferPtr obj;
+} PyinputBuffer_Object;
+
+#define PyinputBuffer_Get(v) (((v) == Py_None) ? NULL : \
+	(((PyURI_Object *)(v))->obj))
+
+typedef struct {
+    PyObject_HEAD
     xmlURIPtr obj;
 } PyURI_Object;
 
@@ -89,5 +105,7 @@
 PyObject * libxml_xmlXPathObjectPtrWrap(xmlXPathObjectPtr obj);
 PyObject * libxml_xmlCatalogPtrWrap(xmlCatalogPtr obj);
 PyObject * libxml_xmlURIPtrWrap(xmlURIPtr uri);
+PyObject * libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer);
+PyObject * libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer);
 
 xmlXPathObjectPtr libxml_xmlXPathObjectPtrConvert(PyObject * obj);
diff --git a/python/tests/Makefile.am b/python/tests/Makefile.am
index 3255141..435b5ac 100644
--- a/python/tests/Makefile.am
+++ b/python/tests/Makefile.am
@@ -15,7 +15,10 @@
     tstURI.py	\
     cutnpaste.py\
     xpathret.py	\
-    xpath.py
+    xpath.py	\
+    outbuf.py	\
+    inbuf.py	\
+    resolver.py
 
 XMLS=		\
     tst.xml	\
diff --git a/python/tests/inbuf.py b/python/tests/inbuf.py
new file mode 100755
index 0000000..a7cc7a6
--- /dev/null
+++ b/python/tests/inbuf.py
@@ -0,0 +1,25 @@
+#!/usr/bin/python -u
+import sys
+import libxml2
+import StringIO
+
+# Memory debug specific
+libxml2.debugMemory(1)
+
+i = 0
+while i < 5000:
+    f = StringIO.StringIO("foobar")
+    buf = libxml2.inputBuffer(f)
+    i = i + 1
+
+del f
+del buf
+
+# Memory debug specific
+libxml2.cleanupParser()
+if libxml2.debugMemory(1) == 0:
+    print "OK"
+else:
+    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+    libxml2.dumpMemory()
+
diff --git a/python/tests/outbuf.py b/python/tests/outbuf.py
new file mode 100755
index 0000000..ba8b25e
--- /dev/null
+++ b/python/tests/outbuf.py
@@ -0,0 +1,33 @@
+#!/usr/bin/python -u
+import sys
+import libxml2
+import StringIO
+
+print "Skipped"
+sys.exit(1)
+
+# Memory debug specific
+libxml2.debugMemory(1)
+
+#f = open('res', 'w')
+f = StringIO.StringIO()
+buf = libxml2.createOutputBuffer(f, "ISO-8859-1")
+buf.write(3, "foo")
+buf.writeString("bar")
+buf.close()
+del buf
+
+if f.getvalue() != "foobar":
+    print "Failed to save to StringIO"
+    sys.exit(1)
+
+del f
+
+# Memory debug specific
+libxml2.cleanupParser()
+if libxml2.debugMemory(1) == 0:
+    print "OK"
+else:
+    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+    libxml2.dumpMemory()
+
diff --git a/python/tests/pushSAXhtml.py b/python/tests/pushSAXhtml.py
index 43bf656..e6e89d9 100755
--- a/python/tests/pushSAXhtml.py
+++ b/python/tests/pushSAXhtml.py
@@ -49,7 +49,8 @@
 ctxt.htmlParseChunk(chunk, len(chunk), 1)
 ctxt=None
 
-reference = "startDocument:startElement foo {'url': 'tst'}:characters: bar:endElement foo:endDocument:"
+reference = """startDocument:startElement html None:startElement body None:startElement foo {'url': 'tst'}:error: Tag foo invalid
+:characters: bar:endElement foo:endElement body:endElement html:endDocument:"""
 if log != reference:
     print "Error got: %s" % log
     print "Exprected: %s" % reference
diff --git a/python/tests/resolver.py b/python/tests/resolver.py
new file mode 100755
index 0000000..16174a0
--- /dev/null
+++ b/python/tests/resolver.py
@@ -0,0 +1,39 @@
+#!/usr/bin/python -u
+import sys
+import libxml2
+import StringIO
+
+# Memory debug specific
+libxml2.debugMemory(1)
+
+def myResolver(URL, ID, ctxt):
+    return(StringIO.StringIO("<foo/>"))
+
+libxml2.setEntityLoader(myResolver)
+
+doc = libxml2.parseFile("doesnotexist.xml")
+root = doc.children
+if root.name != "foo":
+    print "root element name error"
+    sys.exit(1)
+doc.freeDoc()
+
+i = 0
+while i < 5000:
+    doc = libxml2.parseFile("doesnotexist.xml")
+    root = doc.children
+    if root.name != "foo":
+	print "root element name error"
+	sys.exit(1)
+    doc.freeDoc()
+    i = i + 1
+
+
+# Memory debug specific
+libxml2.cleanupParser()
+if libxml2.debugMemory(1) == 0:
+    print "OK"
+else:
+    print "Memory leak %d bytes" % (libxml2.debugMemory(1))
+    libxml2.dumpMemory()
+
diff --git a/python/tests/serialize.py b/python/tests/serialize.py
index 984d4eb..d7226c4 100755
--- a/python/tests/serialize.py
+++ b/python/tests/serialize.py
@@ -76,7 +76,7 @@
    sys.exit(1)
 str = doc.serialize("ISO-8859-1")
 if str != """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
-<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"><title>Hello</title></head><body><p>hello</p></body></html>
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Hello</title></head><body><p>hello</p></body></html>
 """:
    print "error serializing HTML document 2"
    sys.exit(1)
@@ -84,7 +84,7 @@
 if str != """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
 <html>
 <head>
-<meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type">
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>Hello</title>
 </head>
 <body><p>hello</p></body>
@@ -96,7 +96,7 @@
 if str != """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
 <html>
 <head>
-<meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
 <title>Hello</title>
 </head>
 <body><p>hello</p></body>
@@ -115,13 +115,13 @@
    print "error serializing HTML root 1"
    sys.exit(1)
 str = root.serialize("ISO-8859-1")
-if str != """<html><head><meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type"><title>Hello</title></head><body><p>hello</p></body></html>""":
+if str != """<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Hello</title></head><body><p>hello</p></body></html>""":
    print "error serializing HTML root 2"
    sys.exit(1)
 str = root.serialize(format=1)
 if str != """<html>
 <head>
-<meta content="text/html; charset=ISO-8859-1" http-equiv="Content-Type">
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
 <title>Hello</title>
 </head>
 <body><p>hello</p></body>
@@ -131,7 +131,7 @@
 str = root.serialize("iso-8859-1", 1)
 if str != """<html>
 <head>
-<meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
 <title>Hello</title>
 </head>
 <body><p>hello</p></body>
diff --git a/python/types.c b/python/types.c
index 2eff1a3..6b13092 100644
--- a/python/types.c
+++ b/python/types.c
@@ -469,3 +469,39 @@
                                      (char *) "xmlCatalogPtr", NULL);
     return (ret);
 }
+
+PyObject *
+libxml_xmlOutputBufferPtrWrap(xmlOutputBufferPtr buffer)
+{
+    PyObject *ret;
+
+#ifdef DEBUG
+    printf("libxml_xmlOutputBufferPtrWrap: buffer = %p\n", buffer);
+#endif
+    if (buffer == NULL) {
+        Py_INCREF(Py_None);
+        return (Py_None);
+    }
+    ret =
+        PyCObject_FromVoidPtrAndDesc((void *) buffer,
+                                     (char *) "xmlOutputBufferPtr", NULL);
+    return (ret);
+}
+
+PyObject *
+libxml_xmlParserInputBufferPtrWrap(xmlParserInputBufferPtr buffer)
+{
+    PyObject *ret;
+
+#ifdef DEBUG
+    printf("libxml_xmlParserInputBufferPtrWrap: buffer = %p\n", buffer);
+#endif
+    if (buffer == NULL) {
+        Py_INCREF(Py_None);
+        return (Py_None);
+    }
+    ret =
+        PyCObject_FromVoidPtrAndDesc((void *) buffer,
+                                     (char *) "xmlParserInputBufferPtr", NULL);
+    return (ret);
+}