1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-07-29 11:41:22 +03:00

- Large resync between W3C and Gnome tree

- configure.in: 2.1.0 prerelease
- example/Makefile.am example/gjobread.c tree.h: work on
  libxml1 libxml2 convergence.
- nanoftp, nanohttp.c: fixed stalled connections probs
- HTMLtree.c SAX.c : support for attribute without values in
  HTML for andersca
- valid.c: Fixed most validation + namespace problems
- HTMLparser.c: start document callback for andersca
- debugXML.c xpath.c: lots of XPath fixups from Picdar Technology
- parser.h, SAX.c: serious speed improvement for large
  CDATA blocks
- encoding.[ch] xmlIO.[ch]: Improved seriously saving to
  different encoding
- config.h.in parser.c xmllint.c: added xmlCheckVersion()
  and the LIBXML_TEST_VERSION macro
Daniel
This commit is contained in:
Daniel Veillard
2000-06-28 23:40:59 +00:00
parent c310d56482
commit be803967db
41 changed files with 2877 additions and 1562 deletions

627
xmlIO.c
View File

@ -41,9 +41,9 @@
#include <libxml/nanohttp.h>
#include <libxml/nanoftp.h>
/* #define DEBUG_INPUT */
/* #define VERBOSE_FAILURE */
/* #define DEBUG_EXTERNAL_ENTITIES */
/* #define DEBUG_INPUT */
#ifdef DEBUG_INPUT
#define MINLEN 40
@ -67,6 +67,22 @@ xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
int xmlInputCallbackNr = 0;
int xmlInputCallbackInitialized = 0;
/*
* Output I/O callback sets
*/
typedef struct _xmlOutputCallback {
xmlOutputMatchCallback matchcallback;
xmlOutputOpenCallback opencallback;
xmlOutputWriteCallback writecallback;
xmlOutputCloseCallback closecallback;
} xmlOutputCallback;
#define MAX_OUTPUT_CALLBACK 15
xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
int xmlOutputCallbackNr = 0;
int xmlOutputCallbackInitialized = 0;
/************************************************************************
* *
* Standard I/O for file accesses *
@ -123,11 +139,44 @@ xmlFdOpen (const char *filename) {
return((void *) fd);
}
/**
* xmlFdOpenW:
* @filename: the URI for matching
*
* input from file descriptor,
* if @filename is "-" then the standard output is used
*
* Returns an I/O context or NULL in case of error
*/
void *
xmlFdOpenW (const char *filename) {
const char *path = NULL;
int fd;
if (!strcmp(filename, "-")) {
fd = 1;
return((void *) fd);
}
if (!strncmp(filename, "file://localhost", 16))
path = &filename[16];
else if (!strncmp(filename, "file:///", 8))
path = &filename[8];
else if (filename[0] == '/')
path = filename;
if (path == NULL)
return(NULL);
fd = open (filename, O_WRONLY);
return((void *) fd);
}
/**
* xmlFdRead:
* @context: the I/O context
* @buffer: where to drop data
* @len: number of bytes to write
* @len: number of bytes to read
*
* Read @len bytes to @buffer from the I/O channel.
*
@ -138,6 +187,21 @@ xmlFdRead (void * context, char * buffer, int len) {
return(read((int) context, &buffer[0], len));
}
/**
* xmlFdWrite:
* @context: the I/O context
* @buffer: where to get data
* @len: number of bytes to write
*
* Write @len bytes from @buffer to the I/O channel.
*
* Returns the number of bytes written
*/
int
xmlFdWrite (void * context, const char * buffer, int len) {
return(write((int) context, &buffer[0], len));
}
/**
* xmlFdClose:
* @context: the I/O context
@ -198,6 +262,38 @@ xmlFileOpen (const char *filename) {
return((void *) fd);
}
/**
* xmlFileOpenW:
* @filename: the URI for matching
*
* output to from FILE *,
* if @filename is "-" then the standard output is used
*
* Returns an I/O context or NULL in case of error
*/
void *
xmlFileOpenW (const char *filename) {
const char *path = NULL;
FILE *fd;
if (!strcmp(filename, "-")) {
fd = stdout;
return((void *) fd);
}
if (!strncmp(filename, "file://localhost", 16))
path = &filename[16];
else if (!strncmp(filename, "file:///", 8))
path = &filename[8];
else
path = filename;
if (path == NULL)
return(NULL);
fd = fopen(path, "w");
return((void *) fd);
}
/**
* xmlFileRead:
* @context: the I/O context
@ -213,6 +309,21 @@ xmlFileRead (void * context, char * buffer, int len) {
return(fread(&buffer[0], 1, len, (FILE *) context));
}
/**
* 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
*/
int
xmlFileWrite (void * context, const char * buffer, int len) {
return(fwrite(&buffer[0], 1, len, (FILE *) context));
}
/**
* xmlFileClose:
* @context: the I/O context
@ -273,6 +384,39 @@ xmlGzfileOpen (const char *filename) {
return((void *) fd);
}
/**
* xmlGzfileOpenW:
* @filename: the URI for matching
* @compression: the compression factor (0 - 9 included)
*
* input from compressed file open
* if @filename is " " then the standard input is used
*
* Returns an I/O context or NULL in case of error
*/
void *
xmlGzfileOpenW (const char *filename, int compression) {
const char *path = NULL;
char mode[15];
gzFile fd;
sprintf(mode, "w%d", compression);
if (!strcmp(filename, "-")) {
fd = gzdopen(1, mode);
return((void *) fd);
}
if (!strncmp(filename, "file://localhost", 16))
path = &filename[16];
else if (!strncmp(filename, "file:///", 8))
path = &filename[8];
else
path = filename;
fd = gzopen(filename, mode);
return((void *) fd);
}
/**
* xmlGzfileRead:
* @context: the I/O context
@ -288,6 +432,21 @@ xmlGzfileRead (void * context, char * buffer, int len) {
return(gzread((gzFile) context, &buffer[0], len));
}
/**
* xmlGzfileWrite:
* @context: the I/O context
* @buffer: where to drop data
* @len: number of bytes to write
*
* Write @len bytes from @buffer to the compressed I/O channel.
*
* Returns the number of bytes written
*/
int
xmlGzfileWrite (void * context, const char * buffer, int len) {
return(gzwrite((gzFile) context, (char *) &buffer[0], len));
}
/**
* xmlGzfileClose:
* @context: the I/O context
@ -448,6 +607,31 @@ xmlRegisterInputCallbacks(xmlInputMatchCallback match,
return(xmlInputCallbackNr++);
}
/**
* xmlRegisterOutputCallbacks:
* @match: the xmlOutputMatchCallback
* @open: the xmlOutputOpenCallback
* @write: the xmlOutputWriteCallback
* @close: the xmlOutputCloseCallback
*
* Register a new set of I/O callback for handling output.
*
* Returns the registered handler number or -1 in case of error
*/
int
xmlRegisterOutputCallbacks(xmlOutputMatchCallback match,
xmlOutputOpenCallback open, xmlOutputWriteCallback write,
xmlOutputCloseCallback close) {
if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
return(-1);
}
xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = match;
xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = open;
xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = write;
xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = close;
return(xmlOutputCallbackNr++);
}
/**
* xmlRegisterDefaultInputCallbacks:
*
@ -473,6 +657,39 @@ xmlRegisterDefaultInputCallbacks(void) {
#endif /* LIBXML_FTP_ENABLED */
}
/**
* xmlRegisterDefaultOutputCallbacks:
*
* Registers the default compiled-in I/O handlers.
*/
void
xmlRegisterDefaultOutputCallbacks(void) {
xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
xmlFileWrite, xmlFileClose);
/*********************************
No way a-priori to distinguish between gzipped files from
uncompressed ones except opening if existing then closing
and saving with same compression ratio ... a pain.
#ifdef HAVE_ZLIB_H
xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
xmlGzfileWrite, xmlGzfileClose);
#endif
No HTTP PUT support yet, patches welcome
#ifdef LIBXML_HTTP_ENABLED
xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
xmlIOHTTPWrite, xmlIOHTTPClose);
#endif
Nor FTP PUT ....
#ifdef LIBXML_FTP_ENABLED
xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
xmlIOFTPWrite, xmlIOFTPClose);
#endif
**********************************/
}
/**
* xmlAllocParserInputBuffer:
* @enc: the charset encoding if known
@ -509,6 +726,47 @@ xmlAllocParserInputBuffer(xmlCharEncoding enc) {
return(ret);
}
/**
* xmlAllocOutputBuffer:
* @encoder: the encoding converter or NULL
*
* Create a buffered parser output
*
* Returns the new parser output or NULL
*/
xmlOutputBufferPtr
xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
xmlOutputBufferPtr ret;
ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
if (ret == NULL) {
fprintf(stderr, "xmlAllocOutputBuffer : out of memory!\n");
return(NULL);
}
memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
ret->buffer = xmlBufferCreate();
if (ret->buffer == NULL) {
xmlFree(ret);
return(NULL);
}
ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
ret->encoder = encoder;
if (encoder != NULL) {
ret->conv = xmlBufferCreateSize(4000);
/*
* This call is designed to initiate the encoder state
*/
xmlCharEncOutFunc(encoder, ret->conv, NULL);
} else
ret->conv = NULL;
ret->writecallback = NULL;
ret->closecallback = NULL;
ret->context = NULL;
ret->written = 0;
return(ret);
}
/**
* xmlFreeParserInputBuffer:
* @in: a buffered parser input
@ -536,6 +794,43 @@ xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
xmlFree(in);
}
/**
* xmlOutputBufferClose:
* @out: a buffered output
*
* flushes and close the output I/O channel
* and free up all the associated resources
*
* Returns the number of byte written or -1 in case of error.
*/
int
xmlOutputBufferClose(xmlOutputBufferPtr out) {
int written;
if (out == NULL)
return(-1);
xmlOutputBufferFlush(out);
if (out->closecallback != NULL) {
out->closecallback(out->context);
}
written = out->written;
if (out->conv) {
xmlBufferFree(out->conv);
out->conv = NULL;
}
if (out->encoder != NULL) {
xmlCharEncCloseFunc(out->encoder);
}
if (out->buffer != NULL) {
xmlBufferFree(out->buffer);
out->buffer = NULL;
}
memset(out, 0xbe, (size_t) sizeof(xmlOutputBuffer));
xmlFree(out);
return(written);
}
/**
* xmlParserInputBufferCreateFilename:
* @URI: a C string containing the URI or filename
@ -591,6 +886,80 @@ xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
return(ret);
}
/**
* xmlOutputBufferCreateFilename:
* @URI: a C string containing the URI or filename
* @encoder: the encoding converter or NULL
* @compression: the compression ration (0 none, 9 max).
*
* Create a buffered output for the progressive saving of a file
* If filename is "-' then we use stdout as the output.
* Automatic support for ZLIB/Compress compressed document is provided
* by default if found at compile-time.
* TODO: currently if compression is set, the library only support
* writing to a local file.
*
* Returns the new output or NULL
*/
xmlOutputBufferPtr
xmlOutputBufferCreateFilename(const char *URI,
xmlCharEncodingHandlerPtr encoder,
int compression) {
xmlOutputBufferPtr ret;
int i;
void *context = NULL;
if (xmlOutputCallbackInitialized == 0)
xmlRegisterDefaultOutputCallbacks();
if (URI == NULL) return(NULL);
#ifdef HAVE_ZLIB_H
if ((compression > 0) && (compression <= 9)) {
context = xmlGzfileOpenW(URI, compression);
if (context != NULL) {
ret = xmlAllocOutputBuffer(encoder);
if (ret != NULL) {
ret->context = context;
ret->writecallback = xmlGzfileWrite;
ret->closecallback = xmlGzfileClose;
}
return(ret);
}
}
#endif
/*
* Try to find one of the output accept method accepting taht scheme
* Go in reverse to give precedence to user defined handlers.
*/
for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
(xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
context = xmlOutputCallbackTable[i].opencallback(URI);
if (context != NULL)
break;
}
}
if (context == NULL) {
#ifdef DEBUG_INPUT
fprintf(stderr, "No output filter matching \"%s\"\n", URI);
#endif
return(NULL);
}
/*
* Allocate the Output buffer front-end.
*/
ret = xmlAllocOutputBuffer(encoder);
if (ret != NULL) {
ret->context = context;
ret->writecallback = xmlOutputCallbackTable[i].writecallback;
ret->closecallback = xmlOutputCallbackTable[i].closecallback;
}
return(ret);
}
/**
* xmlParserInputBufferCreateFile:
* @file: a FILE*
@ -620,6 +989,35 @@ xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
return(ret);
}
/**
* xmlOutputBufferCreateFile:
* @file: a FILE*
* @encoder: the encoding converter or NULL
*
* Create a buffered output for the progressive saving to a FILE *
* buffered C I/O
*
* Returns the new parser output or NULL
*/
xmlOutputBufferPtr
xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
xmlOutputBufferPtr ret;
if (xmlOutputCallbackInitialized == 0)
xmlRegisterDefaultOutputCallbacks();
if (file == NULL) return(NULL);
ret = xmlAllocOutputBuffer(encoder);
if (ret != NULL) {
ret->context = file;
ret->writecallback = xmlFileWrite;
ret->closecallback = xmlFileClose;
}
return(ret);
}
/**
* xmlParserInputBufferCreateFd:
* @fd: a file descriptor number
@ -646,6 +1044,32 @@ xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
return(ret);
}
/**
* xmlOutputBufferCreateFd:
* @fd: a file descriptor number
* @encoder: the encoding converter or NULL
*
* Create a buffered output for the progressive saving
* to a file descriptor
*
* Returns the new parser output or NULL
*/
xmlOutputBufferPtr
xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
xmlOutputBufferPtr ret;
if (fd < 0) return(NULL);
ret = xmlAllocOutputBuffer(encoder);
if (ret != NULL) {
ret->context = (void *) fd;
ret->writecallback = xmlFdWrite;
ret->closecallback = xmlFdClose;
}
return(ret);
}
/**
* xmlParserInputBufferCreateIO:
* @ioread: an I/O read function
@ -654,7 +1078,7 @@ xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
* @enc: the charset encoding if known
*
* Create a buffered parser input for the progressive parsing for the input
* from a file descriptor
* from an I/O handler
*
* Returns the new parser input or NULL
*/
@ -675,11 +1099,41 @@ xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
return(ret);
}
/**
* xmlOutputBufferCreateIO:
* @iowrite: an I/O write function
* @ioclose: an I/O close function
* @ioctx: an I/O handler
* @enc: the charset encoding if known
*
* Create a buffered output for the progressive saving
* to an I/O handler
*
* Returns the new parser output or NULL
*/
xmlOutputBufferPtr
xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
xmlOutputCloseCallback ioclose, void *ioctx,
xmlCharEncodingHandlerPtr encoder) {
xmlOutputBufferPtr ret;
if (iowrite == NULL) return(NULL);
ret = xmlAllocOutputBuffer(encoder);
if (ret != NULL) {
ret->context = (void *) ioctx;
ret->writecallback = iowrite;
ret->closecallback = ioclose;
}
return(ret);
}
/**
* xmlParserInputBufferPush:
* @in: a buffered parser input
* @buf: an char array
* @len: the size in bytes of the array.
* @buf: an char array
*
* Push the content of the arry in the input buffer
* This routine handle the I18N transcoding to internal UTF-8
@ -769,16 +1223,12 @@ xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
xmlFree(buffer);
return(-1);
}
if (res == 0) {
xmlFree(buffer);
return(0);
}
if (res < 0) {
perror ("read error");
xmlFree(buffer);
return(-1);
}
len = res;
if (in->encoder != NULL) {
/*
* Store the data in the incoming raw buffer
@ -797,7 +1247,7 @@ xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
return(-1);
}
} else {
nbchars = res;
nbchars = len;
buffer[nbchars] = 0;
xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
}
@ -827,7 +1277,162 @@ xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
if (in->readcallback != NULL)
return(xmlParserInputBufferGrow(in, len));
else
return(0);
return(-1);
}
/**
* xmlOutputBufferWrite:
* @out: a buffered parser output
* @len: the size in bytes of the array.
* @buf: an char array
*
* Write the content of the array in the output I/O buffer
* This routine handle the I18N transcoding from internal UTF-8
* The buffer is lossless, i.e. will store in case of partial
* or delayed writes.
*
* Returns the number of chars immediately written, or -1
* in case of error.
*/
int
xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
int nbchars = 0, ret;
if (len < 0) return(0);
/*
* first handle encoding stuff.
*/
if (out->encoder != NULL) {
/*
* Store the data in the incoming raw buffer
*/
if (out->conv == NULL) {
out->conv = xmlBufferCreate();
}
xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
if (out->buffer->use < MINLEN)
return(0);
/*
* convert as much as possible to the parser reading buffer.
*/
nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
if (nbchars < 0) {
fprintf(stderr, "xmlOutputBufferWrite: encoder error\n");
return(-1);
}
nbchars = out->conv->use;
} else {
xmlBufferAdd(out->buffer, (const xmlChar *) buf, len);
nbchars = out->buffer->use;
}
if (nbchars < MINLEN)
return(0);
/*
* second write the stuff to the I/O channel
*/
if (out->encoder != NULL) {
ret = out->writecallback(out->context,
(const char *)out->conv->content, nbchars);
if (ret >= 0)
xmlBufferShrink(out->conv, nbchars);
} else {
ret = out->writecallback(out->context,
(const char *)out->buffer->content, nbchars);
if (ret >= 0)
xmlBufferShrink(out->buffer, nbchars);
}
if (ret < 0) {
fprintf(stderr, "I/O: error %d writing %d bytes\n", ret, nbchars);
return(ret);
}
out->written += ret;
#ifdef DEBUG_INPUT
fprintf(stderr, "I/O: wrote %d chars\n", ret);
#endif
return(nbchars);
}
/**
* xmlOutputBufferWriteString:
* @out: a buffered parser output
* @str: a zero terminated C string
*
* Write the content of the string in the output I/O buffer
* This routine handle the I18N transcoding from internal UTF-8
* The buffer is lossless, i.e. will store in case of partial
* or delayed writes.
*
* Returns the number of chars immediately written, or -1
* in case of error.
*/
int
xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
int len;
if (str == NULL)
return(-1);
len = strlen(str);
if (len > 0)
return(xmlOutputBufferWrite(out, len, str));
return(len);
}
/**
* xmlOutputBufferFlush:
* @out: a buffered output
*
* flushes the output I/O channel
*
* Returns the number of byte written or -1 in case of error.
*/
int
xmlOutputBufferFlush(xmlOutputBufferPtr out) {
int nbchars = 0, ret;
/*
* first handle encoding stuff.
*/
if ((out->conv != NULL) && (out->encoder != NULL)) {
/*
* convert as much as possible to the parser reading buffer.
*/
nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
if (nbchars < 0) {
fprintf(stderr, "xmlOutputBufferWrite: encoder error\n");
return(-1);
}
}
/*
* second flush the stuff to the I/O channel
*/
if ((out->conv != NULL) && (out->encoder != NULL)) {
ret = out->writecallback(out->context,
(const char *)out->conv->content, out->conv->use);
if (ret >= 0)
xmlBufferShrink(out->conv, ret);
} else {
ret = out->writecallback(out->context,
(const char *)out->buffer->content, out->buffer->use);
if (ret >= 0)
xmlBufferShrink(out->buffer, ret);
}
if (ret < 0) {
fprintf(stderr, "I/O: error %d flushing %d bytes\n", ret, nbchars);
return(ret);
}
out->written += ret;
#ifdef DEBUG_INPUT
fprintf(stderr, "I/O: flushed %d chars\n", ret);
#endif
return(ret);
}
/*