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);
+}