diff options
Diffstat (limited to 'xmlIO.c')
-rw-r--r-- | xmlIO.c | 233 |
1 files changed, 221 insertions, 12 deletions
@@ -475,6 +475,32 @@ xmlCleanupInputCallbacks(void) xmlInputCallbackInitialized = 0; } +/** + * xmlPopInputCallback: + * + * Clear the top input callback from the input stack. this includes the + * compiled-in I/O. + * + * Returns the number of input callback registered or -1 in case of error. + */ +int +xmlPopInputCallbacks(void) +{ + if (!xmlInputCallbackInitialized) + return(-1); + + if (xmlInputCallbackNr <= 0) + return(-1); + + xmlInputCallbackNr--; + xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL; + xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL; + xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL; + xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL; + + return(xmlInputCallbackNr); +} + #ifdef LIBXML_OUTPUT_ENABLED /** * xmlCleanupOutputCallbacks: @@ -2191,33 +2217,38 @@ xmlOutputBufferCreateFilename(const char *URI, xmlCharEncodingHandlerPtr encoder, int compression ATTRIBUTE_UNUSED) { xmlOutputBufferPtr ret; + xmlURIPtr puri; int i = 0; void *context = NULL; - char *unescaped; - - int is_http_uri = 0; /* Can't change if HTTP disabled */ + char *unescaped = NULL; + int is_file_uri = 1; if (xmlOutputCallbackInitialized == 0) xmlRegisterDefaultOutputCallbacks(); if (URI == NULL) return(NULL); -#ifdef LIBXML_HTTP_ENABLED - /* Need to prevent HTTP URI's from falling into zlib short circuit */ - - is_http_uri = xmlIOHTTPMatch( URI ); -#endif - + puri = xmlParseURI(URI); + if (puri != NULL) { + if ((puri->scheme != NULL) && + (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file"))) + is_file_uri = 0; + /* + * try to limit the damages of the URI unescaping code. + */ + if (puri->scheme != NULL) + unescaped = xmlURIUnescapeString(URI, 0, NULL); + xmlFreeURI(puri); + } /* * Try to find one of the output accept method accepting that scheme * Go in reverse to give precedence to user defined handlers. * try with an unescaped version of the URI */ - unescaped = xmlURIUnescapeString(URI, 0, NULL); if (unescaped != NULL) { #ifdef HAVE_ZLIB_H - if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) { + if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { context = xmlGzfileOpenW(unescaped, compression); if (context != NULL) { ret = xmlAllocOutputBuffer(encoder); @@ -2254,7 +2285,7 @@ xmlOutputBufferCreateFilename(const char *URI, */ if (context == NULL) { #ifdef HAVE_ZLIB_H - if ((compression > 0) && (compression <= 9) && (is_http_uri == 0)) { + if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) { context = xmlGzfileOpenW(URI, compression); if (context != NULL) { ret = xmlAllocOutputBuffer(encoder); @@ -2835,6 +2866,184 @@ done: } /** + * xmlEscapeContent: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @in: a pointer to an array of unescaped UTF-8 bytes + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and escape them. + * Returns 0 if success, or -1 otherwise + * The value of @inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + * The value of @outlen after return is the number of octets consumed. + */ +static int +xmlEscapeContent(unsigned char* out, int *outlen, + const xmlChar* in, int *inlen) { + unsigned char* outstart = out; + const unsigned char* base = in; + unsigned char* outend = out + *outlen; + const unsigned char* inend; + + inend = in + (*inlen); + + while ((in < inend) && (out < outend)) { + if (*in == '<') { + if (outend - out < 4) break; + *out++ = '&'; + *out++ = 'l'; + *out++ = 't'; + *out++ = ';'; + } else if (*in == '>') { + if (outend - out < 4) break; + *out++ = '&'; + *out++ = 'g'; + *out++ = 't'; + *out++ = ';'; + } else if (*in == '&') { + if (outend - out < 5) break; + *out++ = '&'; + *out++ = 'a'; + *out++ = 'm'; + *out++ = 'p'; + *out++ = ';'; + } else if (*in == '\r') { + if (outend - out < 5) break; + *out++ = '&'; + *out++ = '#'; + *out++ = '1'; + *out++ = '3'; + *out++ = ';'; + } else { + *out++ = (unsigned char) *in; + } + ++in; + } + *outlen = out - outstart; + *inlen = in - base; + return(0); +} + +/** + * xmlOutputBufferWriteEscape: + * @out: a buffered parser output + * @str: a zero terminated UTF-8 string + * @escaping: an optional escaping function (or NULL) + * + * Write the content of the string in the output I/O buffer + * This routine escapes the caracters and then 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 +xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str, + xmlCharEncodingOutputFunc escaping) { + int nbchars = 0; /* number of chars to output to I/O */ + int ret; /* return from function call */ + int written = 0; /* number of char written to I/O so far */ + int chunk; /* number of byte currently processed from str */ + int len; /* number of bytes in str */ + int cons; /* byte from str consumed */ + + if ((out == NULL) || (out->error) || (str == NULL)) return(-1); + len = strlen((const char *)str); + if (len < 0) return(0); + if (out->error) return(-1); + if (escaping == NULL) escaping = xmlEscapeContent; + + do { + /* + * how many bytes to consume and how many bytes to store. + */ + cons = len; + chunk = (out->buffer->size - out->buffer->use) - 1; + + /* + * first handle encoding stuff. + */ + if (out->encoder != NULL) { + /* + * Store the data in the incoming raw buffer + */ + if (out->conv == NULL) { + out->conv = xmlBufferCreate(); + } + ret = escaping(out->buffer->content + out->buffer->use , + &chunk, str, &cons); + if (ret < 0) + return(-1); + out->buffer->use += chunk; + out->buffer->content[out->buffer->use] = 0; + + if ((out->buffer->use < MINLEN) && (cons == len)) + goto done; + + /* + * convert as much as possible to the output buffer. + */ + ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer); + if ((ret < 0) && (ret != -3)) { + xmlIOErr(XML_IO_ENCODER, NULL); + out->error = XML_IO_ENCODER; + return(-1); + } + nbchars = out->conv->use; + } else { + ret = escaping(out->buffer->content + out->buffer->use , + &chunk, str, &cons); + if (ret < 0) + return(-1); + out->buffer->use += chunk; + out->buffer->content[out->buffer->use] = 0; + nbchars = out->buffer->use; + } + str += cons; + len -= cons; + + if ((nbchars < MINLEN) && (len <= 0)) + goto done; + + if (out->writecallback) { + /* + * 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, ret); + } else { + ret = out->writecallback(out->context, + (const char *)out->buffer->content, nbchars); + if (ret >= 0) + xmlBufferShrink(out->buffer, ret); + } + if (ret < 0) { + xmlIOErr(XML_IO_WRITE, NULL); + out->error = XML_IO_WRITE; + return(ret); + } + out->written += ret; + } else if (out->buffer->size - out->buffer->use < MINLEN) { + xmlBufferResize(out->buffer, out->buffer->size + MINLEN); + } + written += nbchars; + } while (len > 0); + +done: +#ifdef DEBUG_INPUT + xmlGenericError(xmlGenericErrorContext, + "I/O: wrote %d chars\n", written); +#endif + return(written); +} + +/** * xmlOutputBufferWriteString: * @out: a buffered parser output * @str: a zero terminated C string |