1 /* libxml2 - Library for parsing XML documents
2  * Copyright (C) 2006-2019 Free Software Foundation, Inc.
3  *
4  * This file is not part of the GNU gettext program, but is used with
5  * GNU gettext.
6  *
7  * The original copyright notice is as follows:
8  */
9 
10 /*
11  * Copyright (C) 1998-2012 Daniel Veillard.  All Rights Reserved.
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a copy
14  * of this software and associated documentation files (the "Software"), to deal
15  * in the Software without restriction, including without limitation the rights
16  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17  * copies of the Software, and to permit persons to whom the Software is fur-
18  * nished to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included in
21  * all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
25  * NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29  * THE SOFTWARE.
30  *
31  * Daniel Veillard <daniel@veillard.com>
32  */
33 
34 /*
35  * error.c: module displaying/handling XML parser errors
36  */
37 
38 #define IN_LIBXML
39 #include "libxml.h"
40 
41 #include <string.h>
42 #include <stdarg.h>
43 #include <libxml/parser.h>
44 #include <libxml/xmlerror.h>
45 #include <libxml/xmlmemory.h>
46 #include <libxml/globals.h>
47 
48 void XMLCDECL xmlGenericErrorDefaultFunc	(void *ctx ATTRIBUTE_UNUSED,
49 				 const char *msg,
50 				 ...) LIBXML_ATTR_FORMAT(2,3);
51 
52 #define XML_GET_VAR_STR(msg, str) {				\
53     int       size, prev_size = -1;				\
54     int       chars;						\
55     char      *larger;						\
56     va_list   ap;						\
57 								\
58     str = (char *) xmlMalloc(150);				\
59     if (str != NULL) {						\
60 								\
61     size = 150;							\
62 								\
63     while (size < 64000) {					\
64 	va_start(ap, msg);					\
65 	chars = vsnprintf(str, size, msg, ap);			\
66 	va_end(ap);						\
67 	if ((chars > -1) && (chars < size)) {			\
68 	    if (prev_size == chars) {				\
69 		break;						\
70 	    } else {						\
71 		prev_size = chars;				\
72 	    }							\
73 	}							\
74 	if (chars > -1)						\
75 	    size += chars + 1;					\
76 	else							\
77 	    size += 100;					\
78 	if ((larger = (char *) xmlRealloc(str, size)) == NULL) {\
79 	    break;						\
80 	}							\
81 	str = larger;						\
82     }}								\
83 }
84 
85 /************************************************************************
86  *									*
87  *			Handling of out of context errors		*
88  *									*
89  ************************************************************************/
90 
91 /**
92  * xmlGenericErrorDefaultFunc:
93  * @ctx:  an error context
94  * @msg:  the message to display/transmit
95  * @...:  extra parameters for the message display
96  *
97  * Default handler for out of context error messages.
98  */
99 void XMLCDECL
xmlGenericErrorDefaultFunc(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)100 xmlGenericErrorDefaultFunc(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
101     va_list args;
102 
103     if (xmlGenericErrorContext == NULL)
104 	xmlGenericErrorContext = (void *) stderr;
105 
106     va_start(args, msg);
107     vfprintf((FILE *)xmlGenericErrorContext, msg, args);
108     va_end(args);
109 }
110 
111 /**
112  * initGenericErrorDefaultFunc:
113  * @handler:  the handler
114  *
115  * Set or reset (if NULL) the default handler for generic errors
116  * to the builtin error function.
117  */
118 void
initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler)119 initGenericErrorDefaultFunc(xmlGenericErrorFunc * handler)
120 {
121     if (handler == NULL)
122         xmlGenericError = xmlGenericErrorDefaultFunc;
123     else
124         xmlGenericError = (*handler);
125 }
126 
127 /**
128  * xmlSetGenericErrorFunc:
129  * @ctx:  the new error handling context
130  * @handler:  the new handler function
131  *
132  * Function to reset the handler and the error context for out of
133  * context error messages.
134  * This simply means that @handler will be called for subsequent
135  * error messages while not parsing nor validating. And @ctx will
136  * be passed as first argument to @handler
137  * One can simply force messages to be emitted to another FILE * than
138  * stderr by setting @ctx to this file handle and @handler to NULL.
139  * For multi-threaded applications, this must be set separately for each thread.
140  */
141 void
xmlSetGenericErrorFunc(void * ctx,xmlGenericErrorFunc handler)142 xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
143     xmlGenericErrorContext = ctx;
144     if (handler != NULL)
145 	xmlGenericError = handler;
146     else
147 	xmlGenericError = xmlGenericErrorDefaultFunc;
148 }
149 
150 /**
151  * xmlSetStructuredErrorFunc:
152  * @ctx:  the new error handling context
153  * @handler:  the new handler function
154  *
155  * Function to reset the handler and the error context for out of
156  * context structured error messages.
157  * This simply means that @handler will be called for subsequent
158  * error messages while not parsing nor validating. And @ctx will
159  * be passed as first argument to @handler
160  * For multi-threaded applications, this must be set separately for each thread.
161  */
162 void
xmlSetStructuredErrorFunc(void * ctx,xmlStructuredErrorFunc handler)163 xmlSetStructuredErrorFunc(void *ctx, xmlStructuredErrorFunc handler) {
164     xmlStructuredErrorContext = ctx;
165     xmlStructuredError = handler;
166 }
167 
168 /************************************************************************
169  *									*
170  *			Handling of parsing errors			*
171  *									*
172  ************************************************************************/
173 
174 /**
175  * xmlParserPrintFileInfo:
176  * @input:  an xmlParserInputPtr input
177  *
178  * Displays the associated file and line informations for the current input
179  */
180 
181 void
xmlParserPrintFileInfo(xmlParserInputPtr input)182 xmlParserPrintFileInfo(xmlParserInputPtr input) {
183     if (input != NULL) {
184 	if (input->filename)
185 	    xmlGenericError(xmlGenericErrorContext,
186 		    "%s:%d: ", input->filename,
187 		    input->line);
188 	else
189 	    xmlGenericError(xmlGenericErrorContext,
190 		    "Entity: line %d: ", input->line);
191     }
192 }
193 
194 /**
195  * xmlParserPrintFileContext:
196  * @input:  an xmlParserInputPtr input
197  *
198  * Displays current context within the input content for error tracking
199  */
200 
201 static void
xmlParserPrintFileContextInternal(xmlParserInputPtr input,xmlGenericErrorFunc channel,void * data)202 xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
203 		xmlGenericErrorFunc channel, void *data ) {
204     const xmlChar *cur, *base;
205     unsigned int n, col;	/* GCC warns if signed, because compared with sizeof() */
206     xmlChar  content[81]; /* space for 80 chars + line terminator */
207     xmlChar *ctnt;
208 
209     if ((input == NULL) || (input->cur == NULL))
210         return;
211 
212     cur = input->cur;
213     base = input->base;
214     /* skip backwards over any end-of-lines */
215     while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
216 	cur--;
217     }
218     n = 0;
219     /* search backwards for beginning-of-line (to max buff size) */
220     while ((n++ < (sizeof(content)-1)) && (cur > base) &&
221 	   (*(cur) != '\n') && (*(cur) != '\r'))
222         cur--;
223     if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
224     /* calculate the error position in terms of the current position */
225     col = input->cur - cur;
226     /* search forward for end-of-line (to max buff size) */
227     n = 0;
228     ctnt = content;
229     /* copy selected text to our buffer */
230     while ((*cur != 0) && (*(cur) != '\n') &&
231 	   (*(cur) != '\r') && (n < sizeof(content)-1)) {
232 		*ctnt++ = *cur++;
233 	n++;
234     }
235     *ctnt = 0;
236     /* print out the selected text */
237     channel(data ,"%s\n", content);
238     /* create blank line with problem pointer */
239     n = 0;
240     ctnt = content;
241     /* (leave buffer space for pointer + line terminator) */
242     while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
243 	if (*(ctnt) != '\t')
244 	    *(ctnt) = ' ';
245 	ctnt++;
246     }
247     *ctnt++ = '^';
248     *ctnt = 0;
249     channel(data ,"%s\n", content);
250 }
251 
252 /**
253  * xmlParserPrintFileContext:
254  * @input:  an xmlParserInputPtr input
255  *
256  * Displays current context within the input content for error tracking
257  */
258 void
xmlParserPrintFileContext(xmlParserInputPtr input)259 xmlParserPrintFileContext(xmlParserInputPtr input) {
260    xmlParserPrintFileContextInternal(input, xmlGenericError,
261                                      xmlGenericErrorContext);
262 }
263 
264 /**
265  * xmlReportError:
266  * @err: the error
267  * @ctx: the parser context or NULL
268  * @str: the formatted error message
269  *
270  * Report an erro with its context, replace the 4 old error/warning
271  * routines.
272  */
273 static void
xmlReportError(xmlErrorPtr err,xmlParserCtxtPtr ctxt,const char * str,xmlGenericErrorFunc channel,void * data)274 xmlReportError(xmlErrorPtr err, xmlParserCtxtPtr ctxt, const char *str,
275                xmlGenericErrorFunc channel, void *data)
276 {
277     char *file = NULL;
278     int line = 0;
279     int code = -1;
280     int domain;
281     const xmlChar *name = NULL;
282     xmlNodePtr node;
283     xmlErrorLevel level;
284     xmlParserInputPtr input = NULL;
285     xmlParserInputPtr cur = NULL;
286 
287     if (err == NULL)
288         return;
289 
290     if (channel == NULL) {
291 	channel = xmlGenericError;
292 	data = xmlGenericErrorContext;
293     }
294     file = err->file;
295     line = err->line;
296     code = err->code;
297     domain = err->domain;
298     level = err->level;
299     node = err->node;
300 
301     if (code == XML_ERR_OK)
302         return;
303 
304     if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
305         name = node->name;
306 
307     /*
308      * Maintain the compatibility with the legacy error handling
309      */
310     if (ctxt != NULL) {
311         input = ctxt->input;
312         if ((input != NULL) && (input->filename == NULL) &&
313             (ctxt->inputNr > 1)) {
314             cur = input;
315             input = ctxt->inputTab[ctxt->inputNr - 2];
316         }
317         if (input != NULL) {
318             if (input->filename)
319                 channel(data, "%s:%d: ", input->filename, input->line);
320             else if ((line != 0) && (domain == XML_FROM_PARSER))
321                 channel(data, "Entity: line %d: ", input->line);
322         }
323     } else {
324         if (file != NULL)
325             channel(data, "%s:%d: ", file, line);
326         else if ((line != 0) &&
327 	         ((domain == XML_FROM_PARSER) || (domain == XML_FROM_SCHEMASV)||
328 		  (domain == XML_FROM_SCHEMASP)||(domain == XML_FROM_DTD) ||
329 		  (domain == XML_FROM_RELAXNGP)||(domain == XML_FROM_RELAXNGV)))
330             channel(data, "Entity: line %d: ", line);
331     }
332     if (name != NULL) {
333         channel(data, "element %s: ", name);
334     }
335     switch (domain) {
336         case XML_FROM_PARSER:
337             channel(data, "parser ");
338             break;
339         case XML_FROM_NAMESPACE:
340             channel(data, "namespace ");
341             break;
342         case XML_FROM_DTD:
343         case XML_FROM_VALID:
344             channel(data, "validity ");
345             break;
346         case XML_FROM_HTML:
347             channel(data, "HTML parser ");
348             break;
349         case XML_FROM_MEMORY:
350             channel(data, "memory ");
351             break;
352         case XML_FROM_OUTPUT:
353             channel(data, "output ");
354             break;
355         case XML_FROM_IO:
356             channel(data, "I/O ");
357             break;
358         case XML_FROM_XINCLUDE:
359             channel(data, "XInclude ");
360             break;
361         case XML_FROM_XPATH:
362             channel(data, "XPath ");
363             break;
364         case XML_FROM_XPOINTER:
365             channel(data, "parser ");
366             break;
367         case XML_FROM_REGEXP:
368             channel(data, "regexp ");
369             break;
370         case XML_FROM_MODULE:
371             channel(data, "module ");
372             break;
373         case XML_FROM_SCHEMASV:
374             channel(data, "Schemas validity ");
375             break;
376         case XML_FROM_SCHEMASP:
377             channel(data, "Schemas parser ");
378             break;
379         case XML_FROM_RELAXNGP:
380             channel(data, "Relax-NG parser ");
381             break;
382         case XML_FROM_RELAXNGV:
383             channel(data, "Relax-NG validity ");
384             break;
385         case XML_FROM_CATALOG:
386             channel(data, "Catalog ");
387             break;
388         case XML_FROM_C14N:
389             channel(data, "C14N ");
390             break;
391         case XML_FROM_XSLT:
392             channel(data, "XSLT ");
393             break;
394         case XML_FROM_I18N:
395             channel(data, "encoding ");
396             break;
397         case XML_FROM_SCHEMATRONV:
398             channel(data, "schematron ");
399             break;
400         case XML_FROM_BUFFER:
401             channel(data, "internal buffer ");
402             break;
403         case XML_FROM_URI:
404             channel(data, "URI ");
405             break;
406         default:
407             break;
408     }
409     switch (level) {
410         case XML_ERR_NONE:
411             channel(data, ": ");
412             break;
413         case XML_ERR_WARNING:
414             channel(data, "warning : ");
415             break;
416         case XML_ERR_ERROR:
417             channel(data, "error : ");
418             break;
419         case XML_ERR_FATAL:
420             channel(data, "error : ");
421             break;
422     }
423     if (str != NULL) {
424         int len;
425 	len = xmlStrlen((const xmlChar *)str);
426 	if ((len > 0) && (str[len - 1] != '\n'))
427 	    channel(data, "%s\n", str);
428 	else
429 	    channel(data, "%s", str);
430     } else {
431         channel(data, "%s\n", "out of memory error");
432     }
433 
434     if (ctxt != NULL) {
435         xmlParserPrintFileContextInternal(input, channel, data);
436         if (cur != NULL) {
437             if (cur->filename)
438                 channel(data, "%s:%d: \n", cur->filename, cur->line);
439             else if ((line != 0) && (domain == XML_FROM_PARSER))
440                 channel(data, "Entity: line %d: \n", cur->line);
441             xmlParserPrintFileContextInternal(cur, channel, data);
442         }
443     }
444     if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
445         (err->int1 < 100) &&
446 	(err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
447 	xmlChar buf[150];
448 	int i;
449 
450 	channel(data, "%s\n", err->str1);
451 	for (i=0;i < err->int1;i++)
452 	     buf[i] = ' ';
453 	buf[i++] = '^';
454 	buf[i] = 0;
455 	channel(data, "%s\n", buf);
456     }
457 }
458 
459 /**
460  * __xmlRaiseError:
461  * @schannel: the structured callback channel
462  * @channel: the old callback channel
463  * @data: the callback data
464  * @ctx: the parser context or NULL
465  * @ctx: the parser context or NULL
466  * @domain: the domain for the error
467  * @code: the code for the error
468  * @level: the xmlErrorLevel for the error
469  * @file: the file source of the error (or NULL)
470  * @line: the line of the error or 0 if N/A
471  * @str1: extra string info
472  * @str2: extra string info
473  * @str3: extra string info
474  * @int1: extra int info
475  * @col: column number of the error or 0 if N/A
476  * @msg:  the message to display/transmit
477  * @...:  extra parameters for the message display
478  *
479  * Update the appropriate global or contextual error structure,
480  * then forward the error message down the parser or generic
481  * error callback handler
482  */
483 void XMLCDECL
__xmlRaiseError(xmlStructuredErrorFunc schannel,xmlGenericErrorFunc channel,void * data,void * ctx,void * nod,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,...)484 __xmlRaiseError(xmlStructuredErrorFunc schannel,
485               xmlGenericErrorFunc channel, void *data, void *ctx,
486               void *nod, int domain, int code, xmlErrorLevel level,
487               const char *file, int line, const char *str1,
488               const char *str2, const char *str3, int int1, int col,
489 	      const char *msg, ...)
490 {
491     xmlParserCtxtPtr ctxt = NULL;
492     xmlNodePtr node = (xmlNodePtr) nod;
493     char *str = NULL;
494     xmlParserInputPtr input = NULL;
495     xmlErrorPtr to = &xmlLastError;
496     xmlNodePtr baseptr = NULL;
497 
498     if (code == XML_ERR_OK)
499         return;
500     if ((xmlGetWarningsDefaultValue == 0) && (level == XML_ERR_WARNING))
501         return;
502     if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
503         (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
504 	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
505 	ctxt = (xmlParserCtxtPtr) ctx;
506 	if ((schannel == NULL) && (ctxt != NULL) && (ctxt->sax != NULL) &&
507 	    (ctxt->sax->initialized == XML_SAX2_MAGIC) &&
508 	    (ctxt->sax->serror != NULL)) {
509 	    schannel = ctxt->sax->serror;
510 	    data = ctxt->userData;
511 	}
512     }
513     /*
514      * Check if structured error handler set
515      */
516     if (schannel == NULL) {
517 	schannel = xmlStructuredError;
518 	/*
519 	 * if user has defined handler, change data ptr to user's choice
520 	 */
521 	if (schannel != NULL)
522 	    data = xmlStructuredErrorContext;
523     }
524     /*
525      * Formatting the message
526      */
527     if (msg == NULL) {
528         str = (char *) xmlStrdup(BAD_CAST "No error message provided");
529     } else {
530         XML_GET_VAR_STR(msg, str);
531     }
532 
533     /*
534      * specific processing if a parser context is provided
535      */
536     if (ctxt != NULL) {
537         if (file == NULL) {
538             input = ctxt->input;
539             if ((input != NULL) && (input->filename == NULL) &&
540                 (ctxt->inputNr > 1)) {
541                 input = ctxt->inputTab[ctxt->inputNr - 2];
542             }
543             if (input != NULL) {
544                 file = input->filename;
545                 line = input->line;
546                 col = input->col;
547             }
548         }
549         to = &ctxt->lastError;
550     } else if ((node != NULL) && (file == NULL)) {
551 	int i;
552 
553 	if ((node->doc != NULL) && (node->doc->URL != NULL)) {
554 	    baseptr = node;
555 /*	    file = (const char *) node->doc->URL; */
556 	}
557 	for (i = 0;
558 	     ((i < 10) && (node != NULL) && (node->type != XML_ELEMENT_NODE));
559 	     i++)
560 	     node = node->parent;
561         if ((baseptr == NULL) && (node != NULL) &&
562 	    (node->doc != NULL) && (node->doc->URL != NULL))
563 	    baseptr = node;
564 
565 	if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
566 	    line = node->line;
567 	if ((line == 0) || (line == 65535))
568 	    line = xmlGetLineNo(node);
569     }
570 
571     /*
572      * Save the information about the error
573      */
574     xmlResetError(to);
575     to->domain = domain;
576     to->code = code;
577     to->message = str;
578     to->level = level;
579     if (file != NULL)
580         to->file = (char *) xmlStrdup((const xmlChar *) file);
581     else if (baseptr != NULL) {
582 #ifdef LIBXML_XINCLUDE_ENABLED
583 	/*
584 	 * We check if the error is within an XInclude section and,
585 	 * if so, attempt to print out the href of the XInclude instead
586 	 * of the usual "base" (doc->URL) for the node (bug 152623).
587 	 */
588         xmlNodePtr prev = baseptr;
589 	int inclcount = 0;
590 	while (prev != NULL) {
591 	    if (prev->prev == NULL)
592 	        prev = prev->parent;
593 	    else {
594 	        prev = prev->prev;
595 		if (prev->type == XML_XINCLUDE_START) {
596 		    if (--inclcount < 0)
597 		        break;
598 		} else if (prev->type == XML_XINCLUDE_END)
599 		    inclcount++;
600 	    }
601 	}
602 	if (prev != NULL) {
603 	    if (prev->type == XML_XINCLUDE_START) {
604 		prev->type = XML_ELEMENT_NODE;
605 		to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
606 		prev->type = XML_XINCLUDE_START;
607 	    } else {
608 		to->file = (char *) xmlGetProp(prev, BAD_CAST "href");
609 	    }
610 	} else
611 #endif
612 	    to->file = (char *) xmlStrdup(baseptr->doc->URL);
613 	if ((to->file == NULL) && (node != NULL) && (node->doc != NULL)) {
614 	    to->file = (char *) xmlStrdup(node->doc->URL);
615 	}
616     }
617     to->line = line;
618     if (str1 != NULL)
619         to->str1 = (char *) xmlStrdup((const xmlChar *) str1);
620     if (str2 != NULL)
621         to->str2 = (char *) xmlStrdup((const xmlChar *) str2);
622     if (str3 != NULL)
623         to->str3 = (char *) xmlStrdup((const xmlChar *) str3);
624     to->int1 = int1;
625     to->int2 = col;
626     to->node = node;
627     to->ctxt = ctx;
628 
629     if (to != &xmlLastError)
630         xmlCopyError(to,&xmlLastError);
631 
632     if (schannel != NULL) {
633 	schannel(data, to);
634 	return;
635     }
636 
637     /*
638      * Find the callback channel if channel param is NULL
639      */
640     if ((ctxt != NULL) && (channel == NULL) &&
641         (xmlStructuredError == NULL) && (ctxt->sax != NULL)) {
642         if (level == XML_ERR_WARNING)
643 	    channel = ctxt->sax->warning;
644         else
645 	    channel = ctxt->sax->error;
646 	data = ctxt->userData;
647     } else if (channel == NULL) {
648 	channel = xmlGenericError;
649 	if (ctxt != NULL) {
650 	    data = ctxt;
651 	} else {
652 	    data = xmlGenericErrorContext;
653 	}
654     }
655     if (channel == NULL)
656         return;
657 
658     if ((channel == xmlParserError) ||
659         (channel == xmlParserWarning) ||
660 	(channel == xmlParserValidityError) ||
661 	(channel == xmlParserValidityWarning))
662 	xmlReportError(to, ctxt, str, NULL, NULL);
663     else if ((channel == (xmlGenericErrorFunc) fprintf) ||
664              (channel == xmlGenericErrorDefaultFunc))
665 	xmlReportError(to, ctxt, str, channel, data);
666     else
667 	channel(data, "%s", str);
668 }
669 
670 /**
671  * __xmlSimpleError:
672  * @domain: where the error comes from
673  * @code: the error code
674  * @node: the context node
675  * @extra:  extra informations
676  *
677  * Handle an out of memory condition
678  */
679 void
__xmlSimpleError(int domain,int code,xmlNodePtr node,const char * msg,const char * extra)680 __xmlSimpleError(int domain, int code, xmlNodePtr node,
681                  const char *msg, const char *extra)
682 {
683 
684     if (code == XML_ERR_NO_MEMORY) {
685 	if (extra)
686 	    __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
687 			    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, extra,
688 			    NULL, NULL, 0, 0,
689 			    "Memory allocation failed : %s\n", extra);
690 	else
691 	    __xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
692 			    XML_ERR_NO_MEMORY, XML_ERR_FATAL, NULL, 0, NULL,
693 			    NULL, NULL, 0, 0, "Memory allocation failed\n");
694     } else {
695 	__xmlRaiseError(NULL, NULL, NULL, NULL, node, domain,
696 			code, XML_ERR_ERROR, NULL, 0, extra,
697 			NULL, NULL, 0, 0, msg, extra);
698     }
699 }
700 /**
701  * xmlParserError:
702  * @ctx:  an XML parser context
703  * @msg:  the message to display/transmit
704  * @...:  extra parameters for the message display
705  *
706  * Display and format an error messages, gives file, line, position and
707  * extra parameters.
708  */
709 void XMLCDECL
xmlParserError(void * ctx,const char * msg,...)710 xmlParserError(void *ctx, const char *msg, ...)
711 {
712     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
713     xmlParserInputPtr input = NULL;
714     xmlParserInputPtr cur = NULL;
715     char * str;
716 
717     if (ctxt != NULL) {
718 	input = ctxt->input;
719 	if ((input != NULL) && (input->filename == NULL) &&
720 	    (ctxt->inputNr > 1)) {
721 	    cur = input;
722 	    input = ctxt->inputTab[ctxt->inputNr - 2];
723 	}
724 	xmlParserPrintFileInfo(input);
725     }
726 
727     xmlGenericError(xmlGenericErrorContext, "error: ");
728     XML_GET_VAR_STR(msg, str);
729     xmlGenericError(xmlGenericErrorContext, "%s", str);
730     if (str != NULL)
731 	xmlFree(str);
732 
733     if (ctxt != NULL) {
734 	xmlParserPrintFileContext(input);
735 	if (cur != NULL) {
736 	    xmlParserPrintFileInfo(cur);
737 	    xmlGenericError(xmlGenericErrorContext, "\n");
738 	    xmlParserPrintFileContext(cur);
739 	}
740     }
741 }
742 
743 /**
744  * xmlParserWarning:
745  * @ctx:  an XML parser context
746  * @msg:  the message to display/transmit
747  * @...:  extra parameters for the message display
748  *
749  * Display and format a warning messages, gives file, line, position and
750  * extra parameters.
751  */
752 void XMLCDECL
xmlParserWarning(void * ctx,const char * msg,...)753 xmlParserWarning(void *ctx, const char *msg, ...)
754 {
755     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
756     xmlParserInputPtr input = NULL;
757     xmlParserInputPtr cur = NULL;
758     char * str;
759 
760     if (ctxt != NULL) {
761 	input = ctxt->input;
762 	if ((input != NULL) && (input->filename == NULL) &&
763 	    (ctxt->inputNr > 1)) {
764 	    cur = input;
765 	    input = ctxt->inputTab[ctxt->inputNr - 2];
766 	}
767 	xmlParserPrintFileInfo(input);
768     }
769 
770     xmlGenericError(xmlGenericErrorContext, "warning: ");
771     XML_GET_VAR_STR(msg, str);
772     xmlGenericError(xmlGenericErrorContext, "%s", str);
773     if (str != NULL)
774 	xmlFree(str);
775 
776     if (ctxt != NULL) {
777 	xmlParserPrintFileContext(input);
778 	if (cur != NULL) {
779 	    xmlParserPrintFileInfo(cur);
780 	    xmlGenericError(xmlGenericErrorContext, "\n");
781 	    xmlParserPrintFileContext(cur);
782 	}
783     }
784 }
785 
786 /************************************************************************
787  *									*
788  *			Handling of validation errors			*
789  *									*
790  ************************************************************************/
791 
792 /**
793  * xmlParserValidityError:
794  * @ctx:  an XML parser context
795  * @msg:  the message to display/transmit
796  * @...:  extra parameters for the message display
797  *
798  * Display and format an validity error messages, gives file,
799  * line, position and extra parameters.
800  */
801 void XMLCDECL
xmlParserValidityError(void * ctx,const char * msg,...)802 xmlParserValidityError(void *ctx, const char *msg, ...)
803 {
804     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
805     xmlParserInputPtr input = NULL;
806     char * str;
807     int len = xmlStrlen((const xmlChar *) msg);
808     static int had_info = 0;
809 
810     if ((len > 1) && (msg[len - 2] != ':')) {
811 	if (ctxt != NULL) {
812 	    input = ctxt->input;
813 	    if ((input->filename == NULL) && (ctxt->inputNr > 1))
814 		input = ctxt->inputTab[ctxt->inputNr - 2];
815 
816 	    if (had_info == 0) {
817 		xmlParserPrintFileInfo(input);
818 	    }
819 	}
820 	xmlGenericError(xmlGenericErrorContext, "validity error: ");
821 	had_info = 0;
822     } else {
823 	had_info = 1;
824     }
825 
826     XML_GET_VAR_STR(msg, str);
827     xmlGenericError(xmlGenericErrorContext, "%s", str);
828     if (str != NULL)
829 	xmlFree(str);
830 
831     if ((ctxt != NULL) && (input != NULL)) {
832 	xmlParserPrintFileContext(input);
833     }
834 }
835 
836 /**
837  * xmlParserValidityWarning:
838  * @ctx:  an XML parser context
839  * @msg:  the message to display/transmit
840  * @...:  extra parameters for the message display
841  *
842  * Display and format a validity warning messages, gives file, line,
843  * position and extra parameters.
844  */
845 void XMLCDECL
xmlParserValidityWarning(void * ctx,const char * msg,...)846 xmlParserValidityWarning(void *ctx, const char *msg, ...)
847 {
848     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
849     xmlParserInputPtr input = NULL;
850     char * str;
851     int len = xmlStrlen((const xmlChar *) msg);
852 
853     if ((ctxt != NULL) && (len != 0) && (msg[len - 1] != ':')) {
854 	input = ctxt->input;
855 	if ((input->filename == NULL) && (ctxt->inputNr > 1))
856 	    input = ctxt->inputTab[ctxt->inputNr - 2];
857 
858 	xmlParserPrintFileInfo(input);
859     }
860 
861     xmlGenericError(xmlGenericErrorContext, "validity warning: ");
862     XML_GET_VAR_STR(msg, str);
863     xmlGenericError(xmlGenericErrorContext, "%s", str);
864     if (str != NULL)
865 	xmlFree(str);
866 
867     if (ctxt != NULL) {
868 	xmlParserPrintFileContext(input);
869     }
870 }
871 
872 
873 /************************************************************************
874  *									*
875  *			Extended Error Handling				*
876  *									*
877  ************************************************************************/
878 
879 /**
880  * xmlGetLastError:
881  *
882  * Get the last global error registered. This is per thread if compiled
883  * with thread support.
884  *
885  * Returns NULL if no error occurred or a pointer to the error
886  */
887 xmlErrorPtr
xmlGetLastError(void)888 xmlGetLastError(void)
889 {
890     if (xmlLastError.code == XML_ERR_OK)
891         return (NULL);
892     return (&xmlLastError);
893 }
894 
895 /**
896  * xmlResetError:
897  * @err: pointer to the error.
898  *
899  * Cleanup the error.
900  */
901 void
xmlResetError(xmlErrorPtr err)902 xmlResetError(xmlErrorPtr err)
903 {
904     if (err == NULL)
905         return;
906     if (err->code == XML_ERR_OK)
907         return;
908     if (err->message != NULL)
909         xmlFree(err->message);
910     if (err->file != NULL)
911         xmlFree(err->file);
912     if (err->str1 != NULL)
913         xmlFree(err->str1);
914     if (err->str2 != NULL)
915         xmlFree(err->str2);
916     if (err->str3 != NULL)
917         xmlFree(err->str3);
918     memset(err, 0, sizeof(xmlError));
919     err->code = XML_ERR_OK;
920 }
921 
922 /**
923  * xmlResetLastError:
924  *
925  * Cleanup the last global error registered. For parsing error
926  * this does not change the well-formedness result.
927  */
928 void
xmlResetLastError(void)929 xmlResetLastError(void)
930 {
931     if (xmlLastError.code == XML_ERR_OK)
932         return;
933     xmlResetError(&xmlLastError);
934 }
935 
936 /**
937  * xmlCtxtGetLastError:
938  * @ctx:  an XML parser context
939  *
940  * Get the last parsing error registered.
941  *
942  * Returns NULL if no error occurred or a pointer to the error
943  */
944 xmlErrorPtr
xmlCtxtGetLastError(void * ctx)945 xmlCtxtGetLastError(void *ctx)
946 {
947     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
948 
949     if (ctxt == NULL)
950         return (NULL);
951     if (ctxt->lastError.code == XML_ERR_OK)
952         return (NULL);
953     return (&ctxt->lastError);
954 }
955 
956 /**
957  * xmlCtxtResetLastError:
958  * @ctx:  an XML parser context
959  *
960  * Cleanup the last global error registered. For parsing error
961  * this does not change the well-formedness result.
962  */
963 void
xmlCtxtResetLastError(void * ctx)964 xmlCtxtResetLastError(void *ctx)
965 {
966     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
967 
968     if (ctxt == NULL)
969         return;
970     ctxt->errNo = XML_ERR_OK;
971     if (ctxt->lastError.code == XML_ERR_OK)
972         return;
973     xmlResetError(&ctxt->lastError);
974 }
975 
976 /**
977  * xmlCopyError:
978  * @from:  a source error
979  * @to:  a target error
980  *
981  * Save the original error to the new place.
982  *
983  * Returns 0 in case of success and -1 in case of error.
984  */
985 int
xmlCopyError(xmlErrorPtr from,xmlErrorPtr to)986 xmlCopyError(xmlErrorPtr from, xmlErrorPtr to) {
987     char *message, *file, *str1, *str2, *str3;
988 
989     if ((from == NULL) || (to == NULL))
990         return(-1);
991 
992     message = (char *) xmlStrdup((xmlChar *) from->message);
993     file = (char *) xmlStrdup ((xmlChar *) from->file);
994     str1 = (char *) xmlStrdup ((xmlChar *) from->str1);
995     str2 = (char *) xmlStrdup ((xmlChar *) from->str2);
996     str3 = (char *) xmlStrdup ((xmlChar *) from->str3);
997 
998     if (to->message != NULL)
999         xmlFree(to->message);
1000     if (to->file != NULL)
1001         xmlFree(to->file);
1002     if (to->str1 != NULL)
1003         xmlFree(to->str1);
1004     if (to->str2 != NULL)
1005         xmlFree(to->str2);
1006     if (to->str3 != NULL)
1007         xmlFree(to->str3);
1008     to->domain = from->domain;
1009     to->code = from->code;
1010     to->level = from->level;
1011     to->line = from->line;
1012     to->node = from->node;
1013     to->int1 = from->int1;
1014     to->int2 = from->int2;
1015     to->node = from->node;
1016     to->ctxt = from->ctxt;
1017     to->message = message;
1018     to->file = file;
1019     to->str1 = str1;
1020     to->str2 = str2;
1021     to->str3 = str3;
1022 
1023     return 0;
1024 }
1025 
1026 #define bottom_error
1027 #include "elfgcchack.h"
1028