diff --git a/ChangeLog b/ChangeLog index 909397fb..3d4f217c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +Thu Sep 12 16:57:45 CEST 2002 Daniel Veillard + + * 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 * win32/configure.js: added more readme info for the binary diff --git a/python/generator.py b/python/generator.py index c34949e0..e2a4204f 100755 --- a/python/generator.py +++ b/python/generator.py @@ -268,6 +268,8 @@ py_types = { '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 @@ classes_type = { "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 @@ classes_ancestor = { "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 @@ def nameFixup(name, classe, type, file): 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 0072c31f..fd76ea81 100644 --- a/python/libxml.c +++ b/python/libxml.c @@ -12,6 +12,7 @@ * daniel@veillard.com */ #include +#include #include "config.h" #include #include @@ -20,21 +21,30 @@ #include #include #include +#include #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 * @@ -123,6 +133,363 @@ libxml_xmlDumpMemory(ATTRIBUTE_UNUSED PyObject * self, return (Py_None); } +/************************************************************************ + * * + * 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 @@ static PyMethodDef libxmlMethods[] = { {(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 @@ initlibxml2mod(void) 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 dd8cf770..73c54a6f 100644 --- a/python/libxml.py +++ b/python/libxml.py @@ -27,6 +27,74 @@ class xpathError: 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 938d968b..739b0669 100644 --- a/python/libxml2-python-api.xml +++ b/python/libxml2-python-api.xml @@ -50,6 +50,23 @@ + + Create a libxml2 output buffer from a Python file + + + + + + Create a libxml2 input buffer from a Python file + + + + + + Set the entity resolver as a python function + + + Get the document tree from a parser context. diff --git a/python/libxml2class.txt b/python/libxml2class.txt index 30838a08..0aaa7fbe 100644 --- a/python/libxml2class.txt +++ b/python/libxml2class.txt @@ -114,6 +114,8 @@ nodePush() # functions from module python SAXParseFile() +createInputBuffer() +createOutputBuffer() createPushParser() debugMemory() dumpMemory() @@ -121,6 +123,7 @@ htmlCreatePushParser() htmlSAXParseFile() newNode() registerErrorHandler() +setEntityLoader() # functions from module tree compressMode() @@ -276,10 +279,13 @@ Class xmlDoc(xmlNode) htmlIsAutoClosed() # functions from module HTMLtree + htmlDocContentDumpFormatOutput() + htmlDocContentDumpOutput() htmlDocDump() htmlGetMetaEncoding() htmlNodeDumpFile() htmlNodeDumpFileFormat() + htmlNodeDumpFormatOutput() htmlSaveFile() htmlSaveFileEnc() htmlSaveFileFormat() @@ -323,10 +329,13 @@ Class xmlDoc(xmlNode) newDtd() newGlobalNs() newReference() + nodeDumpOutput() saveFile() saveFileEnc() + saveFileTo() saveFormatFile() saveFormatFileEnc() + saveFormatFileTo() setDocCompressMode() stringGetNodeList() stringLenGetNodeList() @@ -510,6 +519,15 @@ Class parserCtxt() stringDecodeEntities() +Class outputBuffer(ioWriteWrapper) + + # functions from module xmlIO + close() + flush() + write() + writeString() + + Class xmlElement(xmlNode) @@ -584,3 +602,12 @@ Class xpathContext() 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 1877debe..7202c320 100644 --- a/python/libxml_wrap.h +++ b/python/libxml_wrap.h @@ -58,6 +58,22 @@ typedef struct { #define PyURI_Get(v) (((v) == Py_None) ? NULL : \ (((PyURI_Object *)(v))->obj)) +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; @@ -89,5 +105,7 @@ PyObject * libxml_xmlXPathParserContextPtrWrap(xmlXPathParserContextPtr ctxt); 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 3255141f..435b5acb 100644 --- a/python/tests/Makefile.am +++ b/python/tests/Makefile.am @@ -15,7 +15,10 @@ PYTESTS= \ 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 00000000..a7cc7a61 --- /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 00000000..ba8b25ee --- /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 43bf6564..e6e89d95 100755 --- a/python/tests/pushSAXhtml.py +++ b/python/tests/pushSAXhtml.py @@ -49,7 +49,8 @@ chunk = "ar" 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 00000000..16174a07 --- /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("")) + +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 984d4eb9..d7226c4a 100755 --- a/python/tests/serialize.py +++ b/python/tests/serialize.py @@ -76,7 +76,7 @@ if str != """ -Hello

hello

+Hello

hello

""": print "error serializing HTML document 2" sys.exit(1) @@ -84,7 +84,7 @@ str = doc.serialize(format=1) if str != """ - + Hello

hello

@@ -96,7 +96,7 @@ str = doc.serialize("iso-8859-1", 1) if str != """ - + Hello

hello

@@ -115,13 +115,13 @@ if str != """Hello

hello

Hello

hello

""": +if str != """Hello

hello

""": print "error serializing HTML root 2" sys.exit(1) str = root.serialize(format=1) if str != """ - + Hello

hello

@@ -131,7 +131,7 @@ if str != """ str = root.serialize("iso-8859-1", 1) if str != """ - + Hello

hello

diff --git a/python/types.c b/python/types.c index 2eff1a3e..6b13092e 100644 --- a/python/types.c +++ b/python/types.c @@ -469,3 +469,39 @@ libxml_xmlCatalogPtrWrap(xmlCatalogPtr catal) (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); +}