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