diff --git a/error.c b/error.c index cf03bac2..6d31a6bf 100644 --- a/error.c +++ b/error.c @@ -16,62 +16,163 @@ #include #include "private/error.h" +#include "private/string.h" -#ifndef va_copy - #ifdef __va_copy - #define va_copy(dest, src) __va_copy(dest, src) - #else - #define va_copy(dest, src) memcpy(dest, src, sizeof(va_list)) - #endif -#endif +/************************************************************************ + * * + * Error struct * + * * + ************************************************************************/ -#define XML_GET_VAR_STR(msg, str) \ - do { \ - va_list ap; \ - va_start(ap, msg); \ - str = xmlVsnprintf(msg, ap); \ - va_end(ap); \ - } while (0); +static int +xmlVSetError(xmlError *err, + void *ctxt, xmlNodePtr node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, + const char *str1, const char *str2, const char *str3, + int int1, int col, + const char *fmt, va_list ap) +{ + char *message = NULL; + char *fileCopy = NULL; + char *str1Copy = NULL; + char *str2Copy = NULL; + char *str3Copy = NULL; -static char * -xmlVsnprintf(const char *msg, va_list ap) { - int size, prev_size = -1; - int chars; - char *larger; - char *str; - - str = (char *) xmlMalloc(150); - if (str == NULL) - return(NULL); - - size = 150; - - while (size < 64000) { - va_list copy; - - va_copy(copy, ap); - chars = vsnprintf(str, size, msg, copy); - va_end(copy); - if ((chars > -1) && (chars < size)) { - if (prev_size == chars) { - break; - } else { - prev_size = chars; - } - } - if (chars > -1) - size += chars + 1; - else - size += 100; - larger = (char *) xmlRealloc(str, size); - if (larger == NULL) { - xmlFree(str); - return(NULL); - } - str = larger; + if (code == XML_ERR_OK) { + xmlResetError(err); + return(0); } - return(str); + /* + * Formatting the message + */ + if (fmt == NULL) { + message = xmlMemStrdup("No error message provided"); + } else { + xmlChar *tmp; + int res; + + res = xmlStrVASPrintf(&tmp, MAX_ERR_MSG_SIZE, fmt, ap); + if (res < 0) + goto err_memory; + message = (char *) tmp; + } + if (message == NULL) + goto err_memory; + + if (file != NULL) { + fileCopy = (char *) xmlStrdup((const xmlChar *) file); + if (fileCopy == NULL) + goto err_memory; + } + if (str1 != NULL) { + str1Copy = (char *) xmlStrdup((const xmlChar *) str1); + if (str1Copy == NULL) + goto err_memory; + } + if (str2 != NULL) { + str2Copy = (char *) xmlStrdup((const xmlChar *) str2); + if (str2Copy == NULL) + goto err_memory; + } + if (str3 != NULL) { + str3Copy = (char *) xmlStrdup((const xmlChar *) str3); + if (str3Copy == NULL) + goto err_memory; + } + + xmlResetError(err); + + err->domain = domain; + err->code = code; + err->message = message; + err->level = level; + err->file = fileCopy; + err->line = line; + err->str1 = str1Copy; + err->str2 = str2Copy; + err->str3 = str3Copy; + err->int1 = int1; + err->int2 = col; + err->node = node; + err->ctxt = ctxt; + + return(0); + +err_memory: + xmlFree(message); + xmlFree(fileCopy); + xmlFree(str1Copy); + xmlFree(str2Copy); + xmlFree(str3Copy); + return(-1); +} + +static int LIBXML_ATTR_FORMAT(14,15) +xmlSetError(xmlError *err, + void *ctxt, xmlNodePtr node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, + const char *str1, const char *str2, const char *str3, + int int1, int col, + const char *fmt, ...) +{ + va_list ap; + int res; + + va_start(ap, fmt); + res = xmlVSetError(err, ctxt, node, domain, code, level, file, line, + str1, str2, str3, int1, col, fmt, ap); + va_end(ap); + + return(res); +} + +static int +xmlVUpdateError(xmlError *err, + void *ctxt, xmlNodePtr node, + int domain, int code, xmlErrorLevel level, + const char *file, int line, + const char *str1, const char *str2, const char *str3, + int int1, int col, + const char *fmt, va_list ap) +{ + int res; + + /* + * Find first element parent. + */ + if (node != NULL) { + int i; + + for (i = 0; i < 10; i++) { + if ((node->type == XML_ELEMENT_NODE) || + (node->parent == NULL)) + break; + node = node->parent; + } + } + + /* + * Get file and line from node. + */ + if (node != NULL) { + if ((file == NULL) && (node->doc != NULL)) + file = (const char *) node->doc->URL; + + if (line == 0) { + if (node->type == XML_ELEMENT_NODE) + line = node->line; + if ((line == 0) || (line == 65535)) + line = xmlGetLineNo(node); + } + } + + res = xmlVSetError(err, ctxt, node, domain, code, level, file, line, + str1, str2, str3, int1, col, fmt, ap); + + return(res); } /************************************************************************ @@ -278,12 +379,14 @@ xmlParserPrintFileContext(xmlParserInputPtr input) { * routines. */ static void -xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, - xmlGenericErrorFunc channel, void *data) +xmlReportError(xmlParserCtxtPtr ctxt, const xmlError *err) { - char *file = NULL; - int line = 0; - int code = -1; + xmlGenericErrorFunc channel; + void *data; + const char *message; + const char *file; + int line; + int code; int domain; const xmlChar *name = NULL; xmlNodePtr node; @@ -291,13 +394,16 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, xmlParserInputPtr input = NULL; xmlParserInputPtr cur = NULL; - if (err == NULL) - return; - - if (channel == NULL) { - channel = xmlGenericError; - data = xmlGenericErrorContext; + if (err == NULL) { + if (ctxt == NULL) + return; + err = &ctxt->lastError; } + + channel = xmlGenericError; + data = xmlGenericErrorContext; + + message = err->message; file = err->file; line = err->line; code = err->code; @@ -425,15 +531,15 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, channel(data, "error : "); break; } - if (str != NULL) { + if (message != NULL) { int len; - len = xmlStrlen((const xmlChar *)str); - if ((len > 0) && (str[len - 1] != '\n')) - channel(data, "%s\n", str); + len = xmlStrlen((const xmlChar *) message); + if ((len > 0) && (message[len - 1] != '\n')) + channel(data, "%s\n", message); else - channel(data, "%s", str); + channel(data, "%s", message); } else { - channel(data, "%s\n", "out of memory error"); + channel(data, "%s\n", "No error message provided"); } if (ctxt != NULL) { @@ -461,6 +567,47 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, } } +/** + * xmlRaiseMemoryError: + * @schannel: the structured callback channel + * @channel: the old callback channel + * @data: the callback data + * @domain: the domain for the error + * @error: optional error struct to be filled + * + * Update the global and optional error structure, then forward the + * error to an error handler. + * + * This function doesn't make memory allocations which are likely + * to fail after an OOM error. + */ +void +xmlRaiseMemoryError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, int domain, xmlError *error) +{ + xmlError *lastError = &xmlLastError; + + xmlResetLastError(); + lastError->domain = domain; + lastError->code = XML_ERR_NO_MEMORY; + lastError->level = XML_ERR_FATAL; + + if (error != NULL) { + xmlResetError(error); + error->domain = domain; + error->code = XML_ERR_NO_MEMORY; + error->level = XML_ERR_FATAL; + } + + if (schannel != NULL) { + schannel(data, lastError); + } else if (xmlStructuredError != NULL) { + xmlStructuredError(xmlStructuredErrorContext, lastError); + } else if (channel != NULL) { + channel(data, "libxml2: out of memory\n"); + } +} + /** * xmlVRaiseError: * @schannel: the structured callback channel @@ -490,197 +637,50 @@ xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str, int xmlVRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, void *data, void *ctx, - void *nod, int domain, int code, xmlErrorLevel level, + xmlNode *node, int domain, int code, xmlErrorLevel level, const char *file, int line, const char *str1, const char *str2, const char *str3, int int1, int col, const char *msg, va_list ap) { xmlParserCtxtPtr ctxt = NULL; - xmlNodePtr node = (xmlNodePtr) nod; - char *str = NULL; /* xmlLastError is a macro retrieving the per-thread global. */ xmlErrorPtr lastError = &xmlLastError; xmlErrorPtr to = lastError; - xmlNodePtr baseptr = NULL; if (code == XML_ERR_OK) return(0); if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING)) return(0); + if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) || (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) || (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) { ctxt = (xmlParserCtxtPtr) ctx; - } - /* - * Check if structured error handler set - */ - if (schannel == NULL) { - schannel = xmlStructuredError; - /* - * if user has defined handler, change data ptr to user's choice - */ - if (schannel != NULL) - data = xmlStructuredErrorContext; - } - /* - * Formatting the message - */ - if (msg == NULL) { - str = (char *) xmlStrdup(BAD_CAST "No error message provided"); - } else { - str = xmlVsnprintf(msg, ap); - } - if (str == NULL) - goto err_memory; - /* - * specific processing if a parser context is provided - */ - if (ctxt != NULL) - to = &ctxt->lastError; - - if ((node != NULL) && (file == NULL)) { - int i; - - if ((node->doc != NULL) && (node->doc->URL != NULL)) { - baseptr = node; -/* file = (const char *) node->doc->URL; */ - } - for (i = 0; - ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE)); - i++) - node = node->parent; - if ((baseptr == NULL) && (node != NULL) && - (node->doc != NULL) && (node->doc->URL != NULL)) - baseptr = node; - - if ((node != NULL) && (node->type == XML_ELEMENT_NODE)) - line = node->line; - if ((line == 0) || (line == 65535)) - line = xmlGetLineNo(node); + if (ctxt != NULL) + to = &ctxt->lastError; } - /* - * Save the information about the error - */ - xmlResetError(to); - to->domain = domain; - to->code = code; - to->message = str; - to->level = level; - if (file != NULL) { - to->file = (char *) xmlStrdup((const xmlChar *) file); - if (to->file == NULL) - goto err_memory; - } - else if (baseptr != NULL) { -#ifdef LIBXML_XINCLUDE_ENABLED - /* - * We check if the error is within an XInclude section and, - * if so, attempt to print out the href of the XInclude instead - * of the usual "base" (doc->URL) for the node (bug 152623). - */ - xmlNodePtr prev = baseptr; - xmlChar *href = NULL; - int inclcount = 0; - while (prev != NULL) { - if (prev->prev == NULL) - prev = prev->parent; - else { - prev = prev->prev; - if (prev->type == XML_XINCLUDE_START) { - if (inclcount > 0) { - --inclcount; - } else { - if (xmlNodeGetAttrValue(prev, BAD_CAST "href", NULL, - &href) < 0) - goto err_memory; - if (href != NULL) - break; - } - } else if (prev->type == XML_XINCLUDE_END) - inclcount++; - } - } - if (href != NULL) { - to->file = (char *) href; - } else -#endif - if (baseptr->doc->URL != NULL) { - to->file = (char *) xmlStrdup(baseptr->doc->URL); - if (to->file == NULL) - goto err_memory; - } - } - to->line = line; - if (str1 != NULL) { - to->str1 = (char *) xmlStrdup((const xmlChar *) str1); - if (to->str1 == NULL) - goto err_memory; - } - if (str2 != NULL) { - to->str2 = (char *) xmlStrdup((const xmlChar *) str2); - if (to->str2 == NULL) - goto err_memory; - } - if (str3 != NULL) { - to->str3 = (char *) xmlStrdup((const xmlChar *) str3); - if (to->str3 == NULL) - goto err_memory; - } - to->int1 = int1; - to->int2 = col; - to->node = node; - to->ctxt = ctx; + if (xmlVUpdateError(to, ctxt, node, domain, code, level, file, line, + str1, str2, str3, int1, col, msg, ap)) + return(-1); if (to != lastError) { if (xmlCopyError(to, lastError) < 0) - goto err_memory; + return(-1); } if (schannel != NULL) { schannel(data, to); - return(0); + } else if (xmlStructuredError != NULL) { + xmlStructuredError(xmlStructuredErrorContext, to); + } else if ((ctxt == NULL) && (channel == NULL)) { + xmlGenericError(xmlGenericErrorContext, "%s", to->message); + } else if (channel != NULL) { + channel(data, "%s", to->message); } - /* - * Find the callback channel if channel param is NULL - */ - if ((ctxt == NULL) && (channel == NULL)) { - channel = xmlGenericError; - data = xmlGenericErrorContext; - } - if (channel == NULL) - return(0); - - if ((channel == xmlParserError) || - (channel == xmlParserWarning) || - (channel == xmlParserValidityError) || - (channel == xmlParserValidityWarning)) - xmlReportError(to, ctxt, str, NULL, NULL); - else if (((void(*)(void)) channel == (void(*)(void)) fprintf) || - (channel == xmlGenericErrorDefaultFunc)) - xmlReportError(to, ctxt, str, channel, data); - else - channel(data, "%s", str); - return(0); - -err_memory: - xmlResetError(to); - to->domain = domain; - to->code = XML_ERR_NO_MEMORY; - to->level = XML_ERR_FATAL; - - if (to != lastError) { - xmlResetError(lastError); - lastError->domain = domain; - lastError->code = XML_ERR_NO_MEMORY; - lastError->level = XML_ERR_FATAL; - } - - return(-1); } /** @@ -712,7 +712,7 @@ err_memory: int __xmlRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, void *data, void *ctx, - void *nod, int domain, int code, xmlErrorLevel level, + xmlNode *node, int domain, int code, xmlErrorLevel level, const char *file, int line, const char *str1, const char *str2, const char *str3, int int1, int col, const char *msg, ...) @@ -721,7 +721,7 @@ __xmlRaiseError(xmlStructuredErrorFunc schannel, int res; va_start(ap, msg); - res = xmlVRaiseError(schannel, channel, data, ctx, nod, domain, code, + res = xmlVRaiseError(schannel, channel, data, ctx, node, domain, code, level, file, line, str1, str2, str3, int1, col, msg, ap); va_end(ap); @@ -769,37 +769,9 @@ __xmlSimpleError(int domain, int code, xmlNodePtr node, * extra parameters. */ void -xmlParserError(void *ctx, const char *msg, ...) +xmlParserError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr input = NULL; - xmlParserInputPtr cur = NULL; - char * str; - - if (ctxt != NULL) { - input = ctxt->input; - if ((input != NULL) && (input->filename == NULL) && - (ctxt->inputNr > 1)) { - cur = input; - input = ctxt->inputTab[ctxt->inputNr - 2]; - } - xmlParserPrintFileInfo(input); - } - - xmlGenericError(xmlGenericErrorContext, "error: "); - XML_GET_VAR_STR(msg, str); - xmlGenericError(xmlGenericErrorContext, "%s", str); - if (str != NULL) - xmlFree(str); - - if (ctxt != NULL) { - xmlParserPrintFileContext(input); - if (cur != NULL) { - xmlParserPrintFileInfo(cur); - xmlGenericError(xmlGenericErrorContext, "\n"); - xmlParserPrintFileContext(cur); - } - } + xmlReportError(ctx, NULL); } /** @@ -812,45 +784,11 @@ xmlParserError(void *ctx, const char *msg, ...) * extra parameters. */ void -xmlParserWarning(void *ctx, const char *msg, ...) +xmlParserWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr input = NULL; - xmlParserInputPtr cur = NULL; - char * str; - - if (ctxt != NULL) { - input = ctxt->input; - if ((input != NULL) && (input->filename == NULL) && - (ctxt->inputNr > 1)) { - cur = input; - input = ctxt->inputTab[ctxt->inputNr - 2]; - } - xmlParserPrintFileInfo(input); - } - - xmlGenericError(xmlGenericErrorContext, "warning: "); - XML_GET_VAR_STR(msg, str); - xmlGenericError(xmlGenericErrorContext, "%s", str); - if (str != NULL) - xmlFree(str); - - if (ctxt != NULL) { - xmlParserPrintFileContext(input); - if (cur != NULL) { - xmlParserPrintFileInfo(cur); - xmlGenericError(xmlGenericErrorContext, "\n"); - xmlParserPrintFileContext(cur); - } - } + xmlReportError(ctx, NULL); } -/************************************************************************ - * * - * Handling of validation errors * - * * - ************************************************************************/ - /** * xmlParserValidityError: * @ctx: an XML parser context @@ -861,38 +799,9 @@ xmlParserWarning(void *ctx, const char *msg, ...) * line, position and extra parameters. */ void -xmlParserValidityError(void *ctx, const char *msg, ...) +xmlParserValidityError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr input = NULL; - char * str; - int len = xmlStrlen((const xmlChar *) msg); - static int had_info = 0; - - if ((len > 1) && (msg[len - 2] != ':')) { - if (ctxt != NULL) { - input = ctxt->input; - if ((input->filename == NULL) && (ctxt->inputNr > 1)) - input = ctxt->inputTab[ctxt->inputNr - 2]; - - if (had_info == 0) { - xmlParserPrintFileInfo(input); - } - } - xmlGenericError(xmlGenericErrorContext, "validity error: "); - had_info = 0; - } else { - had_info = 1; - } - - XML_GET_VAR_STR(msg, str); - xmlGenericError(xmlGenericErrorContext, "%s", str); - if (str != NULL) - xmlFree(str); - - if ((ctxt != NULL) && (input != NULL)) { - xmlParserPrintFileContext(input); - } + xmlReportError(ctx, NULL); } /** @@ -905,30 +814,9 @@ xmlParserValidityError(void *ctx, const char *msg, ...) * position and extra parameters. */ void -xmlParserValidityWarning(void *ctx, const char *msg, ...) +xmlParserValidityWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { - xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; - xmlParserInputPtr input = NULL; - char * str; - int len = xmlStrlen((const xmlChar *) msg); - - if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) { - input = ctxt->input; - if ((input->filename == NULL) && (ctxt->inputNr > 1)) - input = ctxt->inputTab[ctxt->inputNr - 2]; - - xmlParserPrintFileInfo(input); - } - - xmlGenericError(xmlGenericErrorContext, "validity warning: "); - XML_GET_VAR_STR(msg, str); - xmlGenericError(xmlGenericErrorContext, "%s", str); - if (str != NULL) - xmlFree(str); - - if (ctxt != NULL) { - xmlParserPrintFileContext(input); - } + xmlReportError(ctx, NULL); } @@ -1046,75 +934,19 @@ xmlCtxtResetLastError(void *ctx) */ int xmlCopyError(const xmlError *from, xmlErrorPtr to) { - char *message = NULL; - char *file = NULL; - char *str1 = NULL; - char *str2 = NULL; - char *str3 = NULL; + const char *fmt = NULL; if ((from == NULL) || (to == NULL)) return(-1); - if (from->message != NULL) { - message = (char *) xmlStrdup((xmlChar *) from->message); - if (message == NULL) - goto err_memory; - } - if (from->file != NULL) { - file = (char *) xmlStrdup ((xmlChar *) from->file); - if (file == NULL) - goto err_memory; - } - if (from->str1 != NULL) { - str1 = (char *) xmlStrdup ((xmlChar *) from->str1); - if (str1 == NULL) - goto err_memory; - } - if (from->str2 != NULL) { - str2 = (char *) xmlStrdup ((xmlChar *) from->str2); - if (str2 == NULL) - goto err_memory; - } - if (from->str3 != NULL) { - str3 = (char *) xmlStrdup ((xmlChar *) from->str3); - if (str3 == NULL) - goto err_memory; - } + if (from->message != NULL) + fmt = "%s"; - if (to->message != NULL) - xmlFree(to->message); - if (to->file != NULL) - xmlFree(to->file); - if (to->str1 != NULL) - xmlFree(to->str1); - if (to->str2 != NULL) - xmlFree(to->str2); - if (to->str3 != NULL) - xmlFree(to->str3); - to->domain = from->domain; - to->code = from->code; - to->level = from->level; - to->line = from->line; - to->node = from->node; - to->int1 = from->int1; - to->int2 = from->int2; - to->node = from->node; - to->ctxt = from->ctxt; - to->message = message; - to->file = file; - to->str1 = str1; - to->str2 = str2; - to->str3 = str3; - - return 0; - -err_memory: - xmlFree(message); - xmlFree(file); - xmlFree(str1); - xmlFree(str2); - xmlFree(str3); - - return -1; + return(xmlSetError(to, from->ctxt, from->node, + from->domain, from->code, from->level, + from->file, from->line, + from->str1, from->str2, from->str3, + from->int1, from->int2, + fmt, from->message)); } diff --git a/include/private/error.h b/include/private/error.h index d3d2665c..2c78c07c 100644 --- a/include/private/error.h +++ b/include/private/error.h @@ -4,19 +4,24 @@ #include #include +#define MAX_ERR_MSG_SIZE 64000 + struct _xmlNode; +XML_HIDDEN void +xmlRaiseMemoryError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, int domain, xmlError *error); XML_HIDDEN int -xmlVRaiseError(xmlStructuredErrorFunc schannel, - xmlGenericErrorFunc channel, void *data, void *ctx, - void *nod, int domain, int code, xmlErrorLevel level, +xmlVRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, void *ctx, struct _xmlNode *node, + int domain, int code, xmlErrorLevel level, const char *file, int line, const char *str1, const char *str2, const char *str3, int int1, int col, const char *msg, va_list ap); XML_HIDDEN int -__xmlRaiseError(xmlStructuredErrorFunc schannel, - xmlGenericErrorFunc channel, void *data, void *ctx, - void *nod, int domain, int code, xmlErrorLevel level, +__xmlRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, + void *data, void *ctx, struct _xmlNode *node, + int domain, int code, xmlErrorLevel level, const char *file, int line, const char *str1, const char *str2, const char *str3, int int1, int col, const char *msg, ...) LIBXML_ATTR_FORMAT(16,17); diff --git a/include/private/string.h b/include/private/string.h index 9665fc47..34f4c96c 100644 --- a/include/private/string.h +++ b/include/private/string.h @@ -3,6 +3,10 @@ #include +XML_HIDDEN int +xmlStrVASPrintf(xmlChar **out, int maxSize, const char *msg, va_list ap); +XML_HIDDEN int +xmlStrASPrintf(xmlChar **out, int maxSize, const char *msg, ...); XML_HIDDEN xmlChar * xmlEscapeFormatString(xmlChar **msg); diff --git a/python/tests/input_callback.py b/python/tests/input_callback.py index ad8cf3ba..f1663010 100755 --- a/python/tests/input_callback.py +++ b/python/tests/input_callback.py @@ -99,7 +99,7 @@ libxml2.registerInputCallback(my_input_cb) run_test(desc="Loading entity with custom callback", docpath=startURL, catalog=None, exp_status="loaded", exp_err=[ - (-1, "Attempt to load network entity http://example.com/dtds/sample.dtd"), + ( 3, "Attempt to load network entity http://example.com/dtds/sample.dtd"), ( 4, "Entity 'sample.entity' not defined\n") ]) diff --git a/xmlIO.c b/xmlIO.c index db4039e3..c3a4409a 100644 --- a/xmlIO.c +++ b/xmlIO.c @@ -154,7 +154,7 @@ static const char* const IOerr[] = { "No such process", /* ESRCH */ "Operation timed out", /* ETIMEDOUT */ "Improper link", /* EXDEV */ - "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */ + "Attempt to load network entity", /* XML_IO_NETWORK_ATTEMPT */ "encoder error", /* XML_IO_ENCODER */ "flush error", "write error", @@ -4053,7 +4053,8 @@ xmlNoNetExternalEntityLoader(const char *URL, const char *ID, if (resource != NULL) { if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) || (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) { - xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource); + xmlLoaderErr(ctxt, "Attempt to load network entity %s", + (const char *) resource); if (resource != (xmlChar *) URL) xmlFree(resource); return(NULL); diff --git a/xmlstring.c b/xmlstring.c index 5155955d..e30c084a 100644 --- a/xmlstring.c +++ b/xmlstring.c @@ -26,6 +26,14 @@ #include "private/parser.h" #include "private/string.h" +#ifndef va_copy + #ifdef __va_copy + #define va_copy(dest, src) __va_copy(dest, src) + #else + #define va_copy(dest, src) memcpy(dest, src, sizeof(va_list)) + #endif +#endif + /************************************************************************ * * * Commodity functions to handle xmlChars * @@ -585,6 +593,148 @@ xmlStrVPrintf(xmlChar *buf, int len, const char *msg, va_list ap) { return(ret); } +/** + * xmlStrVASPrintf: + * @out: pointer to the resulting string + * @maxSize: maximum size of the output buffer + * @fmt: printf format string + * @ap: arguments for format string + * + * Creates a newly allocated string according to format. + * + * Returns 0 on success, 1 if the result was truncated or on other + * errors, -1 if a memory allocation failed. + */ +int +xmlStrVASPrintf(xmlChar **out, int maxSize, const char *msg, va_list ap) { + char empty[1]; + va_list copy; + xmlChar *buf; + int res, size; + int truncated = 0; + + if (out == NULL) + return(1); + *out = NULL; + if (msg == NULL) + return(1); + if (maxSize < 32) + maxSize = 32; + + va_copy(copy, ap); + res = vsnprintf(empty, 1, msg, copy); + va_end(copy); + + if (res > 0) { + /* snprintf seems to work according to C99. */ + + if (res < maxSize) { + size = res + 1; + } else { + size = maxSize; + truncated = 1; + } + buf = xmlMalloc(size); + if (buf == NULL) + return(-1); + if (vsnprintf((char *) buf, size, msg, ap) < 0) { + xmlFree(buf); + return(1); + } + } else { + /* + * Unfortunately, older snprintf implementations don't follow the + * C99 spec. If the output exceeds the size of the buffer, they can + * return -1, 0 or the number of characters written instead of the + * needed size. Older MSCVRT also won't write a terminating null + * byte if the buffer is too small. + * + * If the value returned is non-negative and strictly less than + * the buffer size (without terminating null), the result should + * have been written completely, so we double the buffer size + * until this condition is true. This assumes that snprintf will + * eventually return a non-negative value. Otherwise, we will + * allocate more and more memory until we run out. + * + * Note that this code path is also executed on conforming + * platforms if the output is the empty string. + */ + + buf = NULL; + size = 32; + while (1) { + buf = xmlMalloc(size); + if (buf == NULL) + return(-1); + + va_copy(copy, ap); + res = vsnprintf((char *) buf, size, msg, copy); + va_end(copy); + if ((res >= 0) && (res < size - 1)) + break; + + if (size >= maxSize) { + truncated = 1; + break; + } + + xmlFree(buf); + + if (size > maxSize / 2) + size = maxSize; + else + size *= 2; + } + } + + /* + * If the output was truncated, make sure that the buffer doesn't + * end with a truncated UTF-8 sequence. + */ + if (truncated != 0) { + int i = size - 1; + + while (i > 0) { + /* Break after ASCII */ + if (buf[i-1] < 0x80) + break; + i -= 1; + /* Break before non-ASCII */ + if (buf[i] >= 0xc0) + break; + } + + buf[i] = 0; + } + + *out = (xmlChar *) buf; + return(truncated); +} + +/** + * xmlStrASPrintf: + * @out: pointer to the resulting string + * @maxSize: maximum size of the output buffer + * @fmt: printf format string + * @ap: arguments for format string + * + * See xmlStrVASPrintf. + * + * Returns 0 on success, 1 if the result was truncated or on other + * errors, -1 if a memory allocation failed. + */ +int +xmlStrASPrintf(xmlChar **out, int maxSize, const char *msg, ...) { + va_list ap; + int ret; + + va_start(ap, msg); + ret = xmlStrVASPrintf(out, maxSize, msg, ap); + va_end(ap); + + return(ret); +} + /************************************************************************ * * * Generic UTF8 handling routines *