/* * error.c: module displaying/handling XML parser errors * * See Copyright for the status of this software. * * Author: Daniel Veillard */ #define IN_LIBXML #include "libxml.h" #include #include #include #include #include #include #include "private/error.h" #include "private/globals.h" #include "private/string.h" /** * This currently comprises * * - OOM errors * - assertion failures * - invalid argument errors * - I/O errors * - unexpected errors from external libraries * * @param level error level * @param code error code * @returns true if an error is catastrophic. */ int xmlIsCatastrophicError(int level, int code) { int fatal = 0; if (level != XML_ERR_FATAL) return(0); switch (code) { case XML_ERR_NO_MEMORY: /* case XML_ERR_RESOURCE_LIMIT: */ case XML_ERR_SYSTEM: case XML_ERR_ARGUMENT: case XML_ERR_INTERNAL_ERROR: fatal = 1; break; default: if ((code >= 1500) && (code <= 1599)) fatal = 1; break; } return(fatal); } /************************************************************************ * * * Error struct * * * ************************************************************************/ 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; if (code == XML_ERR_OK) { xmlResetError(err); return(0); } /* * 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); } /************************************************************************ * * * Handling of out of context errors * * * ************************************************************************/ /** * Default handler for out-of-context error messages. * * @param ctx user data (unused) * @param msg printf-like format string * @param ... arguments to format */ void xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) { va_list args; if (xmlGenericErrorContext == NULL) xmlGenericErrorContext = (void *) stderr; va_start(args, msg); vfprintf((FILE *)xmlGenericErrorContext, msg, args); va_end(args); } /** * Set the thread-local "generic" handler and context for error * messages. * * @deprecated See #xmlSetStructuredErrorFunc for alternatives. * * The generic error handler will only receive fragments of * error messages which should be concatenated or printed to a * stream. * * If `handler` is NULL, use the built-in default handler which prints * to stderr. * * Since this is a thread-local setting, it's a good idea to reset * the error handler to its default value after collecting the * errors you're interested in. To get the original values, you * have to access xmlGenericError and xmlGenericErrorContext * directly, making this function kind of useless. * * For multi-threaded applications, this must be set separately for * each thread. * * @param ctx the new error handling context * @param handler the new handler function */ void xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) { xmlGenericErrorContext = ctx; if (handler != NULL) xmlGenericError = handler; else xmlGenericError = xmlGenericErrorDefaultFunc; } /** * Set the thread-local "structured" handler and context for error * messages. * * @deprecated Use a per-context error handler. * * It's recommended to use the per-context error handlers instead: * * - #xmlCtxtSetErrorHandler (since 2.13.0) * - #xmlTextReaderSetStructuredErrorHandler * - #xmlXPathSetErrorHandler (since 2.13.0) * - #xmlXIncludeSetErrorHandler (since 2.13.0) * - #xmlSchemaSetParserStructuredErrors * - #xmlSchemaSetValidStructuredErrors * - #xmlRelaxNGSetParserStructuredErrors * - #xmlRelaxNGSetValidStructuredErrors * * If `handler` is NULL, the error handler is deactivated. * * The structured error handler takes precedence over "generic" * handlers, even per-context generic handlers. * * Since this is a thread-local setting, it's a good idea to reset * the error handler to its default value after collecting the * errors you're interested in. To get the original values, you * have to access xmlStructuredError and xmlStructuredErrorContext * directly, making this function kind of useless. * * For multi-threaded applications, this must be set separately for * each thread. * * @param ctx the new error handling context * @param handler the new handler function */ void xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) { xmlStructuredErrorContext = ctx; xmlStructuredError = handler; } /************************************************************************ * * * Handling of parsing errors * * * ************************************************************************/ /** * Displays the associated file and line information for the * current input. * * @deprecated Use #xmlFormatError. * * @param input an xmlParserInput input */ void xmlParserPrintFileInfo(struct _xmlParserInput *input) { if (input != NULL) { if (input->filename) xmlGenericError(xmlGenericErrorContext, "%s:%d: ", input->filename, input->line); else xmlGenericError(xmlGenericErrorContext, "Entity: line %d: ", input->line); } } /** * Displays current context within the input content for * error reporting. * * @param input an xmlParserInput input * @param channel output callback * @param data user data for output callback */ static void xmlParserPrintFileContextInternal(xmlParserInputPtr input , xmlGenericErrorFunc channel, void *data ) { const xmlChar *cur, *base, *start; unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */ xmlChar content[81]; /* space for 80 chars + line terminator */ xmlChar *ctnt; if ((input == NULL) || (input->cur == NULL)) return; cur = input->cur; base = input->base; /* skip backwards over any end-of-lines */ while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) { cur--; } n = 0; /* search backwards for beginning-of-line (to max buff size) */ while ((n < sizeof(content) - 1) && (cur > base) && (*cur != '\n') && (*cur != '\r')) { cur--; n++; } if ((n > 0) && ((*cur == '\n') || (*cur == '\r'))) { cur++; } else { /* skip over continuation bytes */ while ((cur < input->cur) && ((*cur & 0xC0) == 0x80)) cur++; } /* calculate the error position in terms of the current position */ col = input->cur - cur; /* search forward for end-of-line (to max buff size) */ n = 0; start = cur; /* copy selected text to our buffer */ while ((*cur != 0) && (*(cur) != '\n') && (*(cur) != '\r')) { int len = input->end - cur; int c = xmlGetUTF8Char(cur, &len); if ((c < 0) || (n + len > sizeof(content)-1)) break; cur += len; n += len; } memcpy(content, start, n); content[n] = 0; /* print out the selected text */ channel(data ,"%s\n", content); /* create blank line with problem pointer */ n = 0; ctnt = content; /* (leave buffer space for pointer + line terminator) */ while ((nmessage; file = err->file; line = err->line; code = err->code; domain = err->domain; level = err->level; node = err->node; if (code == XML_ERR_OK) return; 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 = err->ctxt; } if ((node != NULL) && (node->type == XML_ELEMENT_NODE) && (domain != XML_FROM_SCHEMASV)) name = node->name; /* * Maintain the compatibility with the legacy error handling */ if ((ctxt != NULL) && (ctxt->input != NULL)) { input = ctxt->input; if ((input->filename == NULL) && (ctxt->inputNr > 1)) { cur = input; input = ctxt->inputTab[ctxt->inputNr - 2]; } if (input->filename) channel(data, "%s:%d: ", input->filename, input->line); else if ((line != 0) && (domain == XML_FROM_PARSER)) channel(data, "Entity: line %d: ", input->line); } else { if (file != NULL) channel(data, "%s:%d: ", file, line); else if ((line != 0) && ((domain == XML_FROM_PARSER) || (domain == XML_FROM_SCHEMASV)|| (domain == XML_FROM_SCHEMASP)||(domain == XML_FROM_DTD) || (domain == XML_FROM_RELAXNGP)||(domain == XML_FROM_RELAXNGV))) channel(data, "Entity: line %d: ", line); } if (name != NULL) { channel(data, "element %s: ", name); } switch (domain) { case XML_FROM_PARSER: channel(data, "parser "); break; case XML_FROM_NAMESPACE: channel(data, "namespace "); break; case XML_FROM_DTD: case XML_FROM_VALID: channel(data, "validity "); break; case XML_FROM_HTML: channel(data, "HTML parser "); break; case XML_FROM_MEMORY: channel(data, "memory "); break; case XML_FROM_OUTPUT: channel(data, "output "); break; case XML_FROM_IO: channel(data, "I/O "); break; case XML_FROM_XINCLUDE: channel(data, "XInclude "); break; case XML_FROM_XPATH: channel(data, "XPath "); break; case XML_FROM_XPOINTER: channel(data, "parser "); break; case XML_FROM_REGEXP: channel(data, "regexp "); break; case XML_FROM_MODULE: channel(data, "module "); break; case XML_FROM_SCHEMASV: channel(data, "Schemas validity "); break; case XML_FROM_SCHEMASP: channel(data, "Schemas parser "); break; case XML_FROM_RELAXNGP: channel(data, "Relax-NG parser "); break; case XML_FROM_RELAXNGV: channel(data, "Relax-NG validity "); break; case XML_FROM_CATALOG: channel(data, "Catalog "); break; case XML_FROM_C14N: channel(data, "C14N "); break; case XML_FROM_XSLT: channel(data, "XSLT "); break; case XML_FROM_I18N: channel(data, "encoding "); break; case XML_FROM_SCHEMATRONV: channel(data, "schematron "); break; case XML_FROM_BUFFER: channel(data, "internal buffer "); break; case XML_FROM_URI: channel(data, "URI "); break; default: break; } switch (level) { case XML_ERR_NONE: channel(data, ": "); break; case XML_ERR_WARNING: channel(data, "warning : "); break; case XML_ERR_ERROR: channel(data, "error : "); break; case XML_ERR_FATAL: channel(data, "error : "); break; } if (message != NULL) { int len; len = xmlStrlen((const xmlChar *) message); if ((len > 0) && (message[len - 1] != '\n')) channel(data, "%s\n", message); else channel(data, "%s", message); } else { channel(data, "%s\n", "No error message provided"); } if (ctxt != NULL) { if ((input != NULL) && ((input->buf == NULL) || (input->buf->encoder == NULL)) && (code == XML_ERR_INVALID_ENCODING) && (input->cur < input->end)) { int i; channel(data, "Bytes:"); for (i = 0; i < 4; i++) { if (input->cur + i >= input->end) break; channel(data, " 0x%02X", input->cur[i]); } channel(data, "\n"); } xmlParserPrintFileContextInternal(input, channel, data); if (cur != NULL) { if (cur->filename) channel(data, "%s:%d: \n", cur->filename, cur->line); else if ((line != 0) && ((domain == XML_FROM_PARSER) || (domain == XML_FROM_SCHEMASV) || (domain == XML_FROM_SCHEMASP) || (domain == XML_FROM_DTD) || (domain == XML_FROM_RELAXNGP) || (domain == XML_FROM_RELAXNGV))) channel(data, "Entity: line %d: \n", cur->line); xmlParserPrintFileContextInternal(cur, channel, data); } } if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) && (err->int1 < 100) && (err->int1 < xmlStrlen((const xmlChar *)err->str1))) { xmlChar buf[150]; int i; channel(data, "%s\n", err->str1); for (i=0;i < err->int1;i++) buf[i] = ' '; buf[i++] = '^'; buf[i] = 0; channel(data, "%s\n", buf); } } /** * 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. * * @param schannel the structured callback channel * @param channel the old callback channel * @param data the callback data * @param domain the domain for the error * @param error optional error struct to be filled */ void xmlRaiseMemoryError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, void *data, int domain, xmlError *error) { xmlError *lastError = xmlGetLastErrorInternal(); 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"); } } /** * Update the appropriate global or contextual error structure, * then forward the error message down the parser or generic * error callback handler * * @param schannel the structured callback channel * @param channel the old callback channel * @param data the callback data * @param ctx the parser context or NULL * @param node the current node or NULL * @param domain the domain for the error * @param code the code for the error * @param level the xmlErrorLevel for the error * @param file the file source of the error (or NULL) * @param line the line of the error or 0 if N/A * @param str1 extra string info * @param str2 extra string info * @param str3 extra string info * @param int1 extra int info * @param col column number of the error or 0 if N/A * @param msg the message to display/transmit * @param ap extra parameters for the message display * @returns 0 on success, -1 if a memory allocation failed. */ int xmlVRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, void *data, void *ctx, 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; /* xmlLastError is a macro retrieving the per-thread global. */ xmlErrorPtr lastError = xmlGetLastErrorInternal(); xmlErrorPtr to = lastError; if (code == XML_ERR_OK) return(0); #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if (code == XML_ERR_INTERNAL_ERROR) xmlAbort("Unexpected internal error: %s\n", msg); #endif 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; if (ctxt != NULL) to = &ctxt->lastError; } 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) return(-1); } if (schannel != NULL) { schannel(data, to); } else if (xmlStructuredError != NULL) { xmlStructuredError(xmlStructuredErrorContext, to); } else if (channel != NULL) { /* Don't invoke legacy error handlers */ if ((channel == xmlGenericErrorDefaultFunc) || (channel == xmlParserError) || (channel == xmlParserWarning) || (channel == xmlParserValidityError) || (channel == xmlParserValidityWarning)) xmlFormatError(to, xmlGenericError, xmlGenericErrorContext); else channel(data, "%s", to->message); } return(0); } /** * Update the appropriate global or contextual error structure, * then forward the error message down the parser or generic * error callback handler * * @param schannel the structured callback channel * @param channel the old callback channel * @param data the callback data * @param ctx the parser context or NULL * @param node the node or NULL * @param domain the domain for the error * @param code the code for the error * @param level the xmlErrorLevel for the error * @param file the file source of the error (or NULL) * @param line the line of the error or 0 if N/A * @param str1 extra string info * @param str2 extra string info * @param str3 extra string info * @param int1 extra int info * @param col column number of the error or 0 if N/A * @param msg printf-like format string * @param ... arguments to format * @returns 0 on success, -1 if a memory allocation failed. */ int xmlRaiseError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel, void *data, void *ctx, 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; int res; va_start(ap, msg); res = xmlVRaiseError(schannel, channel, data, ctx, node, domain, code, level, file, line, str1, str2, str3, int1, col, msg, ap); va_end(ap); return(res); } static void xmlVFormatLegacyError(void *ctx, const char *level, const char *fmt, va_list ap) { xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; xmlParserInputPtr input = NULL; xmlParserInputPtr cur = NULL; xmlChar *str = NULL; 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, "%s: ", level); xmlStrVASPrintf(&str, MAX_ERR_MSG_SIZE, fmt, ap); if (str != NULL) { xmlGenericError(xmlGenericErrorContext, "%s", (char *) str); xmlFree(str); } if (ctxt != NULL) { xmlParserPrintFileContext(input); if (cur != NULL) { xmlParserPrintFileInfo(cur); xmlGenericError(xmlGenericErrorContext, "\n"); xmlParserPrintFileContext(cur); } } } /** * This is the default SAX error handler, but it will never be * called. If it isn't replaced by the user, errors will be * handled by #xmlFormatError. * * @deprecated Do not call directly. * * Format an error message with additional detail from the * parser context and print to generic error handler. * * @param ctx an XML parser context * @param msg printf-like format string * @param ... arguments to format */ void xmlParserError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { va_list ap; va_start(ap, msg); xmlVFormatLegacyError(ctx, "error", msg, ap); va_end(ap); } /** * This is the default SAX warning handler, but it will never be * called. If it isn't replaced by the user, warnings will be * handled by #xmlFormatError. * * @deprecated Do not call directly. * * Format an warning message with additional detail from the * parser context and print to generic error handler. * * @param ctx an XML parser context * @param msg printf-like format string * @param ... arguments to format */ void xmlParserWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { va_list ap; va_start(ap, msg); xmlVFormatLegacyError(ctx, "warning", msg, ap); va_end(ap); } /** * This is the default validity error handler, but it will never be * called. If it isn't replaced by the user, errors will be * handled by #xmlFormatError. * * @deprecated Do not call directly. * * Format an error message with additional detail from the * parser context and print to generic error handler. * * @param ctx an XML parser context * @param msg printf-like format string * @param ... arguments to format */ void xmlParserValidityError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { va_list ap; va_start(ap, msg); xmlVFormatLegacyError(ctx, "validity error", msg, ap); va_end(ap); } /** * This is the default validity warning handler, but it will never * be called. If it isn't replaced by the user, warnings will be * handled by #xmlFormatError. * * @deprecated Do not call directly. * * Format an warning message with additional detail from the * parser context and print to generic error handler. * * @param ctx an XML parser context * @param msg printf-like format string * @param ... arguments to format */ void xmlParserValidityWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...) { va_list ap; va_start(ap, msg); xmlVFormatLegacyError(ctx, "validity warning", msg, ap); va_end(ap); } /************************************************************************ * * * Extended Error Handling * * * ************************************************************************/ /** * Get the last error raised in this thread. * * @returns a pointer to the error */ const xmlError * xmlGetLastError(void) { const xmlError *error = xmlGetLastErrorInternal(); if (error->code == XML_ERR_OK) return(NULL); return(error); } /** * Reset the error to success. * * @param err pointer to the error */ void xmlResetError(xmlError *err) { if (err == NULL) return; if (err->code == XML_ERR_OK) return; if (err->message != NULL) xmlFree(err->message); if (err->file != NULL) xmlFree(err->file); if (err->str1 != NULL) xmlFree(err->str1); if (err->str2 != NULL) xmlFree(err->str2); if (err->str3 != NULL) xmlFree(err->str3); memset(err, 0, sizeof(xmlError)); err->code = XML_ERR_OK; } /** * Reset the last error to success. */ void xmlResetLastError(void) { xmlError *error = xmlGetLastErrorInternal(); if (error->code != XML_ERR_OK) xmlResetError(error); } /** * Copy an error. * * @param from a source error * @param to a target error * @returns 0 in case of success and -1 in case of error. */ int xmlCopyError(const xmlError *from, xmlError *to) { const char *fmt = NULL; if ((from == NULL) || (to == NULL)) return(-1); if (from->message != NULL) fmt = "%s"; 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)); } /** * @param code an xmlParserErrors code * @returns an error message for a code. */ const char * xmlErrString(xmlParserErrors code) { const char *errmsg; switch (code) { case XML_ERR_INVALID_HEX_CHARREF: errmsg = "CharRef: invalid hexadecimal value"; break; case XML_ERR_INVALID_DEC_CHARREF: errmsg = "CharRef: invalid decimal value"; break; case XML_ERR_INVALID_CHARREF: errmsg = "CharRef: invalid value"; break; case XML_ERR_INTERNAL_ERROR: errmsg = "internal error"; break; case XML_ERR_PEREF_AT_EOF: errmsg = "PEReference at end of document"; break; case XML_ERR_PEREF_IN_PROLOG: errmsg = "PEReference in prolog"; break; case XML_ERR_PEREF_IN_EPILOG: errmsg = "PEReference in epilog"; break; case XML_ERR_PEREF_NO_NAME: errmsg = "PEReference: no name"; break; case XML_ERR_PEREF_SEMICOL_MISSING: errmsg = "PEReference: expecting ';'"; break; case XML_ERR_ENTITY_LOOP: errmsg = "Detected an entity reference loop"; break; case XML_ERR_ENTITY_NOT_STARTED: errmsg = "EntityValue: \" or ' expected"; break; case XML_ERR_ENTITY_PE_INTERNAL: errmsg = "PEReferences forbidden in internal subset"; break; case XML_ERR_ENTITY_NOT_FINISHED: errmsg = "EntityValue: \" or ' expected"; break; case XML_ERR_ATTRIBUTE_NOT_STARTED: errmsg = "AttValue: \" or ' expected"; break; case XML_ERR_LT_IN_ATTRIBUTE: errmsg = "Unescaped '<' not allowed in attributes values"; break; case XML_ERR_LITERAL_NOT_STARTED: errmsg = "SystemLiteral \" or ' expected"; break; case XML_ERR_LITERAL_NOT_FINISHED: errmsg = "Unfinished System or Public ID \" or ' expected"; break; case XML_ERR_MISPLACED_CDATA_END: errmsg = "Sequence ']]>' not allowed in content"; break; case XML_ERR_URI_REQUIRED: errmsg = "SYSTEM or PUBLIC, the URI is missing"; break; case XML_ERR_PUBID_REQUIRED: errmsg = "PUBLIC, the Public Identifier is missing"; break; case XML_ERR_HYPHEN_IN_COMMENT: errmsg = "Comment must not contain '--' (double-hyphen)"; break; case XML_ERR_PI_NOT_STARTED: errmsg = "xmlParsePI : no target name"; break; case XML_ERR_RESERVED_XML_NAME: errmsg = "Invalid PI name"; break; case XML_ERR_NOTATION_NOT_STARTED: errmsg = "NOTATION: Name expected here"; break; case XML_ERR_NOTATION_NOT_FINISHED: errmsg = "'>' required to close NOTATION declaration"; break; case XML_ERR_VALUE_REQUIRED: errmsg = "Entity value required"; break; case XML_ERR_URI_FRAGMENT: errmsg = "Fragment not allowed"; break; case XML_ERR_ATTLIST_NOT_STARTED: errmsg = "'(' required to start ATTLIST enumeration"; break; case XML_ERR_NMTOKEN_REQUIRED: errmsg = "NmToken expected in ATTLIST enumeration"; break; case XML_ERR_ATTLIST_NOT_FINISHED: errmsg = "')' required to finish ATTLIST enumeration"; break; case XML_ERR_MIXED_NOT_STARTED: errmsg = "MixedContentDecl : '|' or ')*' expected"; break; case XML_ERR_PCDATA_REQUIRED: errmsg = "MixedContentDecl : '#PCDATA' expected"; break; case XML_ERR_ELEMCONTENT_NOT_STARTED: errmsg = "ContentDecl : Name or '(' expected"; break; case XML_ERR_ELEMCONTENT_NOT_FINISHED: errmsg = "ContentDecl : ',' '|' or ')' expected"; break; case XML_ERR_PEREF_IN_INT_SUBSET: errmsg = "PEReference: forbidden within markup decl in internal subset"; break; case XML_ERR_GT_REQUIRED: errmsg = "expected '>'"; break; case XML_ERR_CONDSEC_INVALID: errmsg = "XML conditional section '[' expected"; break; case XML_ERR_INT_SUBSET_NOT_FINISHED: errmsg = "Content error in the internal subset"; break; case XML_ERR_EXT_SUBSET_NOT_FINISHED: errmsg = "Content error in the external subset"; break; case XML_ERR_CONDSEC_INVALID_KEYWORD: errmsg = "conditional section INCLUDE or IGNORE keyword expected"; break; case XML_ERR_CONDSEC_NOT_FINISHED: errmsg = "XML conditional section not closed"; break; case XML_ERR_XMLDECL_NOT_STARTED: errmsg = "Text declaration '' expected"; break; case XML_ERR_EXT_ENTITY_STANDALONE: errmsg = "external parsed entities cannot be standalone"; break; case XML_ERR_ENTITYREF_SEMICOL_MISSING: errmsg = "EntityRef: expecting ';'"; break; case XML_ERR_DOCTYPE_NOT_FINISHED: errmsg = "DOCTYPE improperly terminated"; break; case XML_ERR_LTSLASH_REQUIRED: errmsg = "EndTag: '