1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-06-13 19:21:37 +03:00

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
This commit is contained in:
Daniel Veillard
2002-09-12 15:00:57 +00:00
parent 353bf5822a
commit c6d4a933f0
14 changed files with 677 additions and 12 deletions

View File

@ -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 *
@ -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();