1 /*
2 * error.c: module displaying/handling XML parser errors
3 *
4 * See Copyright for the status of this software.
5 *
6 * Daniel Veillard <[email protected]>
7 */
8
9 #define IN_LIBXML
10 #include "libxml.h"
11
12 #include <string.h>
13 #include <stdarg.h>
14 #include <stdlib.h>
15 #include <libxml/parser.h>
16 #include <libxml/xmlerror.h>
17 #include <libxml/xmlmemory.h>
18
19 #include "private/error.h"
20 #include "private/globals.h"
21 #include "private/string.h"
22
23 /************************************************************************
24 * *
25 * Error struct *
26 * *
27 ************************************************************************/
28
29 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)30 xmlVSetError(xmlError *err,
31 void *ctxt, xmlNodePtr node,
32 int domain, int code, xmlErrorLevel level,
33 const char *file, int line,
34 const char *str1, const char *str2, const char *str3,
35 int int1, int col,
36 const char *fmt, va_list ap)
37 {
38 char *message = NULL;
39 char *fileCopy = NULL;
40 char *str1Copy = NULL;
41 char *str2Copy = NULL;
42 char *str3Copy = NULL;
43
44 if (code == XML_ERR_OK) {
45 xmlResetError(err);
46 return(0);
47 }
48
49 /*
50 * Formatting the message
51 */
52 if (fmt == NULL) {
53 message = xmlMemStrdup("No error message provided");
54 } else {
55 xmlChar *tmp;
56 int res;
57
58 res = xmlStrVASPrintf(&tmp, MAX_ERR_MSG_SIZE, fmt, ap);
59 if (res < 0)
60 goto err_memory;
61 message = (char *) tmp;
62 }
63 if (message == NULL)
64 goto err_memory;
65
66 if (file != NULL) {
67 fileCopy = (char *) xmlStrdup((const xmlChar *) file);
68 if (fileCopy == NULL)
69 goto err_memory;
70 }
71 if (str1 != NULL) {
72 str1Copy = (char *) xmlStrdup((const xmlChar *) str1);
73 if (str1Copy == NULL)
74 goto err_memory;
75 }
76 if (str2 != NULL) {
77 str2Copy = (char *) xmlStrdup((const xmlChar *) str2);
78 if (str2Copy == NULL)
79 goto err_memory;
80 }
81 if (str3 != NULL) {
82 str3Copy = (char *) xmlStrdup((const xmlChar *) str3);
83 if (str3Copy == NULL)
84 goto err_memory;
85 }
86
87 xmlResetError(err);
88
89 err->domain = domain;
90 err->code = code;
91 err->message = message;
92 err->level = level;
93 err->file = fileCopy;
94 err->line = line;
95 err->str1 = str1Copy;
96 err->str2 = str2Copy;
97 err->str3 = str3Copy;
98 err->int1 = int1;
99 err->int2 = col;
100 err->node = node;
101 err->ctxt = ctxt;
102
103 return(0);
104
105 err_memory:
106 xmlFree(message);
107 xmlFree(fileCopy);
108 xmlFree(str1Copy);
109 xmlFree(str2Copy);
110 xmlFree(str3Copy);
111 return(-1);
112 }
113
114 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,...)115 xmlSetError(xmlError *err,
116 void *ctxt, xmlNodePtr node,
117 int domain, int code, xmlErrorLevel level,
118 const char *file, int line,
119 const char *str1, const char *str2, const char *str3,
120 int int1, int col,
121 const char *fmt, ...)
122 {
123 va_list ap;
124 int res;
125
126 va_start(ap, fmt);
127 res = xmlVSetError(err, ctxt, node, domain, code, level, file, line,
128 str1, str2, str3, int1, col, fmt, ap);
129 va_end(ap);
130
131 return(res);
132 }
133
134 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)135 xmlVUpdateError(xmlError *err,
136 void *ctxt, xmlNodePtr node,
137 int domain, int code, xmlErrorLevel level,
138 const char *file, int line,
139 const char *str1, const char *str2, const char *str3,
140 int int1, int col,
141 const char *fmt, va_list ap)
142 {
143 int res;
144
145 /*
146 * Find first element parent.
147 */
148 if (node != NULL) {
149 int i;
150
151 for (i = 0; i < 10; i++) {
152 if ((node->type == XML_ELEMENT_NODE) ||
153 (node->parent == NULL))
154 break;
155 node = node->parent;
156 }
157 }
158
159 /*
160 * Get file and line from node.
161 */
162 if (node != NULL) {
163 if ((file == NULL) && (node->doc != NULL))
164 file = (const char *) node->doc->URL;
165
166 if (line == 0) {
167 if (node->type == XML_ELEMENT_NODE)
168 line = node->line;
169 if ((line == 0) || (line == 65535))
170 line = xmlGetLineNo(node);
171 }
172 }
173
174 res = xmlVSetError(err, ctxt, node, domain, code, level, file, line,
175 str1, str2, str3, int1, col, fmt, ap);
176
177 return(res);
178 }
179
180 /************************************************************************
181 * *
182 * Handling of out of context errors *
183 * *
184 ************************************************************************/
185
186 /**
187 * xmlGenericErrorDefaultFunc:
188 * @ctx: an error context
189 * @msg: the message to display/transmit
190 * @...: extra parameters for the message display
191 *
192 * Default handler for out of context error messages.
193 */
194 void
xmlGenericErrorDefaultFunc(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)195 xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
196 va_list args;
197
198 if (xmlGenericErrorContext == NULL)
199 xmlGenericErrorContext = (void *) stderr;
200
201 va_start(args, msg);
202 vfprintf((FILE *)xmlGenericErrorContext, msg, args);
203 va_end(args);
204 }
205
206 /**
207 * initGenericErrorDefaultFunc:
208 * @handler: the handler
209 *
210 * DEPRECATED: Use xmlSetGenericErrorFunc.
211 *
212 * Set or reset (if NULL) the default handler for generic errors
213 * to the builtin error function.
214 */
215 void
initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler)216 initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler)
217 {
218 if (handler == NULL)
219 xmlGenericError = xmlGenericErrorDefaultFunc;
220 else
221 xmlGenericError = (*handler);
222 }
223
224 /**
225 * xmlSetGenericErrorFunc:
226 * @ctx: the new error handling context
227 * @handler: the new handler function
228 *
229 * DEPRECATED: See xmlSetStructuredErrorFunc for alternatives.
230 *
231 * Set the global "generic" handler and context for error messages.
232 * The generic error handler will only receive fragments of error
233 * messages which should be concatenated or printed to a stream.
234 *
235 * If handler is NULL, use the built-in default handler which prints
236 * to stderr.
237 *
238 * Since this is a global setting, it's a good idea to reset the
239 * error handler to its default value after collecting the errors
240 * you're interested in.
241 *
242 * For multi-threaded applications, this must be set separately for
243 * each thread.
244 */
245 void
xmlSetGenericErrorFunc(void * ctx,xmlGenericErrorFunc handler)246 xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
247 xmlGenericErrorContext = ctx;
248 if (handler != NULL)
249 xmlGenericError = handler;
250 else
251 xmlGenericError = xmlGenericErrorDefaultFunc;
252 }
253
254 /**
255 * xmlSetStructuredErrorFunc:
256 * @ctx: the new error handling context
257 * @handler: the new handler function
258 *
259 * DEPRECATED: Use a per-context error handler.
260 *
261 * It's recommended to use the per-context error handlers instead:
262 *
263 * - xmlCtxtSetErrorHandler (since 2.13.0)
264 * - xmlTextReaderSetStructuredErrorHandler
265 * - xmlXPathSetErrorHandler (since 2.13.0)
266 * - xmlXIncludeSetErrorHandler (since 2.13.0)
267 * - xmlSchemaSetParserStructuredErrors
268 * - xmlSchemaSetValidStructuredErrors
269 * - xmlRelaxNGSetParserStructuredErrors
270 * - xmlRelaxNGSetValidStructuredErrors
271 *
272 * Set the global "structured" handler and context for error messages.
273 * If handler is NULL, the error handler is deactivated.
274 *
275 * The structured error handler takes precedence over "generic"
276 * handlers, even per-context generic handlers.
277 *
278 * Since this is a global setting, it's a good idea to deactivate the
279 * error handler after collecting the errors you're interested in.
280 *
281 * For multi-threaded applications, this must be set separately for
282 * each thread.
283 */
284 void
xmlSetStructuredErrorFunc(void * ctx,xmlStructuredErrorFunc handler)285 xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) {
286 xmlStructuredErrorContext = ctx;
287 xmlStructuredError = handler;
288 }
289
290 /************************************************************************
291 * *
292 * Handling of parsing errors *
293 * *
294 ************************************************************************/
295
296 /**
297 * xmlParserPrintFileInfo:
298 * @input: an xmlParserInputPtr input
299 *
300 * DEPRECATED: Use xmlFormatError.
301 *
302 * Displays the associated file and line information for the current input
303 */
304
305 void
xmlParserPrintFileInfo(xmlParserInputPtr input)306 xmlParserPrintFileInfo(xmlParserInputPtr input) {
307 if (input != NULL) {
308 if (input->filename)
309 xmlGenericError(xmlGenericErrorContext,
310 "%s:%d: ", input->filename,
311 input->line);
312 else
313 xmlGenericError(xmlGenericErrorContext,
314 "Entity: line %d: ", input->line);
315 }
316 }
317
318 /**
319 * xmlParserPrintFileContextInternal:
320 * @input: an xmlParserInputPtr input
321 *
322 * Displays current context within the input content for error tracking
323 */
324
325 static void
xmlParserPrintFileContextInternal(xmlParserInputPtr input,xmlGenericErrorFunc channel,void * data)326 xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
327 xmlGenericErrorFunc channel, void *data ) {
328 const xmlChar *cur, *base, *start;
329 unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
330 xmlChar content[81]; /* space for 80 chars + line terminator */
331 xmlChar *ctnt;
332
333 if ((input == NULL) || (input->cur == NULL))
334 return;
335
336 cur = input->cur;
337 base = input->base;
338 /* skip backwards over any end-of-lines */
339 while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
340 cur--;
341 }
342 n = 0;
343 /* search backwards for beginning-of-line (to max buff size) */
344 while ((n < sizeof(content) - 1) && (cur > base) &&
345 (*cur != '\n') && (*cur != '\r')) {
346 cur--;
347 n++;
348 }
349 if ((n > 0) && ((*cur == '\n') || (*cur == '\r'))) {
350 cur++;
351 } else {
352 /* skip over continuation bytes */
353 while ((cur < input->cur) && ((*cur & 0xC0) == 0x80))
354 cur++;
355 }
356 /* calculate the error position in terms of the current position */
357 col = input->cur - cur;
358 /* search forward for end-of-line (to max buff size) */
359 n = 0;
360 start = cur;
361 /* copy selected text to our buffer */
362 while ((*cur != 0) && (*(cur) != '\n') && (*(cur) != '\r')) {
363 int len = input->end - cur;
364 int c = xmlGetUTF8Char(cur, &len);
365
366 if ((c < 0) || (n + len > sizeof(content)-1))
367 break;
368 cur += len;
369 n += len;
370 }
371 memcpy(content, start, n);
372 content[n] = 0;
373 /* print out the selected text */
374 channel(data ,"%s\n", content);
375 /* create blank line with problem pointer */
376 n = 0;
377 ctnt = content;
378 /* (leave buffer space for pointer + line terminator) */
379 while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
380 if (*(ctnt) != '\t')
381 *(ctnt) = ' ';
382 ctnt++;
383 }
384 *ctnt++ = '^';
385 *ctnt = 0;
386 channel(data ,"%s\n", content);
387 }
388
389 /**
390 * xmlParserPrintFileContext:
391 * @input: an xmlParserInputPtr input
392 *
393 * DEPRECATED: Use xmlFormatError.
394 *
395 * Displays current context within the input content for error tracking
396 */
397 void
xmlParserPrintFileContext(xmlParserInputPtr input)398 xmlParserPrintFileContext(xmlParserInputPtr input) {
399 xmlParserPrintFileContextInternal(input, xmlGenericError,
400 xmlGenericErrorContext);
401 }
402
403 /**
404 * xmlFormatError:
405 * @err: the error
406 * @channel: callback
407 * @data: user data for callback
408 *
409 * Report a formatted error to a printf-like callback.
410 *
411 * This can result in a verbose multi-line report including additional
412 * information from the parser context.
413 *
414 * Available since 2.13.0.
415 */
416 void
xmlFormatError(const xmlError * err,xmlGenericErrorFunc channel,void * data)417 xmlFormatError(const xmlError *err, xmlGenericErrorFunc channel, void *data)
418 {
419 const char *message;
420 const char *file;
421 int line;
422 int code;
423 int domain;
424 const xmlChar *name = NULL;
425 xmlNodePtr node;
426 xmlErrorLevel level;
427 xmlParserCtxtPtr ctxt = NULL;
428 xmlParserInputPtr input = NULL;
429 xmlParserInputPtr cur = NULL;
430
431 if ((err == NULL) || (channel == NULL))
432 return;
433
434 message = err->message;
435 file = err->file;
436 line = err->line;
437 code = err->code;
438 domain = err->domain;
439 level = err->level;
440 node = err->node;
441
442 if (code == XML_ERR_OK)
443 return;
444
445 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
446 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
447 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
448 ctxt = err->ctxt;
449 }
450
451 if ((node != NULL) && (node->type == XML_ELEMENT_NODE) &&
452 (domain != XML_FROM_SCHEMASV))
453 name = node->name;
454
455 /*
456 * Maintain the compatibility with the legacy error handling
457 */
458 if ((ctxt != NULL) && (ctxt->input != NULL)) {
459 input = ctxt->input;
460 if ((input->filename == NULL) &&
461 (ctxt->inputNr > 1)) {
462 cur = input;
463 input = ctxt->inputTab[ctxt->inputNr - 2];
464 }
465 if (input->filename)
466 channel(data, "%s:%d: ", input->filename, input->line);
467 else if ((line != 0) && (domain == XML_FROM_PARSER))
468 channel(data, "Entity: line %d: ", input->line);
469 } else {
470 if (file != NULL)
471 channel(data, "%s:%d: ", file, line);
472 else if ((line != 0) &&
473 ((domain == XML_FROM_PARSER) || (domain == XML_FROM_SCHEMASV)||
474 (domain == XML_FROM_SCHEMASP)||(domain == XML_FROM_DTD) ||
475 (domain == XML_FROM_RELAXNGP)||(domain == XML_FROM_RELAXNGV)))
476 channel(data, "Entity: line %d: ", line);
477 }
478 if (name != NULL) {
479 channel(data, "element %s: ", name);
480 }
481 switch (domain) {
482 case XML_FROM_PARSER:
483 channel(data, "parser ");
484 break;
485 case XML_FROM_NAMESPACE:
486 channel(data, "namespace ");
487 break;
488 case XML_FROM_DTD:
489 case XML_FROM_VALID:
490 channel(data, "validity ");
491 break;
492 case XML_FROM_HTML:
493 channel(data, "HTML parser ");
494 break;
495 case XML_FROM_MEMORY:
496 channel(data, "memory ");
497 break;
498 case XML_FROM_OUTPUT:
499 channel(data, "output ");
500 break;
501 case XML_FROM_IO:
502 channel(data, "I/O ");
503 break;
504 case XML_FROM_XINCLUDE:
505 channel(data, "XInclude ");
506 break;
507 case XML_FROM_XPATH:
508 channel(data, "XPath ");
509 break;
510 case XML_FROM_XPOINTER:
511 channel(data, "parser ");
512 break;
513 case XML_FROM_REGEXP:
514 channel(data, "regexp ");
515 break;
516 case XML_FROM_MODULE:
517 channel(data, "module ");
518 break;
519 case XML_FROM_SCHEMASV:
520 channel(data, "Schemas validity ");
521 break;
522 case XML_FROM_SCHEMASP:
523 channel(data, "Schemas parser ");
524 break;
525 case XML_FROM_RELAXNGP:
526 channel(data, "Relax-NG parser ");
527 break;
528 case XML_FROM_RELAXNGV:
529 channel(data, "Relax-NG validity ");
530 break;
531 case XML_FROM_CATALOG:
532 channel(data, "Catalog ");
533 break;
534 case XML_FROM_C14N:
535 channel(data, "C14N ");
536 break;
537 case XML_FROM_XSLT:
538 channel(data, "XSLT ");
539 break;
540 case XML_FROM_I18N:
541 channel(data, "encoding ");
542 break;
543 case XML_FROM_SCHEMATRONV:
544 channel(data, "schematron ");
545 break;
546 case XML_FROM_BUFFER:
547 channel(data, "internal buffer ");
548 break;
549 case XML_FROM_URI:
550 channel(data, "URI ");
551 break;
552 default:
553 break;
554 }
555 switch (level) {
556 case XML_ERR_NONE:
557 channel(data, ": ");
558 break;
559 case XML_ERR_WARNING:
560 channel(data, "warning : ");
561 break;
562 case XML_ERR_ERROR:
563 channel(data, "error : ");
564 break;
565 case XML_ERR_FATAL:
566 channel(data, "error : ");
567 break;
568 }
569 if (message != NULL) {
570 int len;
571 len = xmlStrlen((const xmlChar *) message);
572 if ((len > 0) && (message[len - 1] != '\n'))
573 channel(data, "%s\n", message);
574 else
575 channel(data, "%s", message);
576 } else {
577 channel(data, "%s\n", "No error message provided");
578 }
579
580 if (ctxt != NULL) {
581 if ((input != NULL) &&
582 ((input->buf == NULL) || (input->buf->encoder == NULL)) &&
583 (code == XML_ERR_INVALID_ENCODING) &&
584 (input->cur < input->end)) {
585 int i;
586
587 channel(data, "Bytes:");
588 for (i = 0; i < 4; i++) {
589 if (input->cur + i >= input->end)
590 break;
591 channel(data, " 0x%02X", input->cur[i]);
592 }
593 channel(data, "\n");
594 }
595
596 xmlParserPrintFileContextInternal(input, channel, data);
597
598 if (cur != NULL) {
599 if (cur->filename)
600 channel(data, "%s:%d: \n", cur->filename, cur->line);
601 else if ((line != 0) && (domain == XML_FROM_PARSER))
602 channel(data, "Entity: line %d: \n", cur->line);
603 xmlParserPrintFileContextInternal(cur, channel, data);
604 }
605 }
606 if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
607 (err->int1 < 100) &&
608 (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
609 xmlChar buf[150];
610 int i;
611
612 channel(data, "%s\n", err->str1);
613 for (i=0;i < err->int1;i++)
614 buf[i] = ' ';
615 buf[i++] = '^';
616 buf[i] = 0;
617 channel(data, "%s\n", buf);
618 }
619 }
620
621 /**
622 * xmlRaiseMemoryError:
623 * @schannel: the structured callback channel
624 * @channel: the old callback channel
625 * @data: the callback data
626 * @domain: the domain for the error
627 * @error: optional error struct to be filled
628 *
629 * Update the global and optional error structure, then forward the
630 * error to an error handler.
631 *
632 * This function doesn't make memory allocations which are likely
633 * to fail after an OOM error.
634 */
635 void
xmlRaiseMemoryError(xmlStructuredErrorFunc schannel,xmlGenericErrorFunc channel,void * data,int domain,xmlError * error)636 xmlRaiseMemoryError(xmlStructuredErrorFunc schannel, xmlGenericErrorFunc channel,
637 void *data, int domain, xmlError *error)
638 {
639 xmlError *lastError = xmlGetLastErrorInternal();
640
641 xmlResetLastError();
642 lastError->domain = domain;
643 lastError->code = XML_ERR_NO_MEMORY;
644 lastError->level = XML_ERR_FATAL;
645
646 if (error != NULL) {
647 xmlResetError(error);
648 error->domain = domain;
649 error->code = XML_ERR_NO_MEMORY;
650 error->level = XML_ERR_FATAL;
651 }
652
653 if (schannel != NULL) {
654 schannel(data, lastError);
655 } else if (xmlStructuredError != NULL) {
656 xmlStructuredError(xmlStructuredErrorContext, lastError);
657 } else if (channel != NULL) {
658 channel(data, "libxml2: out of memory\n");
659 }
660 }
661
662 /**
663 * xmlVRaiseError:
664 * @schannel: the structured callback channel
665 * @channel: the old callback channel
666 * @data: the callback data
667 * @ctx: the parser context or NULL
668 * @node: the current node or NULL
669 * @domain: the domain for the error
670 * @code: the code for the error
671 * @level: the xmlErrorLevel for the error
672 * @file: the file source of the error (or NULL)
673 * @line: the line of the error or 0 if N/A
674 * @str1: extra string info
675 * @str2: extra string info
676 * @str3: extra string info
677 * @int1: extra int info
678 * @col: column number of the error or 0 if N/A
679 * @msg: the message to display/transmit
680 * @ap: extra parameters for the message display
681 *
682 * Update the appropriate global or contextual error structure,
683 * then forward the error message down the parser or generic
684 * error callback handler
685 *
686 * Returns 0 on success, -1 if a memory allocation failed.
687 */
688 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)689 xmlVRaiseError(xmlStructuredErrorFunc schannel,
690 xmlGenericErrorFunc channel, void *data, void *ctx,
691 xmlNode *node, int domain, int code, xmlErrorLevel level,
692 const char *file, int line, const char *str1,
693 const char *str2, const char *str3, int int1, int col,
694 const char *msg, va_list ap)
695 {
696 xmlParserCtxtPtr ctxt = NULL;
697 /* xmlLastError is a macro retrieving the per-thread global. */
698 xmlErrorPtr lastError = xmlGetLastErrorInternal();
699 xmlErrorPtr to = lastError;
700
701 if (code == XML_ERR_OK)
702 return(0);
703 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
704 if (code == XML_ERR_INTERNAL_ERROR)
705 xmlAbort("Unexpected error: %d\n", code);
706 #endif
707 if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING))
708 return(0);
709
710 if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
711 (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
712 (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
713 ctxt = (xmlParserCtxtPtr) ctx;
714
715 if (ctxt != NULL)
716 to = &ctxt->lastError;
717 }
718
719 if (xmlVUpdateError(to, ctxt, node, domain, code, level, file, line,
720 str1, str2, str3, int1, col, msg, ap))
721 return(-1);
722
723 if (to != lastError) {
724 if (xmlCopyError(to, lastError) < 0)
725 return(-1);
726 }
727
728 if (schannel != NULL) {
729 schannel(data, to);
730 } else if (xmlStructuredError != NULL) {
731 xmlStructuredError(xmlStructuredErrorContext, to);
732 } else if (channel != NULL) {
733 /* Don't invoke legacy error handlers */
734 if ((channel == xmlGenericErrorDefaultFunc) ||
735 (channel == xmlParserError) ||
736 (channel == xmlParserWarning) ||
737 (channel == xmlParserValidityError) ||
738 (channel == xmlParserValidityWarning))
739 xmlFormatError(to, xmlGenericError, xmlGenericErrorContext);
740 else
741 channel(data, "%s", to->message);
742 }
743
744 return(0);
745 }
746
747 /**
748 * xmlRaiseError:
749 * @schannel: the structured callback channel
750 * @channel: the old callback channel
751 * @data: the callback data
752 * @ctx: the parser context or NULL
753 * @nod: the node or NULL
754 * @domain: the domain for the error
755 * @code: the code for the error
756 * @level: the xmlErrorLevel for the error
757 * @file: the file source of the error (or NULL)
758 * @line: the line of the error or 0 if N/A
759 * @str1: extra string info
760 * @str2: extra string info
761 * @str3: extra string info
762 * @int1: extra int info
763 * @col: column number of the error or 0 if N/A
764 * @msg: the message to display/transmit
765 * @...: extra parameters for the message display
766 *
767 * Update the appropriate global or contextual error structure,
768 * then forward the error message down the parser or generic
769 * error callback handler
770 *
771 * Returns 0 on success, -1 if a memory allocation failed.
772 */
773 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,...)774 xmlRaiseError(xmlStructuredErrorFunc schannel,
775 xmlGenericErrorFunc channel, void *data, void *ctx,
776 xmlNode *node, int domain, int code, xmlErrorLevel level,
777 const char *file, int line, const char *str1,
778 const char *str2, const char *str3, int int1, int col,
779 const char *msg, ...)
780 {
781 va_list ap;
782 int res;
783
784 va_start(ap, msg);
785 res = xmlVRaiseError(schannel, channel, data, ctx, node, domain, code,
786 level, file, line, str1, str2, str3, int1, col, msg,
787 ap);
788 va_end(ap);
789
790 return(res);
791 }
792
793 static void
xmlVFormatLegacyError(void * ctx,const char * level,const char * fmt,va_list ap)794 xmlVFormatLegacyError(void *ctx, const char *level,
795 const char *fmt, va_list ap) {
796 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
797 xmlParserInputPtr input = NULL;
798 xmlParserInputPtr cur = NULL;
799 xmlChar *str = NULL;
800
801 if (ctxt != NULL) {
802 input = ctxt->input;
803 if ((input != NULL) && (input->filename == NULL) &&
804 (ctxt->inputNr > 1)) {
805 cur = input;
806 input = ctxt->inputTab[ctxt->inputNr - 2];
807 }
808 xmlParserPrintFileInfo(input);
809 }
810
811 xmlGenericError(xmlGenericErrorContext, "%s: ", level);
812
813 xmlStrVASPrintf(&str, MAX_ERR_MSG_SIZE, fmt, ap);
814 if (str != NULL) {
815 xmlGenericError(xmlGenericErrorContext, "%s", (char *) str);
816 xmlFree(str);
817 }
818
819 if (ctxt != NULL) {
820 xmlParserPrintFileContext(input);
821 if (cur != NULL) {
822 xmlParserPrintFileInfo(cur);
823 xmlGenericError(xmlGenericErrorContext, "\n");
824 xmlParserPrintFileContext(cur);
825 }
826 }
827 }
828
829 /**
830 * xmlParserError:
831 * @ctx: an XML parser context
832 * @msg: the message to display/transmit
833 * @...: extra parameters for the message display
834 *
835 * Display and format an error messages, gives file, line, position and
836 * extra parameters.
837 */
838 void
xmlParserError(void * ctx,const char * msg ATTRIBUTE_UNUSED,...)839 xmlParserError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
840 {
841 va_list ap;
842
843 va_start(ap, msg);
844 xmlVFormatLegacyError(ctx, "error", msg, ap);
845 va_end(ap);
846 }
847
848 /**
849 * xmlParserWarning:
850 * @ctx: an XML parser context
851 * @msg: the message to display/transmit
852 * @...: extra parameters for the message display
853 *
854 * Display and format a warning messages, gives file, line, position and
855 * extra parameters.
856 */
857 void
xmlParserWarning(void * ctx,const char * msg ATTRIBUTE_UNUSED,...)858 xmlParserWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
859 {
860 va_list ap;
861
862 va_start(ap, msg);
863 xmlVFormatLegacyError(ctx, "warning", msg, ap);
864 va_end(ap);
865 }
866
867 /**
868 * xmlParserValidityError:
869 * @ctx: an XML parser context
870 * @msg: the message to display/transmit
871 * @...: extra parameters for the message display
872 *
873 * Display and format an validity error messages, gives file,
874 * line, position and extra parameters.
875 */
876 void
xmlParserValidityError(void * ctx,const char * msg ATTRIBUTE_UNUSED,...)877 xmlParserValidityError(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
878 {
879 va_list ap;
880
881 va_start(ap, msg);
882 xmlVFormatLegacyError(ctx, "validity error", msg, ap);
883 va_end(ap);
884 }
885
886 /**
887 * xmlParserValidityWarning:
888 * @ctx: an XML parser context
889 * @msg: the message to display/transmit
890 * @...: extra parameters for the message display
891 *
892 * Display and format a validity warning messages, gives file, line,
893 * position and extra parameters.
894 */
895 void
xmlParserValidityWarning(void * ctx,const char * msg ATTRIBUTE_UNUSED,...)896 xmlParserValidityWarning(void *ctx, const char *msg ATTRIBUTE_UNUSED, ...)
897 {
898 va_list ap;
899
900 va_start(ap, msg);
901 xmlVFormatLegacyError(ctx, "validity warning", msg, ap);
902 va_end(ap);
903 }
904
905
906 /************************************************************************
907 * *
908 * Extended Error Handling *
909 * *
910 ************************************************************************/
911
912 /**
913 * xmlGetLastError:
914 *
915 * Get the last global error registered. This is per thread if compiled
916 * with thread support.
917 *
918 * Returns a pointer to the error
919 */
920 const xmlError *
xmlGetLastError(void)921 xmlGetLastError(void)
922 {
923 const xmlError *error = xmlGetLastErrorInternal();
924
925 if (error->code == XML_ERR_OK)
926 return(NULL);
927 return(error);
928 }
929
930 /**
931 * xmlResetError:
932 * @err: pointer to the error.
933 *
934 * Cleanup the error.
935 */
936 void
xmlResetError(xmlErrorPtr err)937 xmlResetError(xmlErrorPtr err)
938 {
939 if (err == NULL)
940 return;
941 if (err->code == XML_ERR_OK)
942 return;
943 if (err->message != NULL)
944 xmlFree(err->message);
945 if (err->file != NULL)
946 xmlFree(err->file);
947 if (err->str1 != NULL)
948 xmlFree(err->str1);
949 if (err->str2 != NULL)
950 xmlFree(err->str2);
951 if (err->str3 != NULL)
952 xmlFree(err->str3);
953 memset(err, 0, sizeof(xmlError));
954 err->code = XML_ERR_OK;
955 }
956
957 /**
958 * xmlResetLastError:
959 *
960 * Cleanup the last global error registered. For parsing error
961 * this does not change the well-formedness result.
962 */
963 void
xmlResetLastError(void)964 xmlResetLastError(void)
965 {
966 xmlError *error = xmlGetLastErrorInternal();
967
968 if (error->code != XML_ERR_OK)
969 xmlResetError(error);
970 }
971
972 /**
973 * xmlCopyError:
974 * @from: a source error
975 * @to: a target error
976 *
977 * Save the original error to the new place.
978 *
979 * Returns 0 in case of success and -1 in case of error.
980 */
981 int
xmlCopyError(const xmlError * from,xmlErrorPtr to)982 xmlCopyError(const xmlError *from, xmlErrorPtr to) {
983 const char *fmt = NULL;
984
985 if ((from == NULL) || (to == NULL))
986 return(-1);
987
988 if (from->message != NULL)
989 fmt = "%s";
990
991 return(xmlSetError(to, from->ctxt, from->node,
992 from->domain, from->code, from->level,
993 from->file, from->line,
994 from->str1, from->str2, from->str3,
995 from->int1, from->int2,
996 fmt, from->message));
997 }
998
999 /**
1000 * xmlErrString:
1001 * @code: an xmlParserErrors code
1002 *
1003 * Returns an error message for a code.
1004 */
1005 const char *
xmlErrString(xmlParserErrors code)1006 xmlErrString(xmlParserErrors code) {
1007 const char *errmsg;
1008
1009 switch (code) {
1010 case XML_ERR_INVALID_HEX_CHARREF:
1011 errmsg = "CharRef: invalid hexadecimal value";
1012 break;
1013 case XML_ERR_INVALID_DEC_CHARREF:
1014 errmsg = "CharRef: invalid decimal value";
1015 break;
1016 case XML_ERR_INVALID_CHARREF:
1017 errmsg = "CharRef: invalid value";
1018 break;
1019 case XML_ERR_INTERNAL_ERROR:
1020 errmsg = "internal error";
1021 break;
1022 case XML_ERR_PEREF_AT_EOF:
1023 errmsg = "PEReference at end of document";
1024 break;
1025 case XML_ERR_PEREF_IN_PROLOG:
1026 errmsg = "PEReference in prolog";
1027 break;
1028 case XML_ERR_PEREF_IN_EPILOG:
1029 errmsg = "PEReference in epilog";
1030 break;
1031 case XML_ERR_PEREF_NO_NAME:
1032 errmsg = "PEReference: no name";
1033 break;
1034 case XML_ERR_PEREF_SEMICOL_MISSING:
1035 errmsg = "PEReference: expecting ';'";
1036 break;
1037 case XML_ERR_ENTITY_LOOP:
1038 errmsg = "Detected an entity reference loop";
1039 break;
1040 case XML_ERR_ENTITY_NOT_STARTED:
1041 errmsg = "EntityValue: \" or ' expected";
1042 break;
1043 case XML_ERR_ENTITY_PE_INTERNAL:
1044 errmsg = "PEReferences forbidden in internal subset";
1045 break;
1046 case XML_ERR_ENTITY_NOT_FINISHED:
1047 errmsg = "EntityValue: \" or ' expected";
1048 break;
1049 case XML_ERR_ATTRIBUTE_NOT_STARTED:
1050 errmsg = "AttValue: \" or ' expected";
1051 break;
1052 case XML_ERR_LT_IN_ATTRIBUTE:
1053 errmsg = "Unescaped '<' not allowed in attributes values";
1054 break;
1055 case XML_ERR_LITERAL_NOT_STARTED:
1056 errmsg = "SystemLiteral \" or ' expected";
1057 break;
1058 case XML_ERR_LITERAL_NOT_FINISHED:
1059 errmsg = "Unfinished System or Public ID \" or ' expected";
1060 break;
1061 case XML_ERR_MISPLACED_CDATA_END:
1062 errmsg = "Sequence ']]>' not allowed in content";
1063 break;
1064 case XML_ERR_URI_REQUIRED:
1065 errmsg = "SYSTEM or PUBLIC, the URI is missing";
1066 break;
1067 case XML_ERR_PUBID_REQUIRED:
1068 errmsg = "PUBLIC, the Public Identifier is missing";
1069 break;
1070 case XML_ERR_HYPHEN_IN_COMMENT:
1071 errmsg = "Comment must not contain '--' (double-hyphen)";
1072 break;
1073 case XML_ERR_PI_NOT_STARTED:
1074 errmsg = "xmlParsePI : no target name";
1075 break;
1076 case XML_ERR_RESERVED_XML_NAME:
1077 errmsg = "Invalid PI name";
1078 break;
1079 case XML_ERR_NOTATION_NOT_STARTED:
1080 errmsg = "NOTATION: Name expected here";
1081 break;
1082 case XML_ERR_NOTATION_NOT_FINISHED:
1083 errmsg = "'>' required to close NOTATION declaration";
1084 break;
1085 case XML_ERR_VALUE_REQUIRED:
1086 errmsg = "Entity value required";
1087 break;
1088 case XML_ERR_URI_FRAGMENT:
1089 errmsg = "Fragment not allowed";
1090 break;
1091 case XML_ERR_ATTLIST_NOT_STARTED:
1092 errmsg = "'(' required to start ATTLIST enumeration";
1093 break;
1094 case XML_ERR_NMTOKEN_REQUIRED:
1095 errmsg = "NmToken expected in ATTLIST enumeration";
1096 break;
1097 case XML_ERR_ATTLIST_NOT_FINISHED:
1098 errmsg = "')' required to finish ATTLIST enumeration";
1099 break;
1100 case XML_ERR_MIXED_NOT_STARTED:
1101 errmsg = "MixedContentDecl : '|' or ')*' expected";
1102 break;
1103 case XML_ERR_PCDATA_REQUIRED:
1104 errmsg = "MixedContentDecl : '#PCDATA' expected";
1105 break;
1106 case XML_ERR_ELEMCONTENT_NOT_STARTED:
1107 errmsg = "ContentDecl : Name or '(' expected";
1108 break;
1109 case XML_ERR_ELEMCONTENT_NOT_FINISHED:
1110 errmsg = "ContentDecl : ',' '|' or ')' expected";
1111 break;
1112 case XML_ERR_PEREF_IN_INT_SUBSET:
1113 errmsg =
1114 "PEReference: forbidden within markup decl in internal subset";
1115 break;
1116 case XML_ERR_GT_REQUIRED:
1117 errmsg = "expected '>'";
1118 break;
1119 case XML_ERR_CONDSEC_INVALID:
1120 errmsg = "XML conditional section '[' expected";
1121 break;
1122 case XML_ERR_INT_SUBSET_NOT_FINISHED:
1123 errmsg = "Content error in the internal subset";
1124 break;
1125 case XML_ERR_EXT_SUBSET_NOT_FINISHED:
1126 errmsg = "Content error in the external subset";
1127 break;
1128 case XML_ERR_CONDSEC_INVALID_KEYWORD:
1129 errmsg =
1130 "conditional section INCLUDE or IGNORE keyword expected";
1131 break;
1132 case XML_ERR_CONDSEC_NOT_FINISHED:
1133 errmsg = "XML conditional section not closed";
1134 break;
1135 case XML_ERR_XMLDECL_NOT_STARTED:
1136 errmsg = "Text declaration '<?xml' required";
1137 break;
1138 case XML_ERR_XMLDECL_NOT_FINISHED:
1139 errmsg = "parsing XML declaration: '?>' expected";
1140 break;
1141 case XML_ERR_EXT_ENTITY_STANDALONE:
1142 errmsg = "external parsed entities cannot be standalone";
1143 break;
1144 case XML_ERR_ENTITYREF_SEMICOL_MISSING:
1145 errmsg = "EntityRef: expecting ';'";
1146 break;
1147 case XML_ERR_DOCTYPE_NOT_FINISHED:
1148 errmsg = "DOCTYPE improperly terminated";
1149 break;
1150 case XML_ERR_LTSLASH_REQUIRED:
1151 errmsg = "EndTag: '</' not found";
1152 break;
1153 case XML_ERR_EQUAL_REQUIRED:
1154 errmsg = "expected '='";
1155 break;
1156 case XML_ERR_STRING_NOT_CLOSED:
1157 errmsg = "String not closed expecting \" or '";
1158 break;
1159 case XML_ERR_STRING_NOT_STARTED:
1160 errmsg = "String not started expecting ' or \"";
1161 break;
1162 case XML_ERR_ENCODING_NAME:
1163 errmsg = "Invalid XML encoding name";
1164 break;
1165 case XML_ERR_STANDALONE_VALUE:
1166 errmsg = "standalone accepts only 'yes' or 'no'";
1167 break;
1168 case XML_ERR_DOCUMENT_EMPTY:
1169 errmsg = "Document is empty";
1170 break;
1171 case XML_ERR_DOCUMENT_END:
1172 errmsg = "Extra content at the end of the document";
1173 break;
1174 case XML_ERR_NOT_WELL_BALANCED:
1175 errmsg = "chunk is not well balanced";
1176 break;
1177 case XML_ERR_EXTRA_CONTENT:
1178 errmsg = "extra content at the end of well balanced chunk";
1179 break;
1180 case XML_ERR_VERSION_MISSING:
1181 errmsg = "Malformed declaration expecting version";
1182 break;
1183 case XML_ERR_NAME_TOO_LONG:
1184 errmsg = "Name too long";
1185 break;
1186 case XML_ERR_INVALID_ENCODING:
1187 errmsg = "Invalid bytes in character encoding";
1188 break;
1189 case XML_ERR_RESOURCE_LIMIT:
1190 errmsg = "Resource limit exceeded";
1191 break;
1192 case XML_ERR_ARGUMENT:
1193 errmsg = "Invalid argument";
1194 break;
1195 case XML_ERR_SYSTEM:
1196 errmsg = "Out of system resources";
1197 break;
1198 case XML_ERR_REDECL_PREDEF_ENTITY:
1199 errmsg = "Invalid redeclaration of predefined entity";
1200 break;
1201 case XML_ERR_UNSUPPORTED_ENCODING:
1202 errmsg = "Unsupported encoding";
1203 break;
1204 case XML_ERR_INVALID_CHAR:
1205 errmsg = "Invalid character";
1206 break;
1207
1208 case XML_IO_UNKNOWN:
1209 errmsg = "Unknown IO error"; break;
1210 case XML_IO_EACCES:
1211 errmsg = "Permission denied"; break;
1212 case XML_IO_EAGAIN:
1213 errmsg = "Resource temporarily unavailable"; break;
1214 case XML_IO_EBADF:
1215 errmsg = "Bad file descriptor"; break;
1216 case XML_IO_EBADMSG:
1217 errmsg = "Bad message"; break;
1218 case XML_IO_EBUSY:
1219 errmsg = "Resource busy"; break;
1220 case XML_IO_ECANCELED:
1221 errmsg = "Operation canceled"; break;
1222 case XML_IO_ECHILD:
1223 errmsg = "No child processes"; break;
1224 case XML_IO_EDEADLK:
1225 errmsg = "Resource deadlock avoided"; break;
1226 case XML_IO_EDOM:
1227 errmsg = "Domain error"; break;
1228 case XML_IO_EEXIST:
1229 errmsg = "File exists"; break;
1230 case XML_IO_EFAULT:
1231 errmsg = "Bad address"; break;
1232 case XML_IO_EFBIG:
1233 errmsg = "File too large"; break;
1234 case XML_IO_EINPROGRESS:
1235 errmsg = "Operation in progress"; break;
1236 case XML_IO_EINTR:
1237 errmsg = "Interrupted function call"; break;
1238 case XML_IO_EINVAL:
1239 errmsg = "Invalid argument"; break;
1240 case XML_IO_EIO:
1241 errmsg = "Input/output error"; break;
1242 case XML_IO_EISDIR:
1243 errmsg = "Is a directory"; break;
1244 case XML_IO_EMFILE:
1245 errmsg = "Too many open files"; break;
1246 case XML_IO_EMLINK:
1247 errmsg = "Too many links"; break;
1248 case XML_IO_EMSGSIZE:
1249 errmsg = "Inappropriate message buffer length"; break;
1250 case XML_IO_ENAMETOOLONG:
1251 errmsg = "Filename too long"; break;
1252 case XML_IO_ENFILE:
1253 errmsg = "Too many open files in system"; break;
1254 case XML_IO_ENODEV:
1255 errmsg = "No such device"; break;
1256 case XML_IO_ENOENT:
1257 errmsg = "No such file or directory"; break;
1258 case XML_IO_ENOEXEC:
1259 errmsg = "Exec format error"; break;
1260 case XML_IO_ENOLCK:
1261 errmsg = "No locks available"; break;
1262 case XML_IO_ENOMEM:
1263 errmsg = "Not enough space"; break;
1264 case XML_IO_ENOSPC:
1265 errmsg = "No space left on device"; break;
1266 case XML_IO_ENOSYS:
1267 errmsg = "Function not implemented"; break;
1268 case XML_IO_ENOTDIR:
1269 errmsg = "Not a directory"; break;
1270 case XML_IO_ENOTEMPTY:
1271 errmsg = "Directory not empty"; break;
1272 case XML_IO_ENOTSUP:
1273 errmsg = "Not supported"; break;
1274 case XML_IO_ENOTTY:
1275 errmsg = "Inappropriate I/O control operation"; break;
1276 case XML_IO_ENXIO:
1277 errmsg = "No such device or address"; break;
1278 case XML_IO_EPERM:
1279 errmsg = "Operation not permitted"; break;
1280 case XML_IO_EPIPE:
1281 errmsg = "Broken pipe"; break;
1282 case XML_IO_ERANGE:
1283 errmsg = "Result too large"; break;
1284 case XML_IO_EROFS:
1285 errmsg = "Read-only file system"; break;
1286 case XML_IO_ESPIPE:
1287 errmsg = "Invalid seek"; break;
1288 case XML_IO_ESRCH:
1289 errmsg = "No such process"; break;
1290 case XML_IO_ETIMEDOUT:
1291 errmsg = "Operation timed out"; break;
1292 case XML_IO_EXDEV:
1293 errmsg = "Improper link"; break;
1294 case XML_IO_NETWORK_ATTEMPT:
1295 errmsg = "Attempt to load network entity"; break;
1296 case XML_IO_ENCODER:
1297 errmsg = "encoder error"; break;
1298 case XML_IO_FLUSH:
1299 errmsg = "flush error"; break;
1300 case XML_IO_WRITE:
1301 errmsg = "write error"; break;
1302 case XML_IO_NO_INPUT:
1303 errmsg = "no input"; break;
1304 case XML_IO_BUFFER_FULL:
1305 errmsg = "buffer full"; break;
1306 case XML_IO_LOAD_ERROR:
1307 errmsg = "loading error"; break;
1308 case XML_IO_ENOTSOCK:
1309 errmsg = "not a socket"; break;
1310 case XML_IO_EISCONN:
1311 errmsg = "already connected"; break;
1312 case XML_IO_ECONNREFUSED:
1313 errmsg = "connection refused"; break;
1314 case XML_IO_ENETUNREACH:
1315 errmsg = "unreachable network"; break;
1316 case XML_IO_EADDRINUSE:
1317 errmsg = "address in use"; break;
1318 case XML_IO_EALREADY:
1319 errmsg = "already in use"; break;
1320 case XML_IO_EAFNOSUPPORT:
1321 errmsg = "unknown address family"; break;
1322 case XML_IO_UNSUPPORTED_PROTOCOL:
1323 errmsg = "unsupported protocol"; break;
1324
1325 default:
1326 errmsg = "Unregistered error message";
1327 }
1328
1329 return(errmsg);
1330 }
1331
1332 void
xmlVPrintErrorMessage(const char * fmt,va_list ap)1333 xmlVPrintErrorMessage(const char *fmt, va_list ap) {
1334 vfprintf(stderr, fmt, ap);
1335 }
1336
1337 void
xmlPrintErrorMessage(const char * fmt,...)1338 xmlPrintErrorMessage(const char *fmt, ...) {
1339 va_list ap;
1340
1341 va_start(ap, fmt);
1342 xmlVPrintErrorMessage(fmt, ap);
1343 va_end(ap);
1344 }
1345
1346 void
xmlAbort(const char * fmt,...)1347 xmlAbort(const char *fmt, ...) {
1348 va_list ap;
1349
1350 va_start(ap, fmt);
1351 xmlVPrintErrorMessage(fmt, ap);
1352 va_end(ap);
1353
1354 abort();
1355 }
1356