/* * xmlIO.c : implementation of the I/O interfaces used by the parser * * See Copyright for the status of this software. * * Daniel.Veillard@w3.org */ #ifdef WIN32 #include "win32config.h" #else #include "config.h" #endif #include #include #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_ZLIB_H #include #endif #include #include #include #include #include #include /* #define VERBOSE_FAILURE */ /* #define DEBUG_EXTERNAL_ENTITIES */ /* #define DEBUG_INPUT */ #ifdef DEBUG_INPUT #define MINLEN 40 #else #define MINLEN 4000 #endif /* * Input I/O callback sets */ typedef struct _xmlInputCallback { xmlInputMatchCallback matchcallback; xmlInputOpenCallback opencallback; xmlInputReadCallback readcallback; xmlInputCloseCallback closecallback; } xmlInputCallback; #define MAX_INPUT_CALLBACK 15 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 * * * ************************************************************************/ /** * xmlFdMatch: * @filename: the URI for matching * * input from file descriptor * * Returns 1 if matches, 0 otherwise */ int xmlFdMatch (const char *filename) { return(1); } /** * xmlFdOpen: * @filename: the URI for matching * * input from file descriptor, supports compressed input * if @filename is " " then the standard input is used * * Returns an I/O context or NULL in case of error */ void * xmlFdOpen (const char *filename) { const char *path = NULL; int fd; if (!strcmp(filename, "-")) { fd = 0; 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); #ifdef WIN32 fd = _open (filename, O_RDONLY | _O_BINARY); #else fd = open (filename, O_RDONLY); #endif 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 read * * Read @len bytes to @buffer from the I/O channel. * * Returns the number of bytes written */ int 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 * * Close an I/O channel */ void xmlFdClose (void * context) { close((int) context); } /** * xmlFileMatch: * @filename: the URI for matching * * input from FILE * * * Returns 1 if matches, 0 otherwise */ int xmlFileMatch (const char *filename) { return(1); } /** * xmlFileOpen: * @filename: the URI for matching * * input from FILE *, supports compressed input * if @filename is " " then the standard input is used * * Returns an I/O context or NULL in case of error */ void * xmlFileOpen (const char *filename) { const char *path = NULL; FILE *fd; if (!strcmp(filename, "-")) { fd = stdin; 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); #ifdef WIN32 fd = fopen(path, "rb"); #else fd = fopen(path, "r"); #endif /* WIN32 */ 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 * @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 written */ int 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 * * Close an I/O channel */ void xmlFileClose (void * context) { fclose((FILE *) context); } #ifdef HAVE_ZLIB_H /************************************************************************ * * * I/O for compressed file accesses * * * ************************************************************************/ /** * xmlGzfileMatch: * @filename: the URI for matching * * input from compressed file test * * Returns 1 if matches, 0 otherwise */ int xmlGzfileMatch (const char *filename) { return(1); } /** * xmlGzfileOpen: * @filename: the URI for matching * * 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 * xmlGzfileOpen (const char *filename) { const char *path = NULL; gzFile fd; if (!strcmp(filename, "-")) { fd = gzdopen (fileno(stdin), "r"); 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, "r"); 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 * @buffer: where to drop data * @len: number of bytes to write * * Read @len bytes to @buffer from the compressed I/O channel. * * Returns the number of bytes written */ int 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 * * Close a compressed I/O channel */ void xmlGzfileClose (void * context) { gzclose((gzFile) context); } #endif /* HAVE_ZLIB_H */ #ifdef LIBXML_HTTP_ENABLED /************************************************************************ * * * I/O for HTTP file accesses * * * ************************************************************************/ /** * xmlIOHTTPMatch: * @filename: the URI for matching * * check if the URI matches an HTTP one * * Returns 1 if matches, 0 otherwise */ int xmlIOHTTPMatch (const char *filename) { if (!strncmp(filename, "http://", 7)) return(1); return(0); } /** * xmlIOHTTPOpen: * @filename: the URI for matching * * open an HTTP I/O channel * * Returns an I/O context or NULL in case of error */ void * xmlIOHTTPOpen (const char *filename) { return(xmlNanoHTTPOpen(filename, NULL)); } /** * xmlIOHTTPRead: * @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 written */ int xmlIOHTTPRead(void * context, char * buffer, int len) { return(xmlNanoHTTPRead(context, &buffer[0], len)); } /** * xmlIOHTTPClose: * @context: the I/O context * * Close an HTTP I/O channel */ void xmlIOHTTPClose (void * context) { xmlNanoHTTPClose(context); } #endif /* LIBXML_HTTP_ENABLED */ #ifdef LIBXML_FTP_ENABLED /************************************************************************ * * * I/O for FTP file accesses * * * ************************************************************************/ /** * xmlIOFTPMatch: * @filename: the URI for matching * * check if the URI matches an FTP one * * Returns 1 if matches, 0 otherwise */ int xmlIOFTPMatch (const char *filename) { if (!strncmp(filename, "ftp://", 6)) return(1); return(0); } /** * xmlIOFTPOpen: * @filename: the URI for matching * * open an FTP I/O channel * * Returns an I/O context or NULL in case of error */ void * xmlIOFTPOpen (const char *filename) { return(xmlNanoFTPOpen(filename)); } /** * xmlIOFTPRead: * @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 written */ int xmlIOFTPRead(void * context, char * buffer, int len) { return(xmlNanoFTPRead(context, &buffer[0], len)); } /** * xmlIOFTPClose: * @context: the I/O context * * Close an FTP I/O channel */ void xmlIOFTPClose (void * context) { xmlNanoFTPClose(context); } #endif /* LIBXML_FTP_ENABLED */ /** * xmlRegisterInputCallbacks: * @match: the xmlInputMatchCallback * @open: the xmlInputOpenCallback * @read: the xmlInputReadCallback * @close: the xmlInputCloseCallback * * Register a new set of I/O callback for handling parser input. * * Returns the registered handler number or -1 in case of error */ int xmlRegisterInputCallbacks(xmlInputMatchCallback match, xmlInputOpenCallback open, xmlInputReadCallback read, xmlInputCloseCallback close) { if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) { return(-1); } xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = match; xmlInputCallbackTable[xmlInputCallbackNr].opencallback = open; xmlInputCallbackTable[xmlInputCallbackNr].readcallback = read; xmlInputCallbackTable[xmlInputCallbackNr].closecallback = close; 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: * * Registers the default compiled-in I/O handlers. */ void xmlRegisterDefaultInputCallbacks(void) { xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen, xmlFileRead, xmlFileClose); #ifdef HAVE_ZLIB_H xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen, xmlGzfileRead, xmlGzfileClose); #endif /* HAVE_ZLIB_H */ #ifdef LIBXML_HTTP_ENABLED xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen, xmlIOHTTPRead, xmlIOHTTPClose); #endif /* LIBXML_HTTP_ENABLED */ #ifdef LIBXML_FTP_ENABLED xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen, xmlIOFTPRead, xmlIOFTPClose); #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 * * Create a buffered parser input for progressive parsing * * Returns the new parser input or NULL */ xmlParserInputBufferPtr xmlAllocParserInputBuffer(xmlCharEncoding enc) { xmlParserInputBufferPtr ret; ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer)); if (ret == NULL) { fprintf(stderr, "xmlAllocParserInputBuffer : out of memory!\n"); return(NULL); } memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer)); ret->buffer = xmlBufferCreate(); if (ret->buffer == NULL) { xmlFree(ret); return(NULL); } ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT; ret->encoder = xmlGetCharEncodingHandler(enc); if (ret->encoder != NULL) ret->raw = xmlBufferCreate(); else ret->raw = NULL; ret->readcallback = NULL; ret->closecallback = NULL; ret->context = NULL; 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 * * Free up the memory used by a buffered parser input */ void xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) { if (in->raw) { xmlBufferFree(in->raw); in->raw = NULL; } if (in->encoder != NULL) { xmlCharEncCloseFunc(in->encoder); } if (in->closecallback != NULL) { in->closecallback(in->context); } if (in->buffer != NULL) { xmlBufferFree(in->buffer); in->buffer = NULL; } memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer)); 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 * @enc: the charset encoding if known * * Create a buffered parser input for the progressive parsing of a file * If filename is "-' then we use stdin as the input. * Automatic support for ZLIB/Compress compressed document is provided * by default if found at compile-time. * Do an encoding check if enc == XML_CHAR_ENCODING_NONE * * Returns the new parser input or NULL */ xmlParserInputBufferPtr xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) { xmlParserInputBufferPtr ret; int i; void *context = NULL; if (xmlInputCallbackInitialized == 0) xmlRegisterDefaultInputCallbacks(); if (URI == NULL) return(NULL); /* * Try to find one of the input accept method accepting taht scheme * Go in reverse to give precedence to user defined handlers. */ for (i = xmlInputCallbackNr - 1;i >= 0;i--) { if ((xmlInputCallbackTable[i].matchcallback != NULL) && (xmlInputCallbackTable[i].matchcallback(URI) != 0)) { context = xmlInputCallbackTable[i].opencallback(URI); if (context != NULL) break; } } if (context == NULL) { #ifdef DEBUG_INPUT fprintf(stderr, "No input filter matching \"%s\"\n", URI); #endif return(NULL); } /* * Allocate the Input buffer front-end. */ ret = xmlAllocParserInputBuffer(enc); if (ret != NULL) { ret->context = context; ret->readcallback = xmlInputCallbackTable[i].readcallback; ret->closecallback = xmlInputCallbackTable[i].closecallback; } 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* * @enc: the charset encoding if known * * Create a buffered parser input for the progressive parsing of a FILE * * buffered C I/O * * Returns the new parser input or NULL */ xmlParserInputBufferPtr xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) { xmlParserInputBufferPtr ret; if (xmlInputCallbackInitialized == 0) xmlRegisterDefaultInputCallbacks(); if (file == NULL) return(NULL); ret = xmlAllocParserInputBuffer(enc); if (ret != NULL) { ret->context = file; ret->readcallback = xmlFileRead; ret->closecallback = xmlFileClose; } 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 * @enc: the charset encoding if known * * Create a buffered parser input for the progressive parsing for the input * from a file descriptor * * Returns the new parser input or NULL */ xmlParserInputBufferPtr xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) { xmlParserInputBufferPtr ret; if (fd < 0) return(NULL); ret = xmlAllocParserInputBuffer(enc); if (ret != NULL) { ret->context = (void *) fd; ret->readcallback = xmlFdRead; ret->closecallback = xmlFdClose; } return(ret); } /** * xmlParserInputBufferCreateMem: * @mem: the memory input * @size: the length of the memory block * @enc: the charset encoding if known * * Create a buffered parser input for the progressive parsing for the input * from a file descriptor * * Returns the new parser input or NULL */ xmlParserInputBufferPtr xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) { xmlParserInputBufferPtr ret; if (size <= 0) return(NULL); if (mem == NULL) return(NULL); ret = xmlAllocParserInputBuffer(enc); if (ret != NULL) { ret->context = (void *) mem; ret->readcallback = NULL; ret->closecallback = NULL; xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size); } 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 * @ioclose: an I/O close function * @ioctx: an I/O handler * @enc: the charset encoding if known * * Create a buffered parser input for the progressive parsing for the input * from an I/O handler * * Returns the new parser input or NULL */ xmlParserInputBufferPtr xmlParserInputBufferCreateIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) { xmlParserInputBufferPtr ret; if (ioread == NULL) return(NULL); ret = xmlAllocParserInputBuffer(enc); if (ret != NULL) { ret->context = (void *) ioctx; ret->readcallback = ioread; ret->closecallback = ioclose; } 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 * @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 * This is used when operating the parser in progressive (push) mode. * * Returns the number of chars read and stored in the buffer, or -1 * in case of error. */ int xmlParserInputBufferPush(xmlParserInputBufferPtr in, int len, const char *buf) { int nbchars = 0; if (len < 0) return(0); if (in->encoder != NULL) { /* * Store the data in the incoming raw buffer */ if (in->raw == NULL) { in->raw = xmlBufferCreate(); } xmlBufferAdd(in->raw, (const xmlChar *) buf, len); /* * convert as much as possible to the parser reading buffer. */ nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw); if (nbchars < 0) { fprintf(stderr, "xmlParserInputBufferPush: encoder error\n"); return(-1); } } else { nbchars = len; xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars); } #ifdef DEBUG_INPUT fprintf(stderr, "I/O: pushed %d chars, buffer %d/%d\n", nbchars, in->buffer->use, in->buffer->size); #endif return(nbchars); } /** * xmlParserInputBufferGrow: * @in: a buffered parser input * @len: indicative value of the amount of chars to read * * Grow up the content of the input buffer, the old data are preserved * This routine handle the I18N transcoding to internal UTF-8 * This routine is used when operating the parser in normal (pull) mode * * TODO: one should be able to remove one extra copy by copying directy * onto in->buffer or in->raw * * Returns the number of chars read and stored in the buffer, or -1 * in case of error. */ int xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) { char *buffer = NULL; int res = 0; int nbchars = 0; int buffree; if ((len <= MINLEN) && (len != 4)) len = MINLEN; buffree = in->buffer->size - in->buffer->use; if (buffree <= 0) { fprintf(stderr, "xmlParserInputBufferGrow : buffer full !\n"); return(0); } if (len > buffree) len = buffree; buffer = (char *) xmlMalloc((len + 1) * sizeof(char)); if (buffer == NULL) { fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n"); return(-1); } /* * Call the read method for this I/O type. */ if (in->readcallback != NULL) { res = in->readcallback(in->context, &buffer[0], len); } else { fprintf(stderr, "xmlParserInputBufferGrow : no input !\n"); xmlFree(buffer); return(-1); } if (res < 0) { perror ("read error"); xmlFree(buffer); return(-1); } len = res; if (in->encoder != NULL) { /* * Store the data in the incoming raw buffer */ if (in->raw == NULL) { in->raw = xmlBufferCreate(); } xmlBufferAdd(in->raw, (const xmlChar *) buffer, len); /* * convert as much as possible to the parser reading buffer. */ nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw); if (nbchars < 0) { fprintf(stderr, "xmlParserInputBufferGrow: encoder error\n"); return(-1); } } else { nbchars = len; buffer[nbchars] = 0; xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars); } #ifdef DEBUG_INPUT fprintf(stderr, "I/O: read %d chars, buffer %d/%d\n", nbchars, in->buffer->use, in->buffer->size); #endif xmlFree(buffer); return(nbchars); } /** * xmlParserInputBufferRead: * @in: a buffered parser input * @len: indicative value of the amount of chars to read * * Refresh the content of the input buffer, the old data are considered * consumed * This routine handle the I18N transcoding to internal UTF-8 * * Returns the number of chars read and stored in the buffer, or -1 * in case of error. */ int xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) { /* xmlBufferEmpty(in->buffer); */ if (in->readcallback != NULL) return(xmlParserInputBufferGrow(in, len)); else 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); } /* * xmlParserGetDirectory: * @filename: the path to a file * * lookup the directory for that file * * Returns a new allocated string containing the directory, or NULL. */ char * xmlParserGetDirectory(const char *filename) { char *ret = NULL; char dir[1024]; char *cur; char sep = '/'; if (xmlInputCallbackInitialized == 0) xmlRegisterDefaultInputCallbacks(); if (filename == NULL) return(NULL); #ifdef WIN32 sep = '\\'; #endif strncpy(dir, filename, 1023); dir[1023] = 0; cur = &dir[strlen(dir)]; while (cur > dir) { if (*cur == sep) break; cur --; } if (*cur == sep) { if (cur == dir) dir[1] = 0; else *cur = 0; ret = xmlMemStrdup(dir); } else { if (getcwd(dir, 1024) != NULL) { dir[1023] = 0; ret = xmlMemStrdup(dir); } } return(ret); } /**************************************************************** * * * External entities loading * * * ****************************************************************/ /* * xmlDefaultExternalEntityLoader: * @URL: the URL for the entity to load * @ID: the System ID for the entity to load * @ctxt: the context in which the entity is called or NULL * * By default we don't load external entitites, yet. * * Returns a new allocated xmlParserInputPtr, or NULL. */ static xmlParserInputPtr xmlDefaultExternalEntityLoader(const char *URL, const char *ID, xmlParserCtxtPtr ctxt) { xmlParserInputPtr ret = NULL; #ifdef DEBUG_EXTERNAL_ENTITIES fprintf(stderr, "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL); #endif if (URL == NULL) { if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n", ID); return(NULL); } ret = xmlNewInputFromFile(ctxt, URL); if (ret == NULL) { if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n", URL); } return(ret); } static xmlExternalEntityLoader xmlCurrentExternalEntityLoader = xmlDefaultExternalEntityLoader; /* * xmlSetExternalEntityLoader: * @f: the new entity resolver function * * Changes the defaultexternal entity resolver function for the application */ void xmlSetExternalEntityLoader(xmlExternalEntityLoader f) { xmlCurrentExternalEntityLoader = f; } /* * xmlGetExternalEntityLoader: * * Get the default external entity resolver function for the application * * Returns the xmlExternalEntityLoader function pointer */ xmlExternalEntityLoader xmlGetExternalEntityLoader(void) { return(xmlCurrentExternalEntityLoader); } /* * xmlLoadExternalEntity: * @URL: the URL for the entity to load * @ID: the System ID for the entity to load * @ctxt: the context in which the entity is called or NULL * * Load an external entity, note that the use of this function for * unparsed entities may generate problems * TODO: a more generic External entitiy API must be designed * * Returns the xmlParserInputPtr or NULL */ xmlParserInputPtr xmlLoadExternalEntity(const char *URL, const char *ID, xmlParserCtxtPtr ctxt) { return(xmlCurrentExternalEntityLoader(URL, ID, ctxt)); }