• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * xmllint.c : a small tester program for XML input.
3  *
4  * See Copyright for the status of this software.
5  *
6  * daniel@veillard.com
7  */
8 
9 #include "libxml.h"
10 
11 #include <string.h>
12 #include <stdarg.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <limits.h>
17 #include <fcntl.h>
18 
19 #ifdef _WIN32
20   #include <io.h>
21   #include <sys/timeb.h>
22 #else
23   #include <sys/time.h>
24   #include <unistd.h>
25 #endif
26 
27 #if HAVE_DECL_MMAP
28   #include <sys/mman.h>
29   #include <sys/stat.h>
30   /* seems needed for Solaris */
31   #ifndef MAP_FAILED
32     #define MAP_FAILED ((void *) -1)
33   #endif
34 #endif
35 
36 #include <libxml/xmlmemory.h>
37 #include <libxml/parser.h>
38 #include <libxml/parserInternals.h>
39 #include <libxml/HTMLparser.h>
40 #include <libxml/HTMLtree.h>
41 #include <libxml/tree.h>
42 #include <libxml/xpath.h>
43 #include <libxml/xpathInternals.h>
44 #include <libxml/debugXML.h>
45 #include <libxml/xmlerror.h>
46 #ifdef LIBXML_XINCLUDE_ENABLED
47 #include <libxml/xinclude.h>
48 #endif
49 #ifdef LIBXML_CATALOG_ENABLED
50 #include <libxml/catalog.h>
51 #endif
52 #include <libxml/xmlreader.h>
53 #ifdef LIBXML_SCHEMATRON_ENABLED
54 #include <libxml/schematron.h>
55 #endif
56 #ifdef LIBXML_SCHEMAS_ENABLED
57 #include <libxml/relaxng.h>
58 #include <libxml/xmlschemas.h>
59 #endif
60 #ifdef LIBXML_PATTERN_ENABLED
61 #include <libxml/pattern.h>
62 #endif
63 #ifdef LIBXML_C14N_ENABLED
64 #include <libxml/c14n.h>
65 #endif
66 #ifdef LIBXML_OUTPUT_ENABLED
67 #include <libxml/xmlsave.h>
68 #endif
69 
70 #include "private/lint.h"
71 
72 #ifndef STDIN_FILENO
73   #define STDIN_FILENO 0
74 #endif
75 #ifndef STDOUT_FILENO
76   #define STDOUT_FILENO 1
77 #endif
78 
79 #define MAX_PATHS 64
80 
81 #ifdef _WIN32
82   #define PATH_SEPARATOR ';'
83 #else
84   #define PATH_SEPARATOR ':'
85 #endif
86 
87 #define HTML_BUF_SIZE 50000
88 
89 /* Internal parser option */
90 #define XML_PARSE_UNZIP     (1 << 24)
91 
92 typedef enum {
93     XMLLINT_RETURN_OK = 0,	    /* No error */
94     XMLLINT_ERR_UNCLASS = 1,	    /* Unclassified */
95     XMLLINT_ERR_DTD = 2,	    /* Error in DTD */
96     XMLLINT_ERR_VALID = 3,	    /* Validation error */
97     XMLLINT_ERR_RDFILE = 4,	    /* CtxtReadFile error */
98     XMLLINT_ERR_SCHEMACOMP = 5,	    /* Schema compilation */
99     XMLLINT_ERR_OUT = 6,	    /* Error writing output */
100     XMLLINT_ERR_SCHEMAPAT = 7,	    /* Error in schema pattern */
101     /*XMLLINT_ERR_RDREGIS = 8,*/
102     XMLLINT_ERR_MEM = 9,	    /* Out of memory error */
103     XMLLINT_ERR_XPATH = 10,	    /* XPath evaluation error */
104     XMLLINT_ERR_XPATH_EMPTY = 11    /* XPath result is empty */
105 } xmllintReturnCode;
106 
107 #ifdef _WIN32
108 typedef __time64_t xmlSeconds;
109 #else
110 typedef time_t xmlSeconds;
111 #endif
112 
113 typedef struct {
114    xmlSeconds sec;
115    int usec;
116 } xmlTime;
117 
118 typedef struct {
119     FILE *errStream;
120     xmlParserCtxtPtr ctxt;
121     xmlResourceLoader defaultResourceLoader;
122 
123     int version;
124     int maxmem;
125     int nowrap;
126     int sax;
127     int callbacks;
128     int shell;
129 #ifdef LIBXML_DEBUG_ENABLED
130     int debugent;
131 #endif
132     int debug;
133     int copy;
134     int noout;
135 #ifdef LIBXML_OUTPUT_ENABLED
136     const char *output;
137     int format;
138     const char *encoding;
139     int compress;
140 #endif /* LIBXML_OUTPUT_ENABLED */
141 #ifdef LIBXML_VALID_ENABLED
142     int postvalid;
143     const char *dtdvalid;
144     const char *dtdvalidfpi;
145     int insert;
146 #endif
147 #ifdef LIBXML_SCHEMAS_ENABLED
148     const char *relaxng;
149     xmlRelaxNGPtr relaxngschemas;
150     const char *schema;
151     xmlSchemaPtr wxschemas;
152 #endif
153 #ifdef LIBXML_SCHEMATRON_ENABLED
154     const char *schematron;
155     xmlSchematronPtr wxschematron;
156 #endif
157     int repeat;
158 #if defined(LIBXML_HTML_ENABLED)
159     int html;
160     int xmlout;
161 #endif
162     int htmlout;
163 #ifdef LIBXML_PUSH_ENABLED
164     int push;
165 #endif /* LIBXML_PUSH_ENABLED */
166 #if HAVE_DECL_MMAP
167     int memory;
168     char *memoryData;
169     size_t memorySize;
170 #endif
171     int testIO;
172 #ifdef LIBXML_XINCLUDE_ENABLED
173     int xinclude;
174 #endif
175     xmllintReturnCode progresult;
176     int quiet;
177     int timing;
178     int generate;
179     int dropdtd;
180 #ifdef LIBXML_C14N_ENABLED
181     int canonical;
182     int canonical_11;
183     int exc_canonical;
184 #endif
185 #ifdef LIBXML_READER_ENABLED
186     int stream;
187     int walker;
188 #ifdef LIBXML_PATTERN_ENABLED
189     const char *pattern;
190     xmlPatternPtr patternc;
191     xmlStreamCtxtPtr patstream;
192 #endif
193 #endif /* LIBXML_READER_ENABLED */
194 #ifdef LIBXML_XPATH_ENABLED
195     const char *xpathquery;
196 #endif
197 #ifdef LIBXML_CATALOG_ENABLED
198     int catalogs;
199     int nocatalogs;
200 #endif
201     int options;
202     unsigned maxAmpl;
203 
204     xmlChar *paths[MAX_PATHS + 1];
205     int nbpaths;
206     int load_trace;
207 
208     char *htmlBuf;
209     int htmlBufLen;
210 
211     xmlTime begin, end;
212 } xmllintState;
213 
214 static int xmllintMaxmem;
215 static int xmllintMaxmemReached;
216 static int xmllintOom;
217 
218 /************************************************************************
219  *									*
220  *		 Entity loading control and customization.		*
221  *									*
222  ************************************************************************/
223 
224 static void
parsePath(xmllintState * lint,const xmlChar * path)225 parsePath(xmllintState *lint, const xmlChar *path) {
226     const xmlChar *cur;
227 
228     if (path == NULL)
229 	return;
230     while (*path != 0) {
231 	if (lint->nbpaths >= MAX_PATHS) {
232 	    fprintf(lint->errStream, "MAX_PATHS reached: too many paths\n");
233             lint->progresult = XMLLINT_ERR_UNCLASS;
234 	    return;
235 	}
236 	cur = path;
237 	while ((*cur == ' ') || (*cur == PATH_SEPARATOR))
238 	    cur++;
239 	path = cur;
240 	while ((*cur != 0) && (*cur != ' ') && (*cur != PATH_SEPARATOR))
241 	    cur++;
242 	if (cur != path) {
243 	    lint->paths[lint->nbpaths] = xmlStrndup(path, cur - path);
244 	    if (lint->paths[lint->nbpaths] != NULL)
245 		lint->nbpaths++;
246 	    path = cur;
247 	}
248     }
249 }
250 
251 static int
xmllintResourceLoader(void * ctxt,const char * URL,const char * ID,xmlResourceType type,int flags,xmlParserInputPtr * out)252 xmllintResourceLoader(void *ctxt, const char *URL,
253                       const char *ID, xmlResourceType type, int flags,
254 		      xmlParserInputPtr *out) {
255     xmllintState *lint = ctxt;
256     int code;
257     int i;
258     const char *lastsegment = URL;
259     const char *iter = URL;
260 
261     if ((lint->nbpaths > 0) && (iter != NULL)) {
262 	while (*iter != 0) {
263 	    if (*iter == '/')
264 		lastsegment = iter + 1;
265 	    iter++;
266 	}
267     }
268 
269     if (lint->defaultResourceLoader != NULL)
270         code = lint->defaultResourceLoader(NULL, URL, ID, type, flags, out);
271     else
272         code = xmlNewInputFromUrl(URL, flags, out);
273     if (code != XML_IO_ENOENT) {
274         if ((lint->load_trace) && (code == XML_ERR_OK)) {
275             fprintf(lint->errStream, "Loaded URL=\"%s\" ID=\"%s\"\n",
276                     URL, ID ? ID : "(null)");
277         }
278         return(code);
279     }
280 
281     for (i = 0; i < lint->nbpaths; i++) {
282 	xmlChar *newURL;
283 
284 	newURL = xmlStrdup((const xmlChar *) lint->paths[i]);
285 	newURL = xmlStrcat(newURL, (const xmlChar *) "/");
286 	newURL = xmlStrcat(newURL, (const xmlChar *) lastsegment);
287 	if (newURL != NULL) {
288             if (lint->defaultResourceLoader != NULL)
289                 code = lint->defaultResourceLoader(NULL, (const char *) newURL,
290                                                    ID, type, flags, out);
291             else
292                 code = xmlNewInputFromUrl((const char *) newURL, flags, out);
293             if (code != XML_IO_ENOENT) {
294                 if ((lint->load_trace) && (code == XML_ERR_OK)) {
295                     fprintf(lint->errStream, "Loaded URL=\"%s\" ID=\"%s\"\n",
296                             newURL, ID ? ID : "(null)");
297                 }
298 	        xmlFree(newURL);
299                 return(code);
300             }
301 	    xmlFree(newURL);
302 	}
303     }
304 
305     return(XML_IO_ENOENT);
306 }
307 
308 /************************************************************************
309  *									*
310  *		 	Core parsing functions				*
311  *									*
312  ************************************************************************/
313 
314 static int
myRead(void * f,char * buf,int len)315 myRead(void *f, char *buf, int len) {
316     return(fread(buf, 1, len, (FILE *) f));
317 }
318 
319 static int
myClose(void * context)320 myClose(void *context) {
321     FILE *f = (FILE *) context;
322     if (f == stdin)
323         return(0);
324     return(fclose(f));
325 }
326 
327 static xmlDocPtr
parseXml(xmllintState * lint,const char * filename)328 parseXml(xmllintState *lint, const char *filename) {
329     xmlParserCtxtPtr ctxt = lint->ctxt;
330     xmlDocPtr doc;
331 
332 #ifdef LIBXML_PUSH_ENABLED
333     if (lint->push) {
334         FILE *f;
335         int res;
336         char chars[4096];
337 
338         if ((filename[0] == '-') && (filename[1] == 0)) {
339             f = stdin;
340         } else {
341             f = fopen(filename, "rb");
342             if (f == NULL) {
343                 fprintf(lint->errStream, "Can't open %s\n", filename);
344                 lint->progresult = XMLLINT_ERR_RDFILE;
345                 return(NULL);
346             }
347         }
348 
349         while ((res = fread(chars, 1, 4096, f)) > 0) {
350             xmlParseChunk(ctxt, chars, res, 0);
351         }
352         xmlParseChunk(ctxt, chars, 0, 1);
353 
354         doc = ctxt->myDoc;
355         ctxt->myDoc = NULL;
356         if (f != stdin)
357             fclose(f);
358 
359         /*
360          * The push parser leaves non-wellformed documents
361          * in ctxt->myDoc.
362          */
363         if (!ctxt->wellFormed) {
364             xmlFreeDoc(doc);
365             doc = NULL;
366         }
367 
368         return(doc);
369     }
370 #endif /* LIBXML_PUSH_ENABLED */
371 
372 #if HAVE_DECL_MMAP
373     if (lint->memory) {
374         xmlParserInputPtr input;
375 
376         input = xmlNewInputFromMemory(filename,
377                                       lint->memoryData, lint->memorySize,
378                                       XML_INPUT_BUF_STATIC |
379                                       XML_INPUT_BUF_ZERO_TERMINATED);
380         if (input == NULL) {
381             lint->progresult = XMLLINT_ERR_MEM;
382             return(NULL);
383         }
384         doc = xmlCtxtParseDocument(ctxt, input);
385         return(doc);
386     }
387 #endif
388 
389     if (lint->testIO) {
390         FILE *f;
391 
392         if ((filename[0] == '-') && (filename[1] == 0)) {
393             f = stdin;
394         } else {
395             f = fopen(filename, "rb");
396             if (f == NULL) {
397                 fprintf(lint->errStream, "Can't open %s\n", filename);
398                 lint->progresult = XMLLINT_ERR_RDFILE;
399                 return(NULL);
400             }
401         }
402 
403         doc = xmlCtxtReadIO(ctxt, myRead, myClose, f, filename, NULL,
404                             lint->options);
405     } else {
406         if (strcmp(filename, "-") == 0)
407             doc = xmlCtxtReadFd(ctxt, STDIN_FILENO, "-", NULL,
408                                 lint->options | XML_PARSE_UNZIP);
409         else
410             doc = xmlCtxtReadFile(ctxt, filename, NULL,
411                                   lint->options | XML_PARSE_UNZIP);
412     }
413 
414     return(doc);
415 }
416 
417 #ifdef LIBXML_HTML_ENABLED
418 static xmlDocPtr
parseHtml(xmllintState * lint,const char * filename)419 parseHtml(xmllintState *lint, const char *filename) {
420     xmlParserCtxtPtr ctxt = lint->ctxt;
421     xmlDocPtr doc;
422 
423 #ifdef LIBXML_PUSH_ENABLED
424     if (lint->push) {
425         FILE *f;
426         int res;
427         char chars[4096];
428 
429         if ((filename[0] == '-') && (filename[1] == 0)) {
430             f = stdin;
431         } else {
432 	    f = fopen(filename, "rb");
433             if (f == NULL) {
434                 fprintf(lint->errStream, "Can't open %s\n", filename);
435                 lint->progresult = XMLLINT_ERR_RDFILE;
436                 return(NULL);
437             }
438         }
439 
440         while ((res = fread(chars, 1, 4096, f)) > 0) {
441             htmlParseChunk(ctxt, chars, res, 0);
442         }
443         htmlParseChunk(ctxt, chars, 0, 1);
444         doc = ctxt->myDoc;
445         ctxt->myDoc = NULL;
446         if (f != stdin)
447             fclose(f);
448 
449         return(doc);
450     }
451 #endif /* LIBXML_PUSH_ENABLED */
452 
453 #if HAVE_DECL_MMAP
454     if (lint->memory) {
455         xmlParserInputPtr input;
456 
457         input = xmlNewInputFromMemory(filename,
458                                       lint->memoryData, lint->memorySize,
459                                       XML_INPUT_BUF_STATIC |
460                                       XML_INPUT_BUF_ZERO_TERMINATED);
461         if (input == NULL) {
462             lint->progresult = XMLLINT_ERR_MEM;
463             return(NULL);
464         }
465         doc = htmlCtxtParseDocument(ctxt, input);
466         return(doc);
467     }
468 #endif
469 
470     if (strcmp(filename, "-") == 0)
471         doc = htmlCtxtReadFd(ctxt, STDIN_FILENO, "-", NULL,
472                              lint->options);
473     else
474         doc = htmlCtxtReadFile(ctxt, filename, NULL, lint->options);
475 
476     return(doc);
477 }
478 #endif /* LIBXML_HTML_ENABLED */
479 
480 /************************************************************************
481  *									*
482  * Memory allocation consumption debugging				*
483  *									*
484  ************************************************************************/
485 
486 #define XMLLINT_ABORT_ON_FAILURE 0
487 
488 static void
myFreeFunc(void * mem)489 myFreeFunc(void *mem) {
490     xmlMemFree(mem);
491 }
492 
493 static void *
myMallocFunc(size_t size)494 myMallocFunc(size_t size) {
495     void *ret;
496 
497     if (xmlMemUsed() + size > (size_t) xmllintMaxmem) {
498 #if XMLLINT_ABORT_ON_FAILURE
499         abort();
500 #endif
501         xmllintMaxmemReached = 1;
502         xmllintOom = 1;
503         return(NULL);
504     }
505 
506     ret = xmlMemMalloc(size);
507     if (ret == NULL)
508         xmllintOom = 1;
509 
510     return(ret);
511 }
512 
513 static void *
myReallocFunc(void * mem,size_t size)514 myReallocFunc(void *mem, size_t size) {
515     void *ret;
516     size_t oldsize = xmlMemSize(mem);
517 
518     if (xmlMemUsed() + size - oldsize > (size_t) xmllintMaxmem) {
519 #if XMLLINT_ABORT_ON_FAILURE
520         abort();
521 #endif
522         xmllintMaxmemReached = 1;
523         xmllintOom = 1;
524         return(NULL);
525     }
526 
527     ret = xmlMemRealloc(mem, size);
528     if (ret == NULL)
529         xmllintOom = 1;
530 
531     return(ret);
532 }
533 
534 static char *
myStrdupFunc(const char * str)535 myStrdupFunc(const char *str) {
536     size_t size;
537     char *ret;
538 
539     if (str == NULL)
540         return(NULL);
541 
542     size = strlen(str) + 1;
543     if (xmlMemUsed() + size > (size_t) xmllintMaxmem) {
544 #if XMLLINT_ABORT_ON_FAILURE
545         abort();
546 #endif
547         xmllintMaxmemReached = 1;
548         xmllintOom = 1;
549         return(NULL);
550     }
551 
552     ret = xmlMemMalloc(size);
553     if (ret == NULL) {
554         xmllintOom = 1;
555         return(NULL);
556     }
557 
558     memcpy(ret, str, size);
559 
560     return(ret);
561 }
562 
563 /************************************************************************
564  *									*
565  * Internal timing routines to remove the necessity to have		*
566  * unix-specific function calls.					*
567  *									*
568  ************************************************************************/
569 
570 static void
getTime(xmlTime * time)571 getTime(xmlTime *time) {
572 #ifdef _WIN32
573     struct __timeb64 timebuffer;
574 
575     _ftime64(&timebuffer);
576     time->sec = timebuffer.time;
577     time->usec = timebuffer.millitm * 1000;
578 #else /* _WIN32 */
579     struct timeval tv;
580 
581     gettimeofday(&tv, NULL);
582     time->sec = tv.tv_sec;
583     time->usec = tv.tv_usec;
584 #endif /* _WIN32 */
585 }
586 
587 /*
588  * startTimer: call where you want to start timing
589  */
590 static void
startTimer(xmllintState * lint)591 startTimer(xmllintState *lint)
592 {
593     getTime(&lint->begin);
594 }
595 
596 /*
597  * endTimer: call where you want to stop timing and to print out a
598  *           message about the timing performed; format is a printf
599  *           type argument
600  */
601 static void LIBXML_ATTR_FORMAT(2,3)
endTimer(xmllintState * lint,const char * fmt,...)602 endTimer(xmllintState *lint, const char *fmt, ...)
603 {
604     xmlSeconds msec;
605     va_list ap;
606 
607     getTime(&lint->end);
608     msec = lint->end.sec - lint->begin.sec;
609     msec *= 1000;
610     msec += (lint->end.usec - lint->begin.usec) / 1000;
611 
612     va_start(ap, fmt);
613     vfprintf(lint->errStream, fmt, ap);
614     va_end(ap);
615 
616     fprintf(lint->errStream, " took %ld ms\n", (long) msec);
617 }
618 
619 /************************************************************************
620  *									*
621  *			HTML output					*
622  *									*
623  ************************************************************************/
624 
625 static void
xmlHTMLEncodeSend(xmllintState * lint)626 xmlHTMLEncodeSend(xmllintState *lint) {
627     char *result;
628 
629     /*
630      * xmlEncodeEntitiesReentrant assumes valid UTF-8, but the buffer might
631      * end with a truncated UTF-8 sequence. This is a hack to at least avoid
632      * an out-of-bounds read.
633      */
634     memset(&lint->htmlBuf[HTML_BUF_SIZE - 4], 0, 4);
635     result = (char *) xmlEncodeEntitiesReentrant(NULL, BAD_CAST lint->htmlBuf);
636     if (result) {
637 	fprintf(lint->errStream, "%s", result);
638 	xmlFree(result);
639     }
640 
641     lint->htmlBufLen = 0;
642 }
643 
644 static void
xmlHTMLBufCat(void * data,const char * fmt,...)645 xmlHTMLBufCat(void *data, const char *fmt, ...) {
646     xmllintState *lint = data;
647     va_list ap;
648     int res;
649 
650     va_start(ap, fmt);
651     res = vsnprintf(&lint->htmlBuf[lint->htmlBufLen],
652                     HTML_BUF_SIZE - lint->htmlBufLen, fmt, ap);
653     va_end(ap);
654 
655     if (res > 0) {
656         if (res > HTML_BUF_SIZE - lint->htmlBufLen - 1)
657             lint->htmlBufLen = HTML_BUF_SIZE - 1;
658         else
659             lint->htmlBufLen += res;
660     }
661 }
662 
663 /**
664  * xmlHTMLError:
665  * @ctx:  an XML parser context
666  * @msg:  the message to display/transmit
667  * @...:  extra parameters for the message display
668  *
669  * Display and format an error messages, gives file, line, position and
670  * extra parameters.
671  */
672 static void
xmlHTMLError(void * vctxt,const xmlError * error)673 xmlHTMLError(void *vctxt, const xmlError *error)
674 {
675     xmlParserCtxtPtr ctxt = vctxt;
676     xmllintState *lint = ctxt->_private;
677     xmlParserInputPtr input;
678     xmlGenericErrorFunc oldError;
679     void *oldErrorCtxt;
680 
681     input = ctxt->input;
682     if ((input != NULL) && (input->filename == NULL) && (ctxt->inputNr > 1)) {
683         input = ctxt->inputTab[ctxt->inputNr - 2];
684     }
685 
686     oldError = xmlGenericError;
687     oldErrorCtxt = xmlGenericErrorContext;
688     xmlSetGenericErrorFunc(lint, xmlHTMLBufCat);
689 
690     fprintf(lint->errStream, "<p>");
691 
692     xmlParserPrintFileInfo(input);
693     xmlHTMLEncodeSend(lint);
694 
695     fprintf(lint->errStream, "<b>%s%s</b>: ",
696             (error->domain == XML_FROM_VALID) ||
697             (error->domain == XML_FROM_DTD) ? "validity " : "",
698             error->level == XML_ERR_WARNING ? "warning" : "error");
699 
700     snprintf(lint->htmlBuf, HTML_BUF_SIZE, "%s", error->message);
701     xmlHTMLEncodeSend(lint);
702 
703     fprintf(lint->errStream, "</p>\n");
704 
705     if (input != NULL) {
706         fprintf(lint->errStream, "<pre>\n");
707 
708         xmlParserPrintFileContext(input);
709         xmlHTMLEncodeSend(lint);
710 
711         fprintf(lint->errStream, "</pre>");
712     }
713 
714     xmlSetGenericErrorFunc(oldErrorCtxt, oldError);
715 }
716 
717 /************************************************************************
718  *									*
719  *			SAX based tests					*
720  *									*
721  ************************************************************************/
722 
723 /*
724  * empty SAX block
725  */
726 static const xmlSAXHandler emptySAXHandler = {
727     NULL, /* internalSubset */
728     NULL, /* isStandalone */
729     NULL, /* hasInternalSubset */
730     NULL, /* hasExternalSubset */
731     NULL, /* resolveEntity */
732     NULL, /* getEntity */
733     NULL, /* entityDecl */
734     NULL, /* notationDecl */
735     NULL, /* attributeDecl */
736     NULL, /* elementDecl */
737     NULL, /* unparsedEntityDecl */
738     NULL, /* setDocumentLocator */
739     NULL, /* startDocument */
740     NULL, /* endDocument */
741     NULL, /* startElement */
742     NULL, /* endElement */
743     NULL, /* reference */
744     NULL, /* characters */
745     NULL, /* ignorableWhitespace */
746     NULL, /* processingInstruction */
747     NULL, /* comment */
748     NULL, /* xmlParserWarning */
749     NULL, /* xmlParserError */
750     NULL, /* xmlParserError */
751     NULL, /* getParameterEntity */
752     NULL, /* cdataBlock; */
753     NULL, /* externalSubset; */
754     XML_SAX2_MAGIC,
755     NULL,
756     NULL, /* startElementNs */
757     NULL, /* endElementNs */
758     NULL  /* xmlStructuredErrorFunc */
759 };
760 
761 /**
762  * isStandaloneDebug:
763  * @ctxt:  An XML parser context
764  *
765  * Is this document tagged standalone ?
766  *
767  * Returns 1 if true
768  */
769 static int
isStandaloneDebug(void * ctx)770 isStandaloneDebug(void *ctx)
771 {
772     xmllintState *lint = ctx;
773 
774     lint->callbacks++;
775     if (lint->noout)
776 	return(0);
777     fprintf(stdout, "SAX.isStandalone()\n");
778     return(0);
779 }
780 
781 /**
782  * hasInternalSubsetDebug:
783  * @ctxt:  An XML parser context
784  *
785  * Does this document has an internal subset
786  *
787  * Returns 1 if true
788  */
789 static int
hasInternalSubsetDebug(void * ctx)790 hasInternalSubsetDebug(void *ctx)
791 {
792     xmllintState *lint = ctx;
793 
794     lint->callbacks++;
795     if (lint->noout)
796 	return(0);
797     fprintf(stdout, "SAX.hasInternalSubset()\n");
798     return(0);
799 }
800 
801 /**
802  * hasExternalSubsetDebug:
803  * @ctxt:  An XML parser context
804  *
805  * Does this document has an external subset
806  *
807  * Returns 1 if true
808  */
809 static int
hasExternalSubsetDebug(void * ctx)810 hasExternalSubsetDebug(void *ctx)
811 {
812     xmllintState *lint = ctx;
813 
814     lint->callbacks++;
815     if (lint->noout)
816 	return(0);
817     fprintf(stdout, "SAX.hasExternalSubset()\n");
818     return(0);
819 }
820 
821 /**
822  * internalSubsetDebug:
823  * @ctxt:  An XML parser context
824  *
825  * Does this document has an internal subset
826  */
827 static void
internalSubsetDebug(void * ctx,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)828 internalSubsetDebug(void *ctx, const xmlChar *name,
829 	       const xmlChar *ExternalID, const xmlChar *SystemID)
830 {
831     xmllintState *lint = ctx;
832 
833     lint->callbacks++;
834     if (lint->noout)
835 	return;
836     fprintf(stdout, "SAX.internalSubset(%s,", name);
837     if (ExternalID == NULL)
838 	fprintf(stdout, " ,");
839     else
840 	fprintf(stdout, " %s,", ExternalID);
841     if (SystemID == NULL)
842 	fprintf(stdout, " )\n");
843     else
844 	fprintf(stdout, " %s)\n", SystemID);
845 }
846 
847 /**
848  * externalSubsetDebug:
849  * @ctxt:  An XML parser context
850  *
851  * Does this document has an external subset
852  */
853 static void
externalSubsetDebug(void * ctx,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)854 externalSubsetDebug(void *ctx, const xmlChar *name,
855 	       const xmlChar *ExternalID, const xmlChar *SystemID)
856 {
857     xmllintState *lint = ctx;
858 
859     lint->callbacks++;
860     if (lint->noout)
861 	return;
862     fprintf(stdout, "SAX.externalSubset(%s,", name);
863     if (ExternalID == NULL)
864 	fprintf(stdout, " ,");
865     else
866 	fprintf(stdout, " %s,", ExternalID);
867     if (SystemID == NULL)
868 	fprintf(stdout, " )\n");
869     else
870 	fprintf(stdout, " %s)\n", SystemID);
871 }
872 
873 /**
874  * resolveEntityDebug:
875  * @ctxt:  An XML parser context
876  * @publicId: The public ID of the entity
877  * @systemId: The system ID of the entity
878  *
879  * Special entity resolver, better left to the parser, it has
880  * more context than the application layer.
881  * The default behaviour is to NOT resolve the entities, in that case
882  * the ENTITY_REF nodes are built in the structure (and the parameter
883  * values).
884  *
885  * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
886  */
887 static xmlParserInputPtr
resolveEntityDebug(void * ctx,const xmlChar * publicId,const xmlChar * systemId)888 resolveEntityDebug(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
889 {
890     xmllintState *lint = ctx;
891 
892     lint->callbacks++;
893     if (lint->noout)
894 	return(NULL);
895     /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
896 
897 
898     fprintf(stdout, "SAX.resolveEntity(");
899     if (publicId != NULL)
900 	fprintf(stdout, "%s", (char *)publicId);
901     else
902 	fprintf(stdout, " ");
903     if (systemId != NULL)
904 	fprintf(stdout, ", %s)\n", (char *)systemId);
905     else
906 	fprintf(stdout, ", )\n");
907     return(NULL);
908 }
909 
910 /**
911  * getEntityDebug:
912  * @ctxt:  An XML parser context
913  * @name: The entity name
914  *
915  * Get an entity by name
916  *
917  * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
918  */
919 static xmlEntityPtr
getEntityDebug(void * ctx,const xmlChar * name)920 getEntityDebug(void *ctx, const xmlChar *name)
921 {
922     xmllintState *lint = ctx;
923 
924     lint->callbacks++;
925     if (lint->noout)
926 	return(NULL);
927     fprintf(stdout, "SAX.getEntity(%s)\n", name);
928     return(NULL);
929 }
930 
931 /**
932  * getParameterEntityDebug:
933  * @ctxt:  An XML parser context
934  * @name: The entity name
935  *
936  * Get a parameter entity by name
937  *
938  * Returns the xmlParserInputPtr
939  */
940 static xmlEntityPtr
getParameterEntityDebug(void * ctx,const xmlChar * name)941 getParameterEntityDebug(void *ctx, const xmlChar *name)
942 {
943     xmllintState *lint = ctx;
944 
945     lint->callbacks++;
946     if (lint->noout)
947 	return(NULL);
948     fprintf(stdout, "SAX.getParameterEntity(%s)\n", name);
949     return(NULL);
950 }
951 
952 
953 /**
954  * entityDeclDebug:
955  * @ctxt:  An XML parser context
956  * @name:  the entity name
957  * @type:  the entity type
958  * @publicId: The public ID of the entity
959  * @systemId: The system ID of the entity
960  * @content: the entity value (without processing).
961  *
962  * An entity definition has been parsed
963  */
964 static void
entityDeclDebug(void * ctx,const xmlChar * name,int type,const xmlChar * publicId,const xmlChar * systemId,xmlChar * content)965 entityDeclDebug(void *ctx, const xmlChar *name, int type,
966           const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
967 {
968     xmllintState *lint = ctx;
969     const xmlChar *nullstr = BAD_CAST "(null)";
970 
971     /* not all libraries handle printing null pointers nicely */
972     if (publicId == NULL)
973         publicId = nullstr;
974     if (systemId == NULL)
975         systemId = nullstr;
976     if (content == NULL)
977         content = (xmlChar *)nullstr;
978     lint->callbacks++;
979     if (lint->noout)
980 	return;
981     fprintf(stdout, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
982             name, type, publicId, systemId, content);
983 }
984 
985 /**
986  * attributeDeclDebug:
987  * @ctxt:  An XML parser context
988  * @name:  the attribute name
989  * @type:  the attribute type
990  *
991  * An attribute definition has been parsed
992  */
993 static void
attributeDeclDebug(void * ctx,const xmlChar * elem,const xmlChar * name,int type,int def,const xmlChar * defaultValue,xmlEnumerationPtr tree)994 attributeDeclDebug(void *ctx, const xmlChar * elem,
995                    const xmlChar * name, int type, int def,
996                    const xmlChar * defaultValue, xmlEnumerationPtr tree)
997 {
998     xmllintState *lint = ctx;
999 
1000     lint->callbacks++;
1001     if (lint->noout)
1002         return;
1003     if (defaultValue == NULL)
1004         fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
1005                 elem, name, type, def);
1006     else
1007         fprintf(stdout, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
1008                 elem, name, type, def, defaultValue);
1009     xmlFreeEnumeration(tree);
1010 }
1011 
1012 /**
1013  * elementDeclDebug:
1014  * @ctxt:  An XML parser context
1015  * @name:  the element name
1016  * @type:  the element type
1017  * @content: the element value (without processing).
1018  *
1019  * An element definition has been parsed
1020  */
1021 static void
elementDeclDebug(void * ctx,const xmlChar * name,int type,xmlElementContentPtr content ATTRIBUTE_UNUSED)1022 elementDeclDebug(void *ctx, const xmlChar *name, int type,
1023 	    xmlElementContentPtr content ATTRIBUTE_UNUSED)
1024 {
1025     xmllintState *lint = ctx;
1026 
1027     lint->callbacks++;
1028     if (lint->noout)
1029 	return;
1030     fprintf(stdout, "SAX.elementDecl(%s, %d, ...)\n",
1031             name, type);
1032 }
1033 
1034 /**
1035  * notationDeclDebug:
1036  * @ctxt:  An XML parser context
1037  * @name: The name of the notation
1038  * @publicId: The public ID of the entity
1039  * @systemId: The system ID of the entity
1040  *
1041  * What to do when a notation declaration has been parsed.
1042  */
1043 static void
notationDeclDebug(void * ctx,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId)1044 notationDeclDebug(void *ctx, const xmlChar *name,
1045 	     const xmlChar *publicId, const xmlChar *systemId)
1046 {
1047     xmllintState *lint = ctx;
1048 
1049     lint->callbacks++;
1050     if (lint->noout)
1051 	return;
1052     fprintf(stdout, "SAX.notationDecl(%s, %s, %s)\n",
1053             (char *) name, (char *) publicId, (char *) systemId);
1054 }
1055 
1056 /**
1057  * unparsedEntityDeclDebug:
1058  * @ctxt:  An XML parser context
1059  * @name: The name of the entity
1060  * @publicId: The public ID of the entity
1061  * @systemId: The system ID of the entity
1062  * @notationName: the name of the notation
1063  *
1064  * What to do when an unparsed entity declaration is parsed
1065  */
1066 static void
unparsedEntityDeclDebug(void * ctx,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId,const xmlChar * notationName)1067 unparsedEntityDeclDebug(void *ctx, const xmlChar *name,
1068 		   const xmlChar *publicId, const xmlChar *systemId,
1069 		   const xmlChar *notationName)
1070 {
1071     xmllintState *lint = ctx;
1072     const xmlChar *nullstr = BAD_CAST "(null)";
1073 
1074     if (publicId == NULL)
1075         publicId = nullstr;
1076     if (systemId == NULL)
1077         systemId = nullstr;
1078     if (notationName == NULL)
1079         notationName = nullstr;
1080     lint->callbacks++;
1081     if (lint->noout)
1082 	return;
1083     fprintf(stdout, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
1084             (char *) name, (char *) publicId, (char *) systemId,
1085 	    (char *) notationName);
1086 }
1087 
1088 /**
1089  * setDocumentLocatorDebug:
1090  * @ctxt:  An XML parser context
1091  * @loc: A SAX Locator
1092  *
1093  * Receive the document locator at startup, actually xmlDefaultSAXLocator
1094  * Everything is available on the context, so this is useless in our case.
1095  */
1096 static void
setDocumentLocatorDebug(void * ctx,xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)1097 setDocumentLocatorDebug(void *ctx, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
1098 {
1099     xmllintState *lint = ctx;
1100 
1101     lint->callbacks++;
1102     if (lint->noout)
1103 	return;
1104     fprintf(stdout, "SAX.setDocumentLocator()\n");
1105 }
1106 
1107 /**
1108  * startDocumentDebug:
1109  * @ctxt:  An XML parser context
1110  *
1111  * called when the document start being processed.
1112  */
1113 static void
startDocumentDebug(void * ctx)1114 startDocumentDebug(void *ctx)
1115 {
1116     xmllintState *lint = ctx;
1117 
1118     lint->callbacks++;
1119     if (lint->noout)
1120 	return;
1121     fprintf(stdout, "SAX.startDocument()\n");
1122 }
1123 
1124 /**
1125  * endDocumentDebug:
1126  * @ctxt:  An XML parser context
1127  *
1128  * called when the document end has been detected.
1129  */
1130 static void
endDocumentDebug(void * ctx)1131 endDocumentDebug(void *ctx)
1132 {
1133     xmllintState *lint = ctx;
1134 
1135     lint->callbacks++;
1136     if (lint->noout)
1137 	return;
1138     fprintf(stdout, "SAX.endDocument()\n");
1139 }
1140 
1141 #ifdef LIBXML_SAX1_ENABLED
1142 /**
1143  * startElementDebug:
1144  * @ctxt:  An XML parser context
1145  * @name:  The element name
1146  *
1147  * called when an opening tag has been processed.
1148  */
1149 static void
startElementDebug(void * ctx,const xmlChar * name,const xmlChar ** atts)1150 startElementDebug(void *ctx, const xmlChar *name, const xmlChar **atts)
1151 {
1152     xmllintState *lint = ctx;
1153     int i;
1154 
1155     lint->callbacks++;
1156     if (lint->noout)
1157 	return;
1158     fprintf(stdout, "SAX.startElement(%s", (char *) name);
1159     if (atts != NULL) {
1160         for (i = 0;(atts[i] != NULL);i++) {
1161 	    fprintf(stdout, ", %s='", atts[i++]);
1162 	    if (atts[i] != NULL)
1163 	        fprintf(stdout, "%s'", atts[i]);
1164 	}
1165     }
1166     fprintf(stdout, ")\n");
1167 }
1168 
1169 /**
1170  * endElementDebug:
1171  * @ctxt:  An XML parser context
1172  * @name:  The element name
1173  *
1174  * called when the end of an element has been detected.
1175  */
1176 static void
endElementDebug(void * ctx,const xmlChar * name)1177 endElementDebug(void *ctx, const xmlChar *name)
1178 {
1179     xmllintState *lint = ctx;
1180 
1181     lint->callbacks++;
1182     if (lint->noout)
1183 	return;
1184     fprintf(stdout, "SAX.endElement(%s)\n", (char *) name);
1185 }
1186 #endif /* LIBXML_SAX1_ENABLED */
1187 
1188 /**
1189  * charactersDebug:
1190  * @ctxt:  An XML parser context
1191  * @ch:  a xmlChar string
1192  * @len: the number of xmlChar
1193  *
1194  * receiving some chars from the parser.
1195  * Question: how much at a time ???
1196  */
1197 static void
charactersDebug(void * ctx,const xmlChar * ch,int len)1198 charactersDebug(void *ctx, const xmlChar *ch, int len)
1199 {
1200     xmllintState *lint = ctx;
1201     char out[40];
1202     int i;
1203 
1204     lint->callbacks++;
1205     if (lint->noout)
1206 	return;
1207     for (i = 0;(i<len) && (i < 30);i++)
1208 	out[i] = (char) ch[i];
1209     out[i] = 0;
1210 
1211     fprintf(stdout, "SAX.characters(%s, %d)\n", out, len);
1212 }
1213 
1214 /**
1215  * referenceDebug:
1216  * @ctxt:  An XML parser context
1217  * @name:  The entity name
1218  *
1219  * called when an entity reference is detected.
1220  */
1221 static void
referenceDebug(void * ctx,const xmlChar * name)1222 referenceDebug(void *ctx, const xmlChar *name)
1223 {
1224     xmllintState *lint = ctx;
1225 
1226     lint->callbacks++;
1227     if (lint->noout)
1228 	return;
1229     fprintf(stdout, "SAX.reference(%s)\n", name);
1230 }
1231 
1232 /**
1233  * ignorableWhitespaceDebug:
1234  * @ctxt:  An XML parser context
1235  * @ch:  a xmlChar string
1236  * @start: the first char in the string
1237  * @len: the number of xmlChar
1238  *
1239  * receiving some ignorable whitespaces from the parser.
1240  * Question: how much at a time ???
1241  */
1242 static void
ignorableWhitespaceDebug(void * ctx,const xmlChar * ch,int len)1243 ignorableWhitespaceDebug(void *ctx, const xmlChar *ch, int len)
1244 {
1245     xmllintState *lint = ctx;
1246     char out[40];
1247     int i;
1248 
1249     lint->callbacks++;
1250     if (lint->noout)
1251 	return;
1252     for (i = 0;(i<len) && (i < 30);i++)
1253 	out[i] = ch[i];
1254     out[i] = 0;
1255     fprintf(stdout, "SAX.ignorableWhitespace(%s, %d)\n", out, len);
1256 }
1257 
1258 /**
1259  * processingInstructionDebug:
1260  * @ctxt:  An XML parser context
1261  * @target:  the target name
1262  * @data: the PI data's
1263  * @len: the number of xmlChar
1264  *
1265  * A processing instruction has been parsed.
1266  */
1267 static void
processingInstructionDebug(void * ctx,const xmlChar * target,const xmlChar * data)1268 processingInstructionDebug(void *ctx, const xmlChar *target,
1269                       const xmlChar *data)
1270 {
1271     xmllintState *lint = ctx;
1272 
1273     lint->callbacks++;
1274     if (lint->noout)
1275 	return;
1276     if (data != NULL)
1277 	fprintf(stdout, "SAX.processingInstruction(%s, %s)\n",
1278 		(char *) target, (char *) data);
1279     else
1280 	fprintf(stdout, "SAX.processingInstruction(%s, NULL)\n",
1281 		(char *) target);
1282 }
1283 
1284 /**
1285  * cdataBlockDebug:
1286  * @ctx: the user data (XML parser context)
1287  * @value:  The pcdata content
1288  * @len:  the block length
1289  *
1290  * called when a pcdata block has been parsed
1291  */
1292 static void
cdataBlockDebug(void * ctx,const xmlChar * value,int len)1293 cdataBlockDebug(void *ctx, const xmlChar *value, int len)
1294 {
1295     xmllintState *lint = ctx;
1296 
1297     lint->callbacks++;
1298     if (lint->noout)
1299 	return;
1300     fprintf(stdout, "SAX.pcdata(%.20s, %d)\n",
1301 	    (char *) value, len);
1302 }
1303 
1304 /**
1305  * commentDebug:
1306  * @ctxt:  An XML parser context
1307  * @value:  the comment content
1308  *
1309  * A comment has been parsed.
1310  */
1311 static void
commentDebug(void * ctx,const xmlChar * value)1312 commentDebug(void *ctx, const xmlChar *value)
1313 {
1314     xmllintState *lint = ctx;
1315 
1316     lint->callbacks++;
1317     if (lint->noout)
1318 	return;
1319     fprintf(stdout, "SAX.comment(%s)\n", value);
1320 }
1321 
1322 /**
1323  * warningDebug:
1324  * @ctxt:  An XML parser context
1325  * @msg:  the message to display/transmit
1326  * @...:  extra parameters for the message display
1327  *
1328  * Display and format a warning messages, gives file, line, position and
1329  * extra parameters.
1330  */
1331 static void LIBXML_ATTR_FORMAT(2,3)
warningDebug(void * ctx,const char * msg,...)1332 warningDebug(void *ctx, const char *msg, ...)
1333 {
1334     xmllintState *lint = ctx;
1335     va_list args;
1336 
1337     lint->callbacks++;
1338     if (lint->noout)
1339 	return;
1340     va_start(args, msg);
1341     fprintf(stdout, "SAX.warning: ");
1342     vfprintf(stdout, msg, args);
1343     va_end(args);
1344 }
1345 
1346 /**
1347  * errorDebug:
1348  * @ctxt:  An XML parser context
1349  * @msg:  the message to display/transmit
1350  * @...:  extra parameters for the message display
1351  *
1352  * Display and format a error messages, gives file, line, position and
1353  * extra parameters.
1354  */
1355 static void LIBXML_ATTR_FORMAT(2,3)
errorDebug(void * ctx,const char * msg,...)1356 errorDebug(void *ctx, const char *msg, ...)
1357 {
1358     xmllintState *lint = ctx;
1359     va_list args;
1360 
1361     lint->callbacks++;
1362     if (lint->noout)
1363 	return;
1364     va_start(args, msg);
1365     fprintf(stdout, "SAX.error: ");
1366     vfprintf(stdout, msg, args);
1367     va_end(args);
1368 }
1369 
1370 /**
1371  * fatalErrorDebug:
1372  * @ctxt:  An XML parser context
1373  * @msg:  the message to display/transmit
1374  * @...:  extra parameters for the message display
1375  *
1376  * Display and format a fatalError messages, gives file, line, position and
1377  * extra parameters.
1378  */
1379 static void LIBXML_ATTR_FORMAT(2,3)
fatalErrorDebug(void * ctx,const char * msg,...)1380 fatalErrorDebug(void *ctx, const char *msg, ...)
1381 {
1382     xmllintState *lint = ctx;
1383     va_list args;
1384 
1385     lint->callbacks++;
1386     if (lint->noout)
1387 	return;
1388     va_start(args, msg);
1389     fprintf(stdout, "SAX.fatalError: ");
1390     vfprintf(stdout, msg, args);
1391     va_end(args);
1392 }
1393 
1394 #ifdef LIBXML_SAX1_ENABLED
1395 static const xmlSAXHandler debugSAXHandler = {
1396     internalSubsetDebug,
1397     isStandaloneDebug,
1398     hasInternalSubsetDebug,
1399     hasExternalSubsetDebug,
1400     resolveEntityDebug,
1401     getEntityDebug,
1402     entityDeclDebug,
1403     notationDeclDebug,
1404     attributeDeclDebug,
1405     elementDeclDebug,
1406     unparsedEntityDeclDebug,
1407     setDocumentLocatorDebug,
1408     startDocumentDebug,
1409     endDocumentDebug,
1410     startElementDebug,
1411     endElementDebug,
1412     referenceDebug,
1413     charactersDebug,
1414     ignorableWhitespaceDebug,
1415     processingInstructionDebug,
1416     commentDebug,
1417     warningDebug,
1418     errorDebug,
1419     fatalErrorDebug,
1420     getParameterEntityDebug,
1421     cdataBlockDebug,
1422     externalSubsetDebug,
1423     1,
1424     NULL,
1425     NULL,
1426     NULL,
1427     NULL
1428 };
1429 #endif
1430 
1431 /*
1432  * SAX2 specific callbacks
1433  */
1434 /**
1435  * startElementNsDebug:
1436  * @ctxt:  An XML parser context
1437  * @name:  The element name
1438  *
1439  * called when an opening tag has been processed.
1440  */
1441 static void
startElementNsDebug(void * ctx,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI,int nb_namespaces,const xmlChar ** namespaces,int nb_attributes,int nb_defaulted,const xmlChar ** attributes)1442 startElementNsDebug(void *ctx,
1443                     const xmlChar *localname,
1444                     const xmlChar *prefix,
1445                     const xmlChar *URI,
1446 		    int nb_namespaces,
1447 		    const xmlChar **namespaces,
1448 		    int nb_attributes,
1449 		    int nb_defaulted,
1450 		    const xmlChar **attributes)
1451 {
1452     xmllintState *lint = ctx;
1453     int i;
1454 
1455     lint->callbacks++;
1456     if (lint->noout)
1457 	return;
1458     fprintf(stdout, "SAX.startElementNs(%s", (char *) localname);
1459     if (prefix == NULL)
1460 	fprintf(stdout, ", NULL");
1461     else
1462 	fprintf(stdout, ", %s", (char *) prefix);
1463     if (URI == NULL)
1464 	fprintf(stdout, ", NULL");
1465     else
1466 	fprintf(stdout, ", '%s'", (char *) URI);
1467     fprintf(stdout, ", %d", nb_namespaces);
1468 
1469     if (namespaces != NULL) {
1470         for (i = 0;i < nb_namespaces * 2;i++) {
1471 	    fprintf(stdout, ", xmlns");
1472 	    if (namespaces[i] != NULL)
1473 	        fprintf(stdout, ":%s", namespaces[i]);
1474 	    i++;
1475 	    fprintf(stdout, "='%s'", namespaces[i]);
1476 	}
1477     }
1478     fprintf(stdout, ", %d, %d", nb_attributes, nb_defaulted);
1479     if (attributes != NULL) {
1480         for (i = 0;i < nb_attributes * 5;i += 5) {
1481 	    if (attributes[i + 1] != NULL)
1482 		fprintf(stdout, ", %s:%s='", attributes[i + 1], attributes[i]);
1483 	    else
1484 		fprintf(stdout, ", %s='", attributes[i]);
1485 	    fprintf(stdout, "%.4s...', %d", attributes[i + 3],
1486 		    (int)(attributes[i + 4] - attributes[i + 3]));
1487 	}
1488     }
1489     fprintf(stdout, ")\n");
1490 }
1491 
1492 /**
1493  * endElementDebug:
1494  * @ctxt:  An XML parser context
1495  * @name:  The element name
1496  *
1497  * called when the end of an element has been detected.
1498  */
1499 static void
endElementNsDebug(void * ctx,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI)1500 endElementNsDebug(void *ctx,
1501                   const xmlChar *localname,
1502                   const xmlChar *prefix,
1503                   const xmlChar *URI)
1504 {
1505     xmllintState *lint = ctx;
1506 
1507     lint->callbacks++;
1508     if (lint->noout)
1509 	return;
1510     fprintf(stdout, "SAX.endElementNs(%s", (char *) localname);
1511     if (prefix == NULL)
1512 	fprintf(stdout, ", NULL");
1513     else
1514 	fprintf(stdout, ", %s", (char *) prefix);
1515     if (URI == NULL)
1516 	fprintf(stdout, ", NULL)\n");
1517     else
1518 	fprintf(stdout, ", '%s')\n", (char *) URI);
1519 }
1520 
1521 static const xmlSAXHandler debugSAX2Handler = {
1522     internalSubsetDebug,
1523     isStandaloneDebug,
1524     hasInternalSubsetDebug,
1525     hasExternalSubsetDebug,
1526     resolveEntityDebug,
1527     getEntityDebug,
1528     entityDeclDebug,
1529     notationDeclDebug,
1530     attributeDeclDebug,
1531     elementDeclDebug,
1532     unparsedEntityDeclDebug,
1533     setDocumentLocatorDebug,
1534     startDocumentDebug,
1535     endDocumentDebug,
1536     NULL,
1537     NULL,
1538     referenceDebug,
1539     charactersDebug,
1540     ignorableWhitespaceDebug,
1541     processingInstructionDebug,
1542     commentDebug,
1543     warningDebug,
1544     errorDebug,
1545     fatalErrorDebug,
1546     getParameterEntityDebug,
1547     cdataBlockDebug,
1548     externalSubsetDebug,
1549     XML_SAX2_MAGIC,
1550     NULL,
1551     startElementNsDebug,
1552     endElementNsDebug,
1553     NULL
1554 };
1555 
1556 static void
testSAX(xmllintState * lint,const char * filename)1557 testSAX(xmllintState *lint, const char *filename) {
1558     lint->callbacks = 0;
1559 
1560 #ifdef LIBXML_SCHEMAS_ENABLED
1561     if (lint->wxschemas != NULL) {
1562         int ret;
1563 	xmlSchemaValidCtxtPtr vctxt;
1564         xmlParserInputBufferPtr buf;
1565 
1566         if (strcmp(filename, "-") == 0)
1567             buf = xmlParserInputBufferCreateFd(STDIN_FILENO,
1568                     XML_CHAR_ENCODING_NONE);
1569         else
1570             buf = xmlParserInputBufferCreateFilename(filename,
1571                     XML_CHAR_ENCODING_NONE);
1572         if (buf == NULL)
1573             return;
1574 
1575 	vctxt = xmlSchemaNewValidCtxt(lint->wxschemas);
1576         if (vctxt == NULL) {
1577             lint->progresult = XMLLINT_ERR_MEM;
1578             xmlFreeParserInputBuffer(buf);
1579             return;
1580         }
1581 	xmlSchemaValidateSetFilename(vctxt, filename);
1582 
1583 	ret = xmlSchemaValidateStream(vctxt, buf, 0, lint->ctxt->sax, lint);
1584 	if (lint->repeat == 1) {
1585 	    if (ret == 0) {
1586 	        if (!lint->quiet) {
1587 	            fprintf(lint->errStream, "%s validates\n", filename);
1588 	        }
1589 	    } else if (ret > 0) {
1590 		fprintf(lint->errStream, "%s fails to validate\n", filename);
1591 		lint->progresult = XMLLINT_ERR_VALID;
1592 	    } else {
1593 		fprintf(lint->errStream, "%s validation generated an internal error\n",
1594 		       filename);
1595 		lint->progresult = XMLLINT_ERR_VALID;
1596 	    }
1597 	}
1598 	xmlSchemaFreeValidCtxt(vctxt);
1599     } else
1600 #endif
1601 #ifdef LIBXML_HTML_ENABLED
1602     if (lint->html) {
1603         parseHtml(lint, filename);
1604     } else
1605 #endif
1606     {
1607         parseXml(lint, filename);
1608     }
1609 }
1610 
1611 /************************************************************************
1612  *									*
1613  *			Stream Test processing				*
1614  *									*
1615  ************************************************************************/
1616 #ifdef LIBXML_READER_ENABLED
processNode(xmllintState * lint,xmlTextReaderPtr reader)1617 static void processNode(xmllintState *lint, xmlTextReaderPtr reader) {
1618     const xmlChar *name, *value;
1619     int type, empty;
1620 
1621     type = xmlTextReaderNodeType(reader);
1622     empty = xmlTextReaderIsEmptyElement(reader);
1623 
1624     if (lint->debug) {
1625 	name = xmlTextReaderConstName(reader);
1626 	if (name == NULL)
1627 	    name = BAD_CAST "--";
1628 
1629 	value = xmlTextReaderConstValue(reader);
1630 
1631 
1632 	printf("%d %d %s %d %d",
1633 		xmlTextReaderDepth(reader),
1634 		type,
1635 		name,
1636 		empty,
1637 		xmlTextReaderHasValue(reader));
1638 	if (value == NULL)
1639 	    printf("\n");
1640 	else {
1641 	    printf(" %s\n", value);
1642 	}
1643     }
1644 #ifdef LIBXML_PATTERN_ENABLED
1645     if (lint->patternc) {
1646         xmlChar *path = NULL;
1647         int match = -1;
1648 
1649 	if (type == XML_READER_TYPE_ELEMENT) {
1650 	    /* do the check only on element start */
1651 	    match = xmlPatternMatch(lint->patternc,
1652                                     xmlTextReaderCurrentNode(reader));
1653 
1654 	    if (match) {
1655 		path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
1656 		printf("Node %s matches pattern %s\n", path, lint->pattern);
1657 	    }
1658 	}
1659 	if (lint->patstream != NULL) {
1660 	    int ret;
1661 
1662 	    if (type == XML_READER_TYPE_ELEMENT) {
1663 		ret = xmlStreamPush(lint->patstream,
1664 		                    xmlTextReaderConstLocalName(reader),
1665 				    xmlTextReaderConstNamespaceUri(reader));
1666 		if (ret < 0) {
1667 		    fprintf(lint->errStream, "xmlStreamPush() failure\n");
1668                     xmlFreeStreamCtxt(lint->patstream);
1669 		    lint->patstream = NULL;
1670 		} else if (ret != match) {
1671 		    if (path == NULL) {
1672 		        path = xmlGetNodePath(
1673 		                       xmlTextReaderCurrentNode(reader));
1674 		    }
1675 		    fprintf(lint->errStream,
1676 		            "xmlPatternMatch and xmlStreamPush disagree\n");
1677                     if (path != NULL)
1678                         fprintf(lint->errStream, "  pattern %s node %s\n",
1679                                 lint->pattern, path);
1680                     else
1681 		        fprintf(lint->errStream, "  pattern %s node %s\n",
1682 			    lint->pattern, xmlTextReaderConstName(reader));
1683 		}
1684 
1685 	    }
1686 	    if ((type == XML_READER_TYPE_END_ELEMENT) ||
1687 	        ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
1688 	        ret = xmlStreamPop(lint->patstream);
1689 		if (ret < 0) {
1690 		    fprintf(lint->errStream, "xmlStreamPop() failure\n");
1691                     xmlFreeStreamCtxt(lint->patstream);
1692 		    lint->patstream = NULL;
1693 		}
1694 	    }
1695 	}
1696 	if (path != NULL)
1697 	    xmlFree(path);
1698     }
1699 #endif
1700 }
1701 
streamFile(xmllintState * lint,const char * filename)1702 static void streamFile(xmllintState *lint, const char *filename) {
1703     xmlParserInputBufferPtr input = NULL;
1704     FILE *errStream = lint->errStream;
1705     xmlTextReaderPtr reader;
1706     int ret;
1707 
1708 #if HAVE_DECL_MMAP
1709     if (lint->memory) {
1710 	reader = xmlReaderForMemory(lint->memoryData, lint->memorySize,
1711                                     filename, NULL, lint->options);
1712     } else
1713 #endif
1714     {
1715         if (strcmp(filename, "-") == 0) {
1716             reader = xmlReaderForFd(STDIN_FILENO, "-", NULL, lint->options);
1717         }
1718         else {
1719             /*
1720              * There's still no easy way to get a reader for a file with
1721              * adequate error repoting.
1722              */
1723 
1724             xmlResetLastError();
1725             input = xmlParserInputBufferCreateFilename(filename,
1726                                                        XML_CHAR_ENCODING_NONE);
1727             if (input == NULL) {
1728                 const xmlError *error = xmlGetLastError();
1729 
1730                 if ((error != NULL) && (error->code == XML_ERR_NO_MEMORY)) {
1731                     lint->progresult = XMLLINT_ERR_MEM;
1732                 } else {
1733                     fprintf(errStream, "Unable to open %s\n", filename);
1734                     lint->progresult = XMLLINT_ERR_RDFILE;
1735                 }
1736                 return;
1737             }
1738 
1739             reader = xmlNewTextReader(input, filename);
1740             if (reader == NULL) {
1741                 lint->progresult = XMLLINT_ERR_MEM;
1742                 xmlFreeParserInputBuffer(input);
1743                 return;
1744             }
1745             if (xmlTextReaderSetup(reader, NULL, NULL, NULL,
1746                                    lint->options) < 0) {
1747                 lint->progresult = XMLLINT_ERR_MEM;
1748                 xmlFreeParserInputBuffer(input);
1749                 return;
1750             }
1751         }
1752     }
1753     if (reader == NULL) {
1754         lint->progresult = XMLLINT_ERR_MEM;
1755         return;
1756     }
1757 
1758 #ifdef LIBXML_PATTERN_ENABLED
1759     if (lint->patternc != NULL) {
1760         lint->patstream = xmlPatternGetStreamCtxt(lint->patternc);
1761 	if (lint->patstream != NULL) {
1762 	    ret = xmlStreamPush(lint->patstream, NULL, NULL);
1763 	    if (ret < 0) {
1764 		fprintf(errStream, "xmlStreamPush() failure\n");
1765 		xmlFreeStreamCtxt(lint->patstream);
1766 		lint->patstream = NULL;
1767             }
1768 	}
1769     }
1770 #endif
1771 
1772 
1773     xmlTextReaderSetResourceLoader(reader, xmllintResourceLoader, lint);
1774     if (lint->maxAmpl > 0)
1775         xmlTextReaderSetMaxAmplification(reader, lint->maxAmpl);
1776 
1777 #ifdef LIBXML_SCHEMAS_ENABLED
1778     if (lint->relaxng != NULL) {
1779         if ((lint->timing) && (lint->repeat == 1)) {
1780             startTimer(lint);
1781         }
1782         ret = xmlTextReaderRelaxNGValidate(reader, lint->relaxng);
1783         if (ret < 0) {
1784             fprintf(errStream, "Relax-NG schema %s failed to compile\n",
1785                     lint->relaxng);
1786             lint->progresult = XMLLINT_ERR_SCHEMACOMP;
1787             lint->relaxng = NULL;
1788         }
1789         if ((lint->timing) && (lint->repeat == 1)) {
1790             endTimer(lint, "Compiling the schemas");
1791         }
1792     }
1793     if (lint->schema != NULL) {
1794         if ((lint->timing) && (lint->repeat == 1)) {
1795             startTimer(lint);
1796         }
1797         ret = xmlTextReaderSchemaValidate(reader, lint->schema);
1798         if (ret < 0) {
1799             fprintf(errStream, "XSD schema %s failed to compile\n",
1800                     lint->schema);
1801             lint->progresult = XMLLINT_ERR_SCHEMACOMP;
1802             lint->schema = NULL;
1803         }
1804         if ((lint->timing) && (lint->repeat == 1)) {
1805             endTimer(lint, "Compiling the schemas");
1806         }
1807     }
1808 #endif
1809 
1810     /*
1811      * Process all nodes in sequence
1812      */
1813     if ((lint->timing) && (lint->repeat == 1)) {
1814         startTimer(lint);
1815     }
1816     ret = xmlTextReaderRead(reader);
1817     while (ret == 1) {
1818         if ((lint->debug)
1819 #ifdef LIBXML_PATTERN_ENABLED
1820             || (lint->patternc)
1821 #endif
1822            )
1823             processNode(lint, reader);
1824         ret = xmlTextReaderRead(reader);
1825     }
1826     if ((lint->timing) && (lint->repeat == 1)) {
1827 #ifdef LIBXML_SCHEMAS_ENABLED
1828         if (lint->relaxng != NULL)
1829             endTimer(lint, "Parsing and validating");
1830         else
1831 #endif
1832 #ifdef LIBXML_VALID_ENABLED
1833         if (lint->options & XML_PARSE_DTDVALID)
1834             endTimer(lint, "Parsing and validating");
1835         else
1836 #endif
1837         endTimer(lint, "Parsing");
1838     }
1839 
1840 #ifdef LIBXML_VALID_ENABLED
1841     if (lint->options & XML_PARSE_DTDVALID) {
1842         if (xmlTextReaderIsValid(reader) != 1) {
1843             fprintf(errStream,
1844                     "Document %s does not validate\n", filename);
1845             lint->progresult = XMLLINT_ERR_VALID;
1846         }
1847     }
1848 #endif /* LIBXML_VALID_ENABLED */
1849 #ifdef LIBXML_SCHEMAS_ENABLED
1850     if ((lint->relaxng != NULL) || (lint->schema != NULL)) {
1851         if (xmlTextReaderIsValid(reader) != 1) {
1852             fprintf(errStream, "%s fails to validate\n", filename);
1853             lint->progresult = XMLLINT_ERR_VALID;
1854         } else {
1855             if (!lint->quiet) {
1856                 fprintf(errStream, "%s validates\n", filename);
1857             }
1858         }
1859     }
1860 #endif
1861     /*
1862      * Done, cleanup and status
1863      */
1864     xmlFreeTextReader(reader);
1865     xmlFreeParserInputBuffer(input);
1866     if (ret != 0) {
1867         fprintf(errStream, "%s : failed to parse\n", filename);
1868         lint->progresult = XMLLINT_ERR_UNCLASS;
1869     }
1870 #ifdef LIBXML_PATTERN_ENABLED
1871     if (lint->patstream != NULL) {
1872 	xmlFreeStreamCtxt(lint->patstream);
1873 	lint->patstream = NULL;
1874     }
1875 #endif
1876 }
1877 
walkDoc(xmllintState * lint,xmlDocPtr doc)1878 static void walkDoc(xmllintState *lint, xmlDocPtr doc) {
1879     FILE *errStream = lint->errStream;
1880     xmlTextReaderPtr reader;
1881     int ret;
1882 
1883 #ifdef LIBXML_PATTERN_ENABLED
1884     if (lint->pattern != NULL) {
1885         xmlNodePtr root;
1886         const xmlChar *namespaces[22];
1887         int i;
1888         xmlNsPtr ns;
1889 
1890         root = xmlDocGetRootElement(doc);
1891         if (root == NULL ) {
1892             fprintf(errStream,
1893                     "Document does not have a root element");
1894             lint->progresult = XMLLINT_ERR_UNCLASS;
1895             return;
1896         }
1897         for (ns = root->nsDef, i = 0;ns != NULL && i < 20;ns=ns->next) {
1898             namespaces[i++] = ns->href;
1899             namespaces[i++] = ns->prefix;
1900         }
1901         namespaces[i++] = NULL;
1902         namespaces[i] = NULL;
1903 
1904         ret = xmlPatternCompileSafe((const xmlChar *) lint->pattern, doc->dict,
1905                                     0, &namespaces[0], &lint->patternc);
1906 	if (lint->patternc == NULL) {
1907             if (ret < 0) {
1908                 lint->progresult = XMLLINT_ERR_MEM;
1909             } else {
1910                 fprintf(errStream, "Pattern %s failed to compile\n",
1911                         lint->pattern);
1912                 lint->progresult = XMLLINT_ERR_SCHEMAPAT;
1913             }
1914             goto error;
1915 	}
1916 
1917         lint->patstream = xmlPatternGetStreamCtxt(lint->patternc);
1918         if (lint->patstream == NULL) {
1919             lint->progresult = XMLLINT_ERR_MEM;
1920             goto error;
1921         }
1922 
1923         ret = xmlStreamPush(lint->patstream, NULL, NULL);
1924         if (ret < 0) {
1925             fprintf(errStream, "xmlStreamPush() failure\n");
1926             lint->progresult = XMLLINT_ERR_MEM;
1927             goto error;
1928         }
1929     }
1930 #endif /* LIBXML_PATTERN_ENABLED */
1931     reader = xmlReaderWalker(doc);
1932     if (reader != NULL) {
1933 	if ((lint->timing) && (lint->repeat == 1)) {
1934 	    startTimer(lint);
1935 	}
1936 	ret = xmlTextReaderRead(reader);
1937 	while (ret == 1) {
1938 	    if ((lint->debug)
1939 #ifdef LIBXML_PATTERN_ENABLED
1940 	        || (lint->patternc)
1941 #endif
1942 	       )
1943 		processNode(lint, reader);
1944 	    ret = xmlTextReaderRead(reader);
1945 	}
1946 	if ((lint->timing) && (lint->repeat == 1)) {
1947 	    endTimer(lint, "walking through the doc");
1948 	}
1949 	xmlFreeTextReader(reader);
1950 	if (ret != 0) {
1951 	    fprintf(errStream, "failed to walk through the doc\n");
1952 	    lint->progresult = XMLLINT_ERR_UNCLASS;
1953 	}
1954     } else {
1955 	fprintf(errStream, "Failed to create a reader from the document\n");
1956 	lint->progresult = XMLLINT_ERR_UNCLASS;
1957     }
1958 
1959 #ifdef LIBXML_PATTERN_ENABLED
1960 error:
1961     if (lint->patternc != NULL) {
1962         xmlFreePattern(lint->patternc);
1963         lint->patternc = NULL;
1964     }
1965     if (lint->patstream != NULL) {
1966 	xmlFreeStreamCtxt(lint->patstream);
1967 	lint->patstream = NULL;
1968     }
1969 #endif
1970 }
1971 #endif /* LIBXML_READER_ENABLED */
1972 
1973 #ifdef LIBXML_XPATH_ENABLED
1974 /************************************************************************
1975  *									*
1976  *			XPath Query                                     *
1977  *									*
1978  ************************************************************************/
1979 
1980 static void
doXPathDump(xmllintState * lint,xmlXPathObjectPtr cur)1981 doXPathDump(xmllintState *lint, xmlXPathObjectPtr cur) {
1982     switch(cur->type) {
1983         case XPATH_NODESET: {
1984 #ifdef LIBXML_OUTPUT_ENABLED
1985             xmlOutputBufferPtr buf;
1986             xmlNodePtr node;
1987             int i;
1988 
1989             if ((cur->nodesetval == NULL) || (cur->nodesetval->nodeNr <= 0)) {
1990                 lint->progresult = XMLLINT_ERR_XPATH_EMPTY;
1991                 if (!lint->quiet) {
1992                     fprintf(lint->errStream, "XPath set is empty\n");
1993                 }
1994                 break;
1995             }
1996             buf = xmlOutputBufferCreateFile(stdout, NULL);
1997             if (buf == NULL) {
1998                 lint->progresult = XMLLINT_ERR_MEM;
1999                 return;
2000             }
2001             for (i = 0;i < cur->nodesetval->nodeNr;i++) {
2002                 node = cur->nodesetval->nodeTab[i];
2003                 xmlNodeDumpOutput(buf, NULL, node, 0, 0, NULL);
2004                 xmlOutputBufferWrite(buf, 1, "\n");
2005             }
2006             xmlOutputBufferClose(buf);
2007 #else
2008             printf("xpath returned %d nodes\n", cur->nodesetval->nodeNr);
2009 #endif
2010 	    break;
2011         }
2012         case XPATH_BOOLEAN:
2013 	    if (cur->boolval) printf("true\n");
2014 	    else printf("false\n");
2015 	    break;
2016         case XPATH_NUMBER:
2017 	    switch (xmlXPathIsInf(cur->floatval)) {
2018 	    case 1:
2019 		printf("Infinity\n");
2020 		break;
2021 	    case -1:
2022 		printf("-Infinity\n");
2023 		break;
2024 	    default:
2025 		if (xmlXPathIsNaN(cur->floatval)) {
2026 		    printf("NaN\n");
2027 		} else {
2028 		    printf("%0g\n", cur->floatval);
2029 		}
2030 	    }
2031 	    break;
2032         case XPATH_STRING:
2033 	    printf("%s\n", (const char *) cur->stringval);
2034 	    break;
2035         case XPATH_UNDEFINED:
2036 	    fprintf(lint->errStream, "XPath Object is uninitialized\n");
2037             lint->progresult = XMLLINT_ERR_XPATH;
2038 	    break;
2039 	default:
2040 	    fprintf(lint->errStream, "XPath object of unexpected type\n");
2041             lint->progresult = XMLLINT_ERR_XPATH;
2042 	    break;
2043     }
2044 }
2045 
2046 static void
doXPathQuery(xmllintState * lint,xmlDocPtr doc,const char * query)2047 doXPathQuery(xmllintState *lint, xmlDocPtr doc, const char *query) {
2048     xmlXPathContextPtr ctxt = NULL;
2049     xmlXPathCompExprPtr comp = NULL;
2050     xmlXPathObjectPtr res = NULL;
2051 
2052     ctxt = xmlXPathNewContext(doc);
2053     if (ctxt == NULL) {
2054         lint->progresult = XMLLINT_ERR_MEM;
2055         goto error;
2056     }
2057 
2058     comp = xmlXPathCtxtCompile(ctxt, BAD_CAST query);
2059     if (comp == NULL) {
2060         fprintf(lint->errStream, "XPath compilation failure\n");
2061         lint->progresult = XMLLINT_ERR_XPATH;
2062         goto error;
2063     }
2064 
2065 #ifdef LIBXML_DEBUG_ENABLED
2066     if (lint->debug) {
2067         xmlXPathDebugDumpCompExpr(stdout, comp, 0);
2068         printf("\n");
2069     }
2070 #endif
2071 
2072     ctxt->node = (xmlNodePtr) doc;
2073     res = xmlXPathCompiledEval(comp, ctxt);
2074     if (res == NULL) {
2075         fprintf(lint->errStream, "XPath evaluation failure\n");
2076         lint->progresult = XMLLINT_ERR_XPATH;
2077         goto error;
2078     }
2079 
2080     doXPathDump(lint, res);
2081 
2082 error:
2083     xmlXPathFreeObject(res);
2084     xmlXPathFreeCompExpr(comp);
2085     xmlXPathFreeContext(ctxt);
2086 }
2087 #endif /* LIBXML_XPATH_ENABLED */
2088 
2089 /************************************************************************
2090  *									*
2091  *			Tree Test processing				*
2092  *									*
2093  ************************************************************************/
2094 
2095 static xmlDocPtr
parseFile(xmllintState * lint,const char * filename)2096 parseFile(xmllintState *lint, const char *filename) {
2097     xmlDocPtr doc = NULL;
2098 
2099     if ((lint->generate) && (filename == NULL)) {
2100         xmlNodePtr n;
2101 
2102         doc = xmlNewDoc(BAD_CAST "1.0");
2103         if (doc == NULL) {
2104             lint->progresult = XMLLINT_ERR_MEM;
2105             return(NULL);
2106         }
2107         n = xmlNewDocNode(doc, NULL, BAD_CAST "info", NULL);
2108         if (n == NULL) {
2109             xmlFreeDoc(doc);
2110             lint->progresult = XMLLINT_ERR_MEM;
2111             return(NULL);
2112         }
2113         if (xmlNodeSetContent(n, BAD_CAST "abc") < 0) {
2114             xmlFreeNode(n);
2115             xmlFreeDoc(doc);
2116             lint->progresult = XMLLINT_ERR_MEM;
2117             return(NULL);
2118         }
2119         xmlDocSetRootElement(doc, n);
2120 
2121         return(doc);
2122     }
2123 
2124 #ifdef LIBXML_HTML_ENABLED
2125     if (lint->html) {
2126         doc = parseHtml(lint, filename);
2127         return(doc);
2128     }
2129 #endif /* LIBXML_HTML_ENABLED */
2130     {
2131         doc = parseXml(lint, filename);
2132     }
2133 
2134     if (doc == NULL) {
2135         if (lint->ctxt->errNo == XML_ERR_NO_MEMORY)
2136             lint->progresult = XMLLINT_ERR_MEM;
2137         else
2138 	    lint->progresult = XMLLINT_ERR_RDFILE;
2139     } else {
2140 #ifdef LIBXML_VALID_ENABLED
2141         if ((lint->options & XML_PARSE_DTDVALID) && (lint->ctxt->valid == 0))
2142             lint->progresult = XMLLINT_ERR_VALID;
2143 #endif /* LIBXML_VALID_ENABLED */
2144     }
2145 
2146     return(doc);
2147 }
2148 
2149 static void
parseAndPrintFile(xmllintState * lint,const char * filename)2150 parseAndPrintFile(xmllintState *lint, const char *filename) {
2151     FILE *errStream = lint->errStream;
2152     xmlDocPtr doc;
2153 
2154     /* Avoid unused variable warning */
2155     (void) errStream;
2156 
2157     if ((lint->timing) && (lint->repeat == 1))
2158 	startTimer(lint);
2159 
2160     doc = parseFile(lint, filename);
2161     if (doc == NULL) {
2162         if (lint->progresult == XMLLINT_RETURN_OK)
2163             lint->progresult = XMLLINT_ERR_UNCLASS;
2164 	return;
2165     }
2166 
2167     if ((lint->timing) && (lint->repeat == 1)) {
2168 	endTimer(lint, "Parsing");
2169     }
2170 
2171     if (lint->dropdtd) {
2172 	xmlDtdPtr dtd;
2173 
2174 	dtd = xmlGetIntSubset(doc);
2175 	if (dtd != NULL) {
2176 	    xmlUnlinkNode((xmlNodePtr)dtd);
2177             doc->intSubset = dtd;
2178 	}
2179     }
2180 
2181 #ifdef LIBXML_XINCLUDE_ENABLED
2182     if (lint->xinclude) {
2183 	if ((lint->timing) && (lint->repeat == 1)) {
2184 	    startTimer(lint);
2185 	}
2186 	if (xmlXIncludeProcessFlags(doc, lint->options) < 0) {
2187 	    lint->progresult = XMLLINT_ERR_UNCLASS;
2188             goto done;
2189         }
2190 	if ((lint->timing) && (lint->repeat == 1)) {
2191 	    endTimer(lint, "Xinclude processing");
2192 	}
2193     }
2194 #endif
2195 
2196     /*
2197      * shell interaction
2198      */
2199     if (lint->shell) {
2200 #ifdef LIBXML_XPATH_ENABLED
2201         xmlXPathOrderDocElems(doc);
2202 #endif
2203         xmllintShell(doc, filename, stdout);
2204         goto done;
2205     }
2206 
2207 #ifdef LIBXML_XPATH_ENABLED
2208     if (lint->xpathquery != NULL) {
2209 	xmlXPathOrderDocElems(doc);
2210         doXPathQuery(lint, doc, lint->xpathquery);
2211     }
2212 #endif
2213 
2214     /*
2215      * test intermediate copy if needed.
2216      */
2217     if (lint->copy) {
2218         xmlDocPtr tmp;
2219 
2220         tmp = doc;
2221 	if (lint->timing) {
2222 	    startTimer(lint);
2223 	}
2224 	doc = xmlCopyDoc(doc, 1);
2225         if (doc == NULL) {
2226             lint->progresult = XMLLINT_ERR_MEM;
2227             xmlFreeDoc(tmp);
2228             return;
2229         }
2230 	if (lint->timing) {
2231 	    endTimer(lint, "Copying");
2232 	}
2233 	if (lint->timing) {
2234 	    startTimer(lint);
2235 	}
2236 	xmlFreeDoc(tmp);
2237 	if (lint->timing) {
2238 	    endTimer(lint, "Freeing original");
2239 	}
2240     }
2241 
2242 #ifdef LIBXML_VALID_ENABLED
2243     if ((lint->insert)
2244 #ifdef LIBXML_HTML_ENABLED
2245         && (!lint->html)
2246 #endif
2247     ) {
2248         const xmlChar* list[256];
2249 	int nb, i;
2250 	xmlNodePtr node;
2251 
2252 	if (doc->children != NULL) {
2253 	    node = doc->children;
2254 	    while ((node != NULL) &&
2255                    ((node->type != XML_ELEMENT_NODE) ||
2256                     (node->last == NULL)))
2257                 node = node->next;
2258 	    if (node != NULL) {
2259 		nb = xmlValidGetValidElements(node->last, NULL, list, 256);
2260 		if (nb < 0) {
2261 		    fprintf(errStream, "could not get valid list of elements\n");
2262 		} else if (nb == 0) {
2263 		    fprintf(errStream, "No element can be inserted under root\n");
2264 		} else {
2265 		    fprintf(errStream, "%d element types can be inserted under root:\n",
2266 		           nb);
2267 		    for (i = 0;i < nb;i++) {
2268 			 fprintf(errStream, "%s\n", (char *) list[i]);
2269 		    }
2270 		}
2271 	    }
2272 	}
2273     } else
2274 #endif /* LIBXML_VALID_ENABLED */
2275 #ifdef LIBXML_READER_ENABLED
2276     if (lint->walker) {
2277         walkDoc(lint, doc);
2278     }
2279 #endif /* LIBXML_READER_ENABLED */
2280 #ifdef LIBXML_OUTPUT_ENABLED
2281     if (lint->noout == 0) {
2282         if (lint->compress)
2283             xmlSetDocCompressMode(doc, 9);
2284 
2285 	/*
2286 	 * print it.
2287 	 */
2288 #ifdef LIBXML_DEBUG_ENABLED
2289 	if (!lint->debug) {
2290 #endif
2291 	    if ((lint->timing) && (lint->repeat == 1)) {
2292 		startTimer(lint);
2293 	    }
2294 #ifdef LIBXML_HTML_ENABLED
2295             if ((lint->html) && (!lint->xmlout)) {
2296 		if (lint->compress) {
2297 		    htmlSaveFile(lint->output ? lint->output : "-", doc);
2298 		}
2299 		else if (lint->encoding != NULL) {
2300 		    if (lint->format == 1) {
2301 			htmlSaveFileFormat(lint->output ? lint->output : "-",
2302                                            doc, lint->encoding, 1);
2303 		    }
2304 		    else {
2305 			htmlSaveFileFormat(lint->output ? lint->output : "-",
2306                                            doc, lint->encoding, 0);
2307 		    }
2308 		}
2309 		else if (lint->format == 1) {
2310 		    htmlSaveFileFormat(lint->output ? lint->output : "-",
2311                                        doc, NULL, 1);
2312 		}
2313 		else {
2314 		    FILE *out;
2315 		    if (lint->output == NULL)
2316 			out = stdout;
2317 		    else {
2318 			out = fopen(lint->output,"wb");
2319 		    }
2320 		    if (out != NULL) {
2321 			if (htmlDocDump(out, doc) < 0)
2322 			    lint->progresult = XMLLINT_ERR_OUT;
2323 
2324 			if (lint->output != NULL)
2325 			    fclose(out);
2326 		    } else {
2327 			fprintf(errStream, "failed to open %s\n",
2328                                 lint->output);
2329 			lint->progresult = XMLLINT_ERR_OUT;
2330 		    }
2331 		}
2332 		if ((lint->timing) && (lint->repeat == 1)) {
2333 		    endTimer(lint, "Saving");
2334 		}
2335 	    } else
2336 #endif
2337 #ifdef LIBXML_C14N_ENABLED
2338             if (lint->canonical) {
2339 	        xmlChar *result = NULL;
2340 		int size;
2341 
2342 		size = xmlC14NDocDumpMemory(doc, NULL, XML_C14N_1_0, NULL, 1, &result);
2343 		if (size >= 0) {
2344 		    if (write(1, result, size) == -1) {
2345 		        fprintf(errStream, "Can't write data\n");
2346 		    }
2347 		    xmlFree(result);
2348 		} else {
2349 		    fprintf(errStream, "Failed to canonicalize\n");
2350 		    lint->progresult = XMLLINT_ERR_OUT;
2351 		}
2352 	    } else if (lint->canonical_11) {
2353 	        xmlChar *result = NULL;
2354 		int size;
2355 
2356 		size = xmlC14NDocDumpMemory(doc, NULL, XML_C14N_1_1, NULL, 1, &result);
2357 		if (size >= 0) {
2358 		    if (write(1, result, size) == -1) {
2359 		        fprintf(errStream, "Can't write data\n");
2360 		    }
2361 		    xmlFree(result);
2362 		} else {
2363 		    fprintf(errStream, "Failed to canonicalize\n");
2364 		    lint->progresult = XMLLINT_ERR_OUT;
2365 		}
2366 	    } else if (lint->exc_canonical) {
2367 	        xmlChar *result = NULL;
2368 		int size;
2369 
2370 		size = xmlC14NDocDumpMemory(doc, NULL, XML_C14N_EXCLUSIVE_1_0, NULL, 1, &result);
2371 		if (size >= 0) {
2372 		    if (write(1, result, size) == -1) {
2373 		        fprintf(errStream, "Can't write data\n");
2374 		    }
2375 		    xmlFree(result);
2376 		} else {
2377 		    fprintf(errStream, "Failed to canonicalize\n");
2378 		    lint->progresult = XMLLINT_ERR_OUT;
2379 		}
2380 	    } else
2381 #endif
2382 #if HAVE_DECL_MMAP
2383 	    if (lint->memory) {
2384 		xmlChar *result;
2385 		int len;
2386 
2387 		if (lint->encoding != NULL) {
2388 		    if (lint->format == 1) {
2389 		        xmlDocDumpFormatMemoryEnc(doc, &result, &len,
2390                                                   lint->encoding, 1);
2391 		    } else {
2392 			xmlDocDumpMemoryEnc(doc, &result, &len,
2393                                             lint->encoding);
2394 		    }
2395 		} else {
2396 		    if (lint->format == 1)
2397 			xmlDocDumpFormatMemory(doc, &result, &len, 1);
2398 		    else
2399 			xmlDocDumpMemory(doc, &result, &len);
2400 		}
2401 		if (result == NULL) {
2402 		    fprintf(errStream, "Failed to save\n");
2403 		    lint->progresult = XMLLINT_ERR_OUT;
2404 		} else {
2405 		    if (write(1, result, len) == -1) {
2406 		        fprintf(errStream, "Can't write data\n");
2407 		    }
2408 		    xmlFree(result);
2409 		}
2410 
2411 	    } else
2412 #endif /* HAVE_DECL_MMAP */
2413 	    if (lint->compress) {
2414 		xmlSaveFile(lint->output ? lint->output : "-", doc);
2415 	    } else {
2416 	        xmlSaveCtxtPtr ctxt;
2417 		int saveOpts = 0;
2418 
2419                 if (lint->format == 1)
2420 		    saveOpts |= XML_SAVE_FORMAT;
2421                 else if (lint->format == 2)
2422                     saveOpts |= XML_SAVE_WSNONSIG;
2423 
2424 #if defined(LIBXML_HTML_ENABLED)
2425                 if (lint->xmlout)
2426                     saveOpts |= XML_SAVE_AS_XML;
2427 #endif
2428 
2429 		if (lint->output == NULL)
2430 		    ctxt = xmlSaveToFd(STDOUT_FILENO, lint->encoding,
2431                                        saveOpts);
2432 		else
2433 		    ctxt = xmlSaveToFilename(lint->output, lint->encoding,
2434                                              saveOpts);
2435 
2436 		if (ctxt != NULL) {
2437 		    if (xmlSaveDoc(ctxt, doc) < 0) {
2438 			fprintf(errStream, "failed save to %s\n",
2439 				lint->output ? lint->output : "-");
2440 			lint->progresult = XMLLINT_ERR_OUT;
2441 		    }
2442 		    xmlSaveClose(ctxt);
2443 		} else {
2444 		    lint->progresult = XMLLINT_ERR_OUT;
2445 		}
2446 	    }
2447 	    if ((lint->timing) && (lint->repeat == 1)) {
2448 		endTimer(lint, "Saving");
2449 	    }
2450 #ifdef LIBXML_DEBUG_ENABLED
2451 	} else {
2452 	    FILE *out;
2453 	    if (lint->output == NULL)
2454 	        out = stdout;
2455 	    else {
2456 		out = fopen(lint->output, "wb");
2457 	    }
2458 	    if (out != NULL) {
2459 		xmlDebugDumpDocument(out, doc);
2460 
2461 		if (lint->output != NULL)
2462 		    fclose(out);
2463 	    } else {
2464 		fprintf(errStream, "failed to open %s\n", lint->output);
2465 		lint->progresult = XMLLINT_ERR_OUT;
2466 	    }
2467 	}
2468 #endif
2469     }
2470 #endif /* LIBXML_OUTPUT_ENABLED */
2471 
2472 #ifdef LIBXML_VALID_ENABLED
2473     /*
2474      * A posteriori validation test
2475      */
2476     if ((lint->dtdvalid != NULL) || (lint->dtdvalidfpi != NULL)) {
2477 	xmlDtdPtr dtd;
2478 
2479 	if ((lint->timing) && (lint->repeat == 1)) {
2480 	    startTimer(lint);
2481 	}
2482 	if (lint->dtdvalid != NULL)
2483 	    dtd = xmlParseDTD(NULL, BAD_CAST lint->dtdvalid);
2484 	else
2485 	    dtd = xmlParseDTD(BAD_CAST lint->dtdvalidfpi, NULL);
2486 	if ((lint->timing) && (lint->repeat == 1)) {
2487 	    endTimer(lint, "Parsing DTD");
2488 	}
2489 	if (dtd == NULL) {
2490 	    if (lint->dtdvalid != NULL)
2491 		fprintf(errStream, "Could not parse DTD %s\n",
2492                         lint->dtdvalid);
2493 	    else
2494 		fprintf(errStream, "Could not parse DTD %s\n",
2495                         lint->dtdvalidfpi);
2496 	    lint->progresult = XMLLINT_ERR_DTD;
2497 	} else {
2498 	    xmlValidCtxtPtr cvp;
2499 
2500 	    cvp = xmlNewValidCtxt();
2501 	    if (cvp == NULL) {
2502                 lint->progresult = XMLLINT_ERR_MEM;
2503                 xmlFreeDtd(dtd);
2504                 return;
2505 	    }
2506 
2507 	    if ((lint->timing) && (lint->repeat == 1)) {
2508 		startTimer(lint);
2509 	    }
2510 	    if (!xmlValidateDtd(cvp, doc, dtd)) {
2511 		if (lint->dtdvalid != NULL)
2512 		    fprintf(errStream,
2513 			    "Document %s does not validate against %s\n",
2514 			    filename, lint->dtdvalid);
2515 		else
2516 		    fprintf(errStream,
2517 			    "Document %s does not validate against %s\n",
2518 			    filename, lint->dtdvalidfpi);
2519 		lint->progresult = XMLLINT_ERR_VALID;
2520 	    }
2521 	    if ((lint->timing) && (lint->repeat == 1)) {
2522 		endTimer(lint, "Validating against DTD");
2523 	    }
2524 	    xmlFreeValidCtxt(cvp);
2525 	    xmlFreeDtd(dtd);
2526 	}
2527     } else if (lint->postvalid) {
2528 	xmlValidCtxtPtr cvp;
2529 
2530 	cvp = xmlNewValidCtxt();
2531 	if (cvp == NULL) {
2532             lint->progresult = XMLLINT_ERR_MEM;
2533             xmlFreeDoc(doc);
2534             return;
2535 	}
2536 
2537 	if ((lint->timing) && (lint->repeat == 1)) {
2538 	    startTimer(lint);
2539 	}
2540 	if (!xmlValidateDocument(cvp, doc)) {
2541 	    fprintf(errStream,
2542 		    "Document %s does not validate\n", filename);
2543 	    lint->progresult = XMLLINT_ERR_VALID;
2544 	}
2545 	if ((lint->timing) && (lint->repeat == 1)) {
2546 	    endTimer(lint, "Validating");
2547 	}
2548 	xmlFreeValidCtxt(cvp);
2549     }
2550 #endif /* LIBXML_VALID_ENABLED */
2551 #ifdef LIBXML_SCHEMATRON_ENABLED
2552     if (lint->wxschematron != NULL) {
2553 	xmlSchematronValidCtxtPtr ctxt;
2554 	int ret;
2555 	int flag;
2556 
2557 	if ((lint->timing) && (lint->repeat == 1)) {
2558 	    startTimer(lint);
2559 	}
2560 
2561 	if (lint->debug)
2562 	    flag = XML_SCHEMATRON_OUT_XML;
2563 	else
2564 	    flag = XML_SCHEMATRON_OUT_TEXT;
2565 	if (lint->noout)
2566 	    flag |= XML_SCHEMATRON_OUT_QUIET;
2567 	ctxt = xmlSchematronNewValidCtxt(lint->wxschematron, flag);
2568         if (ctxt == NULL) {
2569             lint->progresult = XMLLINT_ERR_MEM;
2570             xmlFreeDoc(doc);
2571             return;
2572         }
2573 	ret = xmlSchematronValidateDoc(ctxt, doc);
2574 	if (ret == 0) {
2575 	    if (!lint->quiet) {
2576 	        fprintf(errStream, "%s validates\n", filename);
2577 	    }
2578 	} else if (ret > 0) {
2579 	    fprintf(errStream, "%s fails to validate\n", filename);
2580 	    lint->progresult = XMLLINT_ERR_VALID;
2581 	} else {
2582 	    fprintf(errStream, "%s validation generated an internal error\n",
2583 		   filename);
2584 	    lint->progresult = XMLLINT_ERR_VALID;
2585 	}
2586 	xmlSchematronFreeValidCtxt(ctxt);
2587 	if ((lint->timing) && (lint->repeat == 1)) {
2588 	    endTimer(lint, "Validating");
2589 	}
2590     }
2591 #endif
2592 #ifdef LIBXML_SCHEMAS_ENABLED
2593     if (lint->relaxngschemas != NULL) {
2594 	xmlRelaxNGValidCtxtPtr ctxt;
2595 	int ret;
2596 
2597 	if ((lint->timing) && (lint->repeat == 1)) {
2598 	    startTimer(lint);
2599 	}
2600 
2601 	ctxt = xmlRelaxNGNewValidCtxt(lint->relaxngschemas);
2602         if (ctxt == NULL) {
2603             lint->progresult = XMLLINT_ERR_MEM;
2604             xmlFreeDoc(doc);
2605             return;
2606         }
2607 	ret = xmlRelaxNGValidateDoc(ctxt, doc);
2608 	if (ret == 0) {
2609 	    if (!lint->quiet) {
2610 	        fprintf(errStream, "%s validates\n", filename);
2611 	    }
2612 	} else if (ret > 0) {
2613 	    fprintf(errStream, "%s fails to validate\n", filename);
2614 	    lint->progresult = XMLLINT_ERR_VALID;
2615 	} else {
2616 	    fprintf(errStream, "%s validation generated an internal error\n",
2617 		   filename);
2618 	    lint->progresult = XMLLINT_ERR_VALID;
2619 	}
2620 	xmlRelaxNGFreeValidCtxt(ctxt);
2621 	if ((lint->timing) && (lint->repeat == 1)) {
2622 	    endTimer(lint, "Validating");
2623 	}
2624     } else if (lint->wxschemas != NULL) {
2625 	xmlSchemaValidCtxtPtr ctxt;
2626 	int ret;
2627 
2628 	if ((lint->timing) && (lint->repeat == 1)) {
2629 	    startTimer(lint);
2630 	}
2631 
2632 	ctxt = xmlSchemaNewValidCtxt(lint->wxschemas);
2633         if (ctxt == NULL) {
2634             lint->progresult = XMLLINT_ERR_MEM;
2635             xmlFreeDoc(doc);
2636             return;
2637         }
2638 	ret = xmlSchemaValidateDoc(ctxt, doc);
2639 	if (ret == 0) {
2640 	    if (!lint->quiet) {
2641 	        fprintf(errStream, "%s validates\n", filename);
2642 	    }
2643 	} else if (ret > 0) {
2644 	    fprintf(errStream, "%s fails to validate\n", filename);
2645 	    lint->progresult = XMLLINT_ERR_VALID;
2646 	} else {
2647 	    fprintf(errStream, "%s validation generated an internal error\n",
2648 		   filename);
2649 	    lint->progresult = XMLLINT_ERR_VALID;
2650 	}
2651 	xmlSchemaFreeValidCtxt(ctxt);
2652 	if ((lint->timing) && (lint->repeat == 1)) {
2653 	    endTimer(lint, "Validating");
2654 	}
2655     }
2656 #endif
2657 
2658 #ifdef LIBXML_DEBUG_ENABLED
2659     if ((lint->debugent)
2660 #if defined(LIBXML_HTML_ENABLED)
2661         && (!lint->html)
2662 #endif
2663     )
2664 	xmlDebugDumpEntities(errStream, doc);
2665 #endif
2666 
2667     /* Avoid unused label warning */
2668     goto done;
2669 
2670 done:
2671     /*
2672      * free it.
2673      */
2674     if ((lint->timing) && (lint->repeat == 1)) {
2675 	startTimer(lint);
2676     }
2677     xmlFreeDoc(doc);
2678     if ((lint->timing) && (lint->repeat == 1)) {
2679 	endTimer(lint, "Freeing");
2680     }
2681 }
2682 
2683 /************************************************************************
2684  *									*
2685  *			Usage and Main					*
2686  *									*
2687  ************************************************************************/
2688 
showVersion(FILE * errStream,const char * name)2689 static void showVersion(FILE *errStream, const char *name) {
2690     fprintf(errStream, "%s: using libxml version %s\n", name, xmlParserVersion);
2691     fprintf(errStream, "   compiled with: ");
2692     if (xmlHasFeature(XML_WITH_THREAD)) fprintf(errStream, "Threads ");
2693     if (xmlHasFeature(XML_WITH_TREE)) fprintf(errStream, "Tree ");
2694     if (xmlHasFeature(XML_WITH_OUTPUT)) fprintf(errStream, "Output ");
2695     if (xmlHasFeature(XML_WITH_PUSH)) fprintf(errStream, "Push ");
2696     if (xmlHasFeature(XML_WITH_READER)) fprintf(errStream, "Reader ");
2697     if (xmlHasFeature(XML_WITH_PATTERN)) fprintf(errStream, "Patterns ");
2698     if (xmlHasFeature(XML_WITH_WRITER)) fprintf(errStream, "Writer ");
2699     if (xmlHasFeature(XML_WITH_SAX1)) fprintf(errStream, "SAXv1 ");
2700     if (xmlHasFeature(XML_WITH_HTTP)) fprintf(errStream, "HTTP ");
2701     if (xmlHasFeature(XML_WITH_VALID)) fprintf(errStream, "DTDValid ");
2702     if (xmlHasFeature(XML_WITH_HTML)) fprintf(errStream, "HTML ");
2703     if (xmlHasFeature(XML_WITH_LEGACY)) fprintf(errStream, "Legacy ");
2704     if (xmlHasFeature(XML_WITH_C14N)) fprintf(errStream, "C14N ");
2705     if (xmlHasFeature(XML_WITH_CATALOG)) fprintf(errStream, "Catalog ");
2706     if (xmlHasFeature(XML_WITH_XPATH)) fprintf(errStream, "XPath ");
2707     if (xmlHasFeature(XML_WITH_XPTR)) fprintf(errStream, "XPointer ");
2708     if (xmlHasFeature(XML_WITH_XINCLUDE)) fprintf(errStream, "XInclude ");
2709     if (xmlHasFeature(XML_WITH_ICONV)) fprintf(errStream, "Iconv ");
2710     if (xmlHasFeature(XML_WITH_ICU)) fprintf(errStream, "ICU ");
2711     if (xmlHasFeature(XML_WITH_ISO8859X)) fprintf(errStream, "ISO8859X ");
2712     if (xmlHasFeature(XML_WITH_UNICODE)) fprintf(errStream, "Unicode ");
2713     if (xmlHasFeature(XML_WITH_REGEXP)) fprintf(errStream, "Regexps ");
2714     if (xmlHasFeature(XML_WITH_AUTOMATA)) fprintf(errStream, "Automata ");
2715     if (xmlHasFeature(XML_WITH_EXPR)) fprintf(errStream, "Expr ");
2716     if (xmlHasFeature(XML_WITH_SCHEMAS)) fprintf(errStream, "Schemas ");
2717     if (xmlHasFeature(XML_WITH_SCHEMATRON)) fprintf(errStream, "Schematron ");
2718     if (xmlHasFeature(XML_WITH_MODULES)) fprintf(errStream, "Modules ");
2719     if (xmlHasFeature(XML_WITH_DEBUG)) fprintf(errStream, "Debug ");
2720     if (xmlHasFeature(XML_WITH_ZLIB)) fprintf(errStream, "Zlib ");
2721     if (xmlHasFeature(XML_WITH_LZMA)) fprintf(errStream, "Lzma ");
2722     fprintf(errStream, "\n");
2723 }
2724 
usage(FILE * f,const char * name)2725 static void usage(FILE *f, const char *name) {
2726     fprintf(f, "Usage : %s [options] XMLfiles ...\n", name);
2727 #ifdef LIBXML_OUTPUT_ENABLED
2728     fprintf(f, "\tParse the XML files and output the result of the parsing\n");
2729 #else
2730     fprintf(f, "\tParse the XML files\n");
2731 #endif /* LIBXML_OUTPUT_ENABLED */
2732     fprintf(f, "\t--version : display the version of the XML library used\n");
2733     fprintf(f, "\t--shell : run a navigating shell\n");
2734 #ifdef LIBXML_DEBUG_ENABLED
2735     fprintf(f, "\t--debug : dump a debug tree of the in-memory document\n");
2736     fprintf(f, "\t--debugent : debug the entities defined in the document\n");
2737 #else
2738 #ifdef LIBXML_READER_ENABLED
2739     fprintf(f, "\t--debug : dump the nodes content when using --stream\n");
2740 #endif /* LIBXML_READER_ENABLED */
2741 #endif
2742     fprintf(f, "\t--copy : used to test the internal copy implementation\n");
2743     fprintf(f, "\t--recover : output what was parsable on broken XML documents\n");
2744     fprintf(f, "\t--huge : remove any internal arbitrary parser limits\n");
2745     fprintf(f, "\t--noent : substitute entity references by their value\n");
2746     fprintf(f, "\t--noenc : ignore any encoding specified inside the document\n");
2747     fprintf(f, "\t--noout : don't output the result tree\n");
2748     fprintf(f, "\t--path 'paths': provide a set of paths for resources\n");
2749     fprintf(f, "\t--load-trace : print trace of all external entities loaded\n");
2750     fprintf(f, "\t--nonet : refuse to fetch DTDs or entities over network\n");
2751     fprintf(f, "\t--nocompact : do not generate compact text nodes\n");
2752     fprintf(f, "\t--htmlout : output results as HTML\n");
2753     fprintf(f, "\t--nowrap : do not put HTML doc wrapper\n");
2754 #ifdef LIBXML_VALID_ENABLED
2755     fprintf(f, "\t--valid : validate the document in addition to std well-formed check\n");
2756     fprintf(f, "\t--postvalid : do a posteriori validation, i.e after parsing\n");
2757     fprintf(f, "\t--dtdvalid URL : do a posteriori validation against a given DTD\n");
2758     fprintf(f, "\t--dtdvalidfpi FPI : same but name the DTD with a Public Identifier\n");
2759     fprintf(f, "\t--insert : ad-hoc test for valid insertions\n");
2760 #endif /* LIBXML_VALID_ENABLED */
2761     fprintf(f, "\t--quiet : be quiet when succeeded\n");
2762     fprintf(f, "\t--timing : print some timings\n");
2763     fprintf(f, "\t--repeat : repeat 100 times, for timing or profiling\n");
2764     fprintf(f, "\t--dropdtd : remove the DOCTYPE of the input docs\n");
2765 #ifdef LIBXML_HTML_ENABLED
2766     fprintf(f, "\t--html : use the HTML parser\n");
2767     fprintf(f, "\t--xmlout : force to use the XML serializer when using --html\n");
2768     fprintf(f, "\t--nodefdtd : do not default HTML doctype\n");
2769 #endif
2770 #ifdef LIBXML_PUSH_ENABLED
2771     fprintf(f, "\t--push : use the push mode of the parser\n");
2772 #endif /* LIBXML_PUSH_ENABLED */
2773 #if HAVE_DECL_MMAP
2774     fprintf(f, "\t--memory : parse from memory\n");
2775 #endif
2776     fprintf(f, "\t--maxmem nbbytes : limits memory allocation to nbbytes bytes\n");
2777     fprintf(f, "\t--nowarning : do not emit warnings from parser/validator\n");
2778     fprintf(f, "\t--noblanks : drop (ignorable?) blanks spaces\n");
2779     fprintf(f, "\t--nocdata : replace cdata section with text nodes\n");
2780     fprintf(f, "\t--nodict : create document without dictionary\n");
2781     fprintf(f, "\t--pedantic : enable additional warnings\n");
2782 #ifdef LIBXML_OUTPUT_ENABLED
2783     fprintf(f, "\t--output file or -o file: save to a given file\n");
2784     fprintf(f, "\t--format : reformat/reindent the output\n");
2785     fprintf(f, "\t--encode encoding : output in the given encoding\n");
2786     fprintf(f, "\t--pretty STYLE : pretty-print in a particular style\n");
2787     fprintf(f, "\t                 0 Do not pretty print\n");
2788     fprintf(f, "\t                 1 Format the XML content, as --format\n");
2789     fprintf(f, "\t                 2 Add whitespace inside tags, preserving content\n");
2790 #ifdef LIBXML_ZLIB_ENABLED
2791     fprintf(f, "\t--compress : turn on gzip compression of output\n");
2792 #endif
2793 #endif /* LIBXML_OUTPUT_ENABLED */
2794     fprintf(f, "\t--c14n : save in W3C canonical format v1.0 (with comments)\n");
2795     fprintf(f, "\t--c14n11 : save in W3C canonical format v1.1 (with comments)\n");
2796     fprintf(f, "\t--exc-c14n : save in W3C exclusive canonical format (with comments)\n");
2797 #ifdef LIBXML_C14N_ENABLED
2798 #endif /* LIBXML_C14N_ENABLED */
2799     fprintf(f, "\t--nsclean : remove redundant namespace declarations\n");
2800     fprintf(f, "\t--testIO : test user I/O support\n");
2801 #ifdef LIBXML_CATALOG_ENABLED
2802     fprintf(f, "\t--catalogs : use SGML catalogs from $SGML_CATALOG_FILES\n");
2803     fprintf(f, "\t             otherwise XML Catalogs starting from \n");
2804     fprintf(f, "\t         file://" XML_SYSCONFDIR "/xml/catalog "
2805             "are activated by default\n");
2806     fprintf(f, "\t--nocatalogs: deactivate all catalogs\n");
2807 #endif
2808     fprintf(f, "\t--auto : generate a small doc on the fly\n");
2809 #ifdef LIBXML_XINCLUDE_ENABLED
2810     fprintf(f, "\t--xinclude : do XInclude processing\n");
2811     fprintf(f, "\t--noxincludenode : same but do not generate XInclude nodes\n");
2812     fprintf(f, "\t--nofixup-base-uris : do not fixup xml:base uris\n");
2813 #endif
2814     fprintf(f, "\t--loaddtd : fetch external DTD\n");
2815     fprintf(f, "\t--dtdattr : loaddtd + populate the tree with inherited attributes \n");
2816 #ifdef LIBXML_READER_ENABLED
2817     fprintf(f, "\t--stream : use the streaming interface to process very large files\n");
2818     fprintf(f, "\t--walker : create a reader and walk though the resulting doc\n");
2819 #ifdef LIBXML_PATTERN_ENABLED
2820     fprintf(f, "\t--pattern pattern_value : test the pattern support\n");
2821 #endif
2822 #endif /* LIBXML_READER_ENABLED */
2823 #ifdef LIBXML_SCHEMAS_ENABLED
2824     fprintf(f, "\t--relaxng schema : do RelaxNG validation against the schema\n");
2825     fprintf(f, "\t--schema schema : do validation against the WXS schema\n");
2826 #endif
2827 #ifdef LIBXML_SCHEMATRON_ENABLED
2828     fprintf(f, "\t--schematron schema : do validation against a schematron\n");
2829 #endif
2830 #ifdef LIBXML_SAX1_ENABLED
2831     fprintf(f, "\t--sax1: use the old SAX1 interfaces for processing\n");
2832 #endif
2833     fprintf(f, "\t--sax: do not build a tree but work just at the SAX level\n");
2834     fprintf(f, "\t--oldxml10: use XML-1.0 parsing rules before the 5th edition\n");
2835 #ifdef LIBXML_XPATH_ENABLED
2836     fprintf(f, "\t--xpath expr: evaluate the XPath expression, imply --noout\n");
2837 #endif
2838     fprintf(f, "\t--max-ampl value: set maximum amplification factor\n");
2839 
2840     fprintf(f, "\nLibxml project home page: https://gitlab.gnome.org/GNOME/libxml2\n");
2841 }
2842 
2843 static unsigned long
parseInteger(FILE * errStream,const char * ctxt,const char * str,unsigned long min,unsigned long max)2844 parseInteger(FILE *errStream, const char *ctxt, const char *str,
2845              unsigned long min, unsigned long max) {
2846     char *strEnd;
2847     unsigned long val;
2848 
2849     errno = 0;
2850     val = strtoul(str, &strEnd, 10);
2851     if (errno == EINVAL || *strEnd != 0) {
2852         fprintf(errStream, "%s: invalid integer: %s\n", ctxt, str);
2853         exit(XMLLINT_ERR_UNCLASS);
2854     }
2855     if (errno != 0 || val < min || val > max) {
2856         fprintf(errStream, "%s: integer out of range: %s\n", ctxt, str);
2857         exit(XMLLINT_ERR_UNCLASS);
2858     }
2859 
2860     return(val);
2861 }
2862 
2863 static int
skipArgs(const char * arg)2864 skipArgs(const char *arg) {
2865     if ((!strcmp(arg, "-path")) ||
2866         (!strcmp(arg, "--path")) ||
2867         (!strcmp(arg, "-maxmem")) ||
2868         (!strcmp(arg, "--maxmem")) ||
2869 #ifdef LIBXML_OUTPUT_ENABLED
2870         (!strcmp(arg, "-o")) ||
2871         (!strcmp(arg, "-output")) ||
2872         (!strcmp(arg, "--output")) ||
2873         (!strcmp(arg, "-encode")) ||
2874         (!strcmp(arg, "--encode")) ||
2875         (!strcmp(arg, "-pretty")) ||
2876         (!strcmp(arg, "--pretty")) ||
2877 #endif
2878 #ifdef LIBXML_VALID_ENABLED
2879         (!strcmp(arg, "-dtdvalid")) ||
2880         (!strcmp(arg, "--dtdvalid")) ||
2881         (!strcmp(arg, "-dtdvalidfpi")) ||
2882         (!strcmp(arg, "--dtdvalidfpi")) ||
2883 #endif
2884 #ifdef LIBXML_SCHEMAS_ENABLED
2885         (!strcmp(arg, "-relaxng")) ||
2886         (!strcmp(arg, "--relaxng")) ||
2887         (!strcmp(arg, "-schema")) ||
2888         (!strcmp(arg, "--schema")) ||
2889 #endif
2890 #ifdef LIBXML_SCHEMATRON_ENABLED
2891         (!strcmp(arg, "-schematron")) ||
2892         (!strcmp(arg, "--schematron")) ||
2893 #endif
2894 #if defined(LIBXML_READER_ENABLED) && defined(LIBXML_PATTERN_ENABLED)
2895         (!strcmp(arg, "-pattern")) ||
2896         (!strcmp(arg, "--pattern")) ||
2897 #endif
2898 #ifdef LIBXML_XPATH_ENABLED
2899         (!strcmp(arg, "-xpath")) ||
2900         (!strcmp(arg, "--xpath")) ||
2901 #endif
2902         (!strcmp(arg, "-max-ampl")) ||
2903         (!strcmp(arg, "--max-ampl"))
2904     ) {
2905         return(1);
2906     }
2907 
2908     return(0);
2909 }
2910 
2911 static void
xmllintInit(xmllintState * lint)2912 xmllintInit(xmllintState *lint) {
2913     memset(lint, 0, sizeof(*lint));
2914 
2915     lint->repeat = 1;
2916     lint->progresult = XMLLINT_RETURN_OK;
2917     lint->options = XML_PARSE_COMPACT | XML_PARSE_BIG_LINES;
2918 }
2919 
2920 static int
xmllintParseOptions(xmllintState * lint,int argc,const char ** argv)2921 xmllintParseOptions(xmllintState *lint, int argc, const char **argv) {
2922     FILE *errStream = lint->errStream;
2923     int i;
2924 
2925     if (argc <= 1) {
2926         usage(errStream, argv[0]);
2927         return(XMLLINT_ERR_UNCLASS);
2928     }
2929 
2930     for (i = 1; i < argc ; i++) {
2931         if (argv[i][0] != '-' || argv[i][1] == 0)
2932             continue;
2933 
2934         if ((!strcmp(argv[i], "-maxmem")) ||
2935             (!strcmp(argv[i], "--maxmem"))) {
2936             i++;
2937             if (i >= argc) {
2938                 fprintf(errStream, "maxmem: missing integer value\n");
2939                 return(XMLLINT_ERR_UNCLASS);
2940             }
2941             errno = 0;
2942             lint->maxmem = parseInteger(errStream, "maxmem", argv[i],
2943                                         0, INT_MAX);
2944         } else if ((!strcmp(argv[i], "-debug")) ||
2945                    (!strcmp(argv[i], "--debug"))) {
2946             lint->debug = 1;
2947         } else if ((!strcmp(argv[i], "-shell")) ||
2948                    (!strcmp(argv[i], "--shell"))) {
2949             lint->shell = 1;
2950         } else if ((!strcmp(argv[i], "-copy")) ||
2951                    (!strcmp(argv[i], "--copy"))) {
2952             lint->copy = 1;
2953         } else if ((!strcmp(argv[i], "-recover")) ||
2954                    (!strcmp(argv[i], "--recover"))) {
2955             lint->options |= XML_PARSE_RECOVER;
2956         } else if ((!strcmp(argv[i], "-huge")) ||
2957                    (!strcmp(argv[i], "--huge"))) {
2958             lint->options |= XML_PARSE_HUGE;
2959         } else if ((!strcmp(argv[i], "-noent")) ||
2960                    (!strcmp(argv[i], "--noent"))) {
2961             lint->options |= XML_PARSE_NOENT;
2962         } else if ((!strcmp(argv[i], "-noenc")) ||
2963                    (!strcmp(argv[i], "--noenc"))) {
2964             lint->options |= XML_PARSE_IGNORE_ENC;
2965         } else if ((!strcmp(argv[i], "-nsclean")) ||
2966                    (!strcmp(argv[i], "--nsclean"))) {
2967             lint->options |= XML_PARSE_NSCLEAN;
2968         } else if ((!strcmp(argv[i], "-nocdata")) ||
2969                    (!strcmp(argv[i], "--nocdata"))) {
2970             lint->options |= XML_PARSE_NOCDATA;
2971         } else if ((!strcmp(argv[i], "-nodict")) ||
2972                    (!strcmp(argv[i], "--nodict"))) {
2973             lint->options |= XML_PARSE_NODICT;
2974         } else if ((!strcmp(argv[i], "-version")) ||
2975                    (!strcmp(argv[i], "--version"))) {
2976             showVersion(errStream, argv[0]);
2977             lint->version = 1;
2978         } else if ((!strcmp(argv[i], "-noout")) ||
2979                    (!strcmp(argv[i], "--noout"))) {
2980             lint->noout = 1;
2981         } else if ((!strcmp(argv[i], "-htmlout")) ||
2982                    (!strcmp(argv[i], "--htmlout"))) {
2983             lint->htmlout = 1;
2984         } else if ((!strcmp(argv[i], "-nowrap")) ||
2985                    (!strcmp(argv[i], "--nowrap"))) {
2986             lint->nowrap = 1;
2987 #ifdef LIBXML_HTML_ENABLED
2988         } else if ((!strcmp(argv[i], "-html")) ||
2989                    (!strcmp(argv[i], "--html"))) {
2990             lint->html = 1;
2991         } else if ((!strcmp(argv[i], "-xmlout")) ||
2992                    (!strcmp(argv[i], "--xmlout"))) {
2993             lint->xmlout = 1;
2994         } else if ((!strcmp(argv[i], "-nodefdtd")) ||
2995                    (!strcmp(argv[i], "--nodefdtd"))) {
2996             lint->options |= HTML_PARSE_NODEFDTD;
2997 #endif /* LIBXML_HTML_ENABLED */
2998         } else if ((!strcmp(argv[i], "-loaddtd")) ||
2999                    (!strcmp(argv[i], "--loaddtd"))) {
3000             lint->options |= XML_PARSE_DTDLOAD;
3001         } else if ((!strcmp(argv[i], "-dtdattr")) ||
3002                    (!strcmp(argv[i], "--dtdattr"))) {
3003             lint->options |= XML_PARSE_DTDATTR;
3004 #ifdef LIBXML_VALID_ENABLED
3005         } else if ((!strcmp(argv[i], "-valid")) ||
3006                    (!strcmp(argv[i], "--valid"))) {
3007             lint->options |= XML_PARSE_DTDVALID;
3008         } else if ((!strcmp(argv[i], "-postvalid")) ||
3009                    (!strcmp(argv[i], "--postvalid"))) {
3010             lint->postvalid = 1;
3011             lint->options |= XML_PARSE_DTDLOAD;
3012         } else if ((!strcmp(argv[i], "-dtdvalid")) ||
3013                    (!strcmp(argv[i], "--dtdvalid"))) {
3014             i++;
3015             lint->dtdvalid = argv[i];
3016             lint->options |= XML_PARSE_DTDLOAD;
3017         } else if ((!strcmp(argv[i], "-dtdvalidfpi")) ||
3018                    (!strcmp(argv[i], "--dtdvalidfpi"))) {
3019             i++;
3020             lint->dtdvalidfpi = argv[i];
3021             lint->options |= XML_PARSE_DTDLOAD;
3022         } else if ((!strcmp(argv[i], "-insert")) ||
3023                    (!strcmp(argv[i], "--insert"))) {
3024             lint->insert = 1;
3025 #endif /* LIBXML_VALID_ENABLED */
3026         } else if ((!strcmp(argv[i], "-dropdtd")) ||
3027                    (!strcmp(argv[i], "--dropdtd"))) {
3028             lint->dropdtd = 1;
3029         } else if ((!strcmp(argv[i], "-quiet")) ||
3030                    (!strcmp(argv[i], "--quiet"))) {
3031             lint->quiet = 1;
3032         } else if ((!strcmp(argv[i], "-timing")) ||
3033                    (!strcmp(argv[i], "--timing"))) {
3034             lint->timing = 1;
3035         } else if ((!strcmp(argv[i], "-auto")) ||
3036                    (!strcmp(argv[i], "--auto"))) {
3037             lint->generate = 1;
3038         } else if ((!strcmp(argv[i], "-repeat")) ||
3039                    (!strcmp(argv[i], "--repeat"))) {
3040 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
3041             lint->repeat = 2;
3042 #else
3043             if (lint->repeat > 1)
3044                 lint->repeat *= 10;
3045             else
3046                 lint->repeat = 100;
3047 #endif
3048 #ifdef LIBXML_PUSH_ENABLED
3049         } else if ((!strcmp(argv[i], "-push")) ||
3050                    (!strcmp(argv[i], "--push"))) {
3051             lint->push = 1;
3052 #endif /* LIBXML_PUSH_ENABLED */
3053 #if HAVE_DECL_MMAP
3054         } else if ((!strcmp(argv[i], "-memory")) ||
3055                    (!strcmp(argv[i], "--memory"))) {
3056             lint->memory = 1;
3057 #endif
3058         } else if ((!strcmp(argv[i], "-testIO")) ||
3059                    (!strcmp(argv[i], "--testIO"))) {
3060             lint->testIO = 1;
3061 #ifdef LIBXML_XINCLUDE_ENABLED
3062         } else if ((!strcmp(argv[i], "-xinclude")) ||
3063                    (!strcmp(argv[i], "--xinclude"))) {
3064             lint->xinclude = 1;
3065             lint->options |= XML_PARSE_XINCLUDE;
3066         } else if ((!strcmp(argv[i], "-noxincludenode")) ||
3067                    (!strcmp(argv[i], "--noxincludenode"))) {
3068             lint->xinclude = 1;
3069             lint->options |= XML_PARSE_XINCLUDE;
3070             lint->options |= XML_PARSE_NOXINCNODE;
3071         } else if ((!strcmp(argv[i], "-nofixup-base-uris")) ||
3072                    (!strcmp(argv[i], "--nofixup-base-uris"))) {
3073             lint->xinclude = 1;
3074             lint->options |= XML_PARSE_XINCLUDE;
3075             lint->options |= XML_PARSE_NOBASEFIX;
3076 #endif
3077         } else if ((!strcmp(argv[i], "-nowarning")) ||
3078                    (!strcmp(argv[i], "--nowarning"))) {
3079             lint->options |= XML_PARSE_NOWARNING;
3080             lint->options &= ~XML_PARSE_PEDANTIC;
3081         } else if ((!strcmp(argv[i], "-pedantic")) ||
3082                    (!strcmp(argv[i], "--pedantic"))) {
3083             lint->options |= XML_PARSE_PEDANTIC;
3084             lint->options &= ~XML_PARSE_NOWARNING;
3085 #ifdef LIBXML_DEBUG_ENABLED
3086         } else if ((!strcmp(argv[i], "-debugent")) ||
3087                    (!strcmp(argv[i], "--debugent"))) {
3088             lint->debugent = 1;
3089 #endif
3090 #ifdef LIBXML_C14N_ENABLED
3091         } else if ((!strcmp(argv[i], "-c14n")) ||
3092                    (!strcmp(argv[i], "--c14n"))) {
3093             lint->canonical = 1;
3094             lint->options |= XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_DTDLOAD;
3095         } else if ((!strcmp(argv[i], "-c14n11")) ||
3096                    (!strcmp(argv[i], "--c14n11"))) {
3097             lint->canonical_11 = 1;
3098             lint->options |= XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_DTDLOAD;
3099         } else if ((!strcmp(argv[i], "-exc-c14n")) ||
3100                    (!strcmp(argv[i], "--exc-c14n"))) {
3101             lint->exc_canonical = 1;
3102             lint->options |= XML_PARSE_NOENT | XML_PARSE_DTDATTR | XML_PARSE_DTDLOAD;
3103 #endif
3104 #ifdef LIBXML_CATALOG_ENABLED
3105         } else if ((!strcmp(argv[i], "-catalogs")) ||
3106                    (!strcmp(argv[i], "--catalogs"))) {
3107             lint->catalogs = 1;
3108         } else if ((!strcmp(argv[i], "-nocatalogs")) ||
3109                    (!strcmp(argv[i], "--nocatalogs"))) {
3110             lint->nocatalogs = 1;
3111 #endif
3112         } else if ((!strcmp(argv[i], "-noblanks")) ||
3113                    (!strcmp(argv[i], "--noblanks"))) {
3114             lint->options |= XML_PARSE_NOBLANKS;
3115 #ifdef LIBXML_OUTPUT_ENABLED
3116         } else if ((!strcmp(argv[i], "-o")) ||
3117                    (!strcmp(argv[i], "-output")) ||
3118                    (!strcmp(argv[i], "--output"))) {
3119             i++;
3120             lint->output = argv[i];
3121         } else if ((!strcmp(argv[i], "-format")) ||
3122                    (!strcmp(argv[i], "--format"))) {
3123             lint->format = 1;
3124             lint->options |= XML_PARSE_NOBLANKS;
3125         } else if ((!strcmp(argv[i], "-encode")) ||
3126                    (!strcmp(argv[i], "--encode"))) {
3127             i++;
3128             lint->encoding = argv[i];
3129         } else if ((!strcmp(argv[i], "-pretty")) ||
3130                    (!strcmp(argv[i], "--pretty"))) {
3131             i++;
3132             if (argv[i] != NULL)
3133                 lint->format = atoi(argv[i]);
3134 #ifdef LIBXML_ZLIB_ENABLED
3135         } else if ((!strcmp(argv[i], "-compress")) ||
3136                    (!strcmp(argv[i], "--compress"))) {
3137             lint->compress = 1;
3138 #endif
3139 #endif /* LIBXML_OUTPUT_ENABLED */
3140 #ifdef LIBXML_READER_ENABLED
3141         } else if ((!strcmp(argv[i], "-stream")) ||
3142                    (!strcmp(argv[i], "--stream"))) {
3143              lint->stream = 1;
3144         } else if ((!strcmp(argv[i], "-walker")) ||
3145                    (!strcmp(argv[i], "--walker"))) {
3146              lint->walker = 1;
3147              lint->noout = 1;
3148 #ifdef LIBXML_PATTERN_ENABLED
3149         } else if ((!strcmp(argv[i], "-pattern")) ||
3150                    (!strcmp(argv[i], "--pattern"))) {
3151             i++;
3152             lint->pattern = argv[i];
3153 #endif
3154 #endif /* LIBXML_READER_ENABLED */
3155 #ifdef LIBXML_SAX1_ENABLED
3156         } else if ((!strcmp(argv[i], "-sax1")) ||
3157                    (!strcmp(argv[i], "--sax1"))) {
3158             lint->options |= XML_PARSE_SAX1;
3159 #endif /* LIBXML_SAX1_ENABLED */
3160         } else if ((!strcmp(argv[i], "-sax")) ||
3161                    (!strcmp(argv[i], "--sax"))) {
3162             lint->sax = 1;
3163 #ifdef LIBXML_SCHEMAS_ENABLED
3164         } else if ((!strcmp(argv[i], "-relaxng")) ||
3165                    (!strcmp(argv[i], "--relaxng"))) {
3166             i++;
3167             lint->relaxng = argv[i];
3168             lint->options |= XML_PARSE_NOENT;
3169         } else if ((!strcmp(argv[i], "-schema")) ||
3170                  (!strcmp(argv[i], "--schema"))) {
3171             i++;
3172             lint->schema = argv[i];
3173             lint->options |= XML_PARSE_NOENT;
3174 #endif
3175 #ifdef LIBXML_SCHEMATRON_ENABLED
3176         } else if ((!strcmp(argv[i], "-schematron")) ||
3177                    (!strcmp(argv[i], "--schematron"))) {
3178             i++;
3179             lint->schematron = argv[i];
3180             lint->options |= XML_PARSE_NOENT;
3181 #endif
3182         } else if ((!strcmp(argv[i], "-nonet")) ||
3183                    (!strcmp(argv[i], "--nonet"))) {
3184             lint->options |= XML_PARSE_NONET;
3185         } else if ((!strcmp(argv[i], "-nocompact")) ||
3186                    (!strcmp(argv[i], "--nocompact"))) {
3187             lint->options &= ~XML_PARSE_COMPACT;
3188         } else if ((!strcmp(argv[i], "-load-trace")) ||
3189                    (!strcmp(argv[i], "--load-trace"))) {
3190             lint->load_trace = 1;
3191         } else if ((!strcmp(argv[i], "-path")) ||
3192                    (!strcmp(argv[i], "--path"))) {
3193             i++;
3194             parsePath(lint, BAD_CAST argv[i]);
3195 #ifdef LIBXML_XPATH_ENABLED
3196         } else if ((!strcmp(argv[i], "-xpath")) ||
3197                    (!strcmp(argv[i], "--xpath"))) {
3198             i++;
3199             lint->noout++;
3200             lint->xpathquery = argv[i];
3201 #endif
3202         } else if ((!strcmp(argv[i], "-oldxml10")) ||
3203                    (!strcmp(argv[i], "--oldxml10"))) {
3204             lint->options |= XML_PARSE_OLD10;
3205         } else if ((!strcmp(argv[i], "-max-ampl")) ||
3206                    (!strcmp(argv[i], "--max-ampl"))) {
3207             i++;
3208             if (i >= argc) {
3209                 fprintf(errStream, "max-ampl: missing integer value\n");
3210                 return(XMLLINT_ERR_UNCLASS);
3211             }
3212             lint->maxAmpl = parseInteger(errStream, "max-ampl", argv[i],
3213                                          1, UINT_MAX);
3214         } else {
3215             fprintf(errStream, "Unknown option %s\n", argv[i]);
3216             usage(errStream, argv[0]);
3217             return(XMLLINT_ERR_UNCLASS);
3218         }
3219     }
3220 
3221     if (lint->shell)
3222         lint->repeat = 1;
3223 
3224     return(XMLLINT_RETURN_OK);
3225 }
3226 
3227 int
xmllintMain(int argc,const char ** argv,FILE * errStream,xmlResourceLoader loader)3228 xmllintMain(int argc, const char **argv, FILE *errStream,
3229             xmlResourceLoader loader) {
3230     xmllintState state, *lint;
3231     int i, j, res;
3232     int files = 0;
3233 
3234 #ifdef _WIN32
3235     _setmode(_fileno(stdin), _O_BINARY);
3236     _setmode(_fileno(stdout), _O_BINARY);
3237     _setmode(_fileno(stderr), _O_BINARY);
3238 #endif
3239 
3240     lint = &state;
3241     xmllintInit(lint);
3242     lint->errStream = errStream;
3243     lint->defaultResourceLoader = loader;
3244 
3245     res = xmllintParseOptions(lint, argc, argv);
3246     if (res != XMLLINT_RETURN_OK) {
3247         lint->progresult = res;
3248         goto error;
3249     }
3250 
3251     if (lint->maxmem != 0) {
3252         xmllintMaxmem = 0;
3253         xmllintMaxmemReached = 0;
3254         xmllintOom = 0;
3255         xmlMemSetup(myFreeFunc, myMallocFunc, myReallocFunc, myStrdupFunc);
3256     }
3257 
3258     LIBXML_TEST_VERSION
3259 
3260 #ifdef LIBXML_CATALOG_ENABLED
3261     if (lint->nocatalogs == 0) {
3262 	if (lint->catalogs) {
3263 	    const char *catal;
3264 
3265 	    catal = getenv("SGML_CATALOG_FILES");
3266 	    if (catal != NULL) {
3267 		xmlLoadCatalogs(catal);
3268 	    } else {
3269 		fprintf(errStream, "Variable $SGML_CATALOG_FILES not set\n");
3270 	    }
3271 	}
3272     }
3273 #endif
3274 
3275 #ifdef LIBXML_OUTPUT_ENABLED
3276     {
3277         const char *indent = getenv("XMLLINT_INDENT");
3278         if (indent != NULL) {
3279             xmlTreeIndentString = indent;
3280         }
3281     }
3282 #endif
3283 
3284     if (lint->htmlout) {
3285         lint->htmlBuf = xmlMalloc(HTML_BUF_SIZE);
3286         if (lint->htmlBuf == NULL) {
3287             lint->progresult = XMLLINT_ERR_MEM;
3288             goto error;
3289         }
3290 
3291         if (!lint->nowrap) {
3292             fprintf(errStream,
3293              "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"\n");
3294             fprintf(errStream,
3295                     "\t\"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
3296             fprintf(errStream,
3297              "<html><head><title>%s output</title></head>\n",
3298                     argv[0]);
3299             fprintf(errStream,
3300              "<body bgcolor=\"#ffffff\"><h1 align=\"center\">%s output</h1>\n",
3301                     argv[0]);
3302         }
3303     }
3304 
3305 #ifdef LIBXML_SCHEMATRON_ENABLED
3306     if ((lint->schematron != NULL) && (lint->sax == 0)
3307 #ifdef LIBXML_READER_ENABLED
3308         && (lint->stream == 0)
3309 #endif /* LIBXML_READER_ENABLED */
3310 	) {
3311 	xmlSchematronParserCtxtPtr ctxt;
3312 
3313         /* forces loading the DTDs */
3314 	lint->options |= XML_PARSE_DTDLOAD;
3315 	if (lint->timing) {
3316 	    startTimer(lint);
3317 	}
3318 	ctxt = xmlSchematronNewParserCtxt(lint->schematron);
3319         if (ctxt == NULL) {
3320             lint->progresult = XMLLINT_ERR_MEM;
3321             goto error;
3322         }
3323 	lint->wxschematron = xmlSchematronParse(ctxt);
3324 	if (lint->wxschematron == NULL) {
3325 	    fprintf(errStream, "Schematron schema %s failed to compile\n",
3326                     lint->schematron);
3327             lint->progresult = XMLLINT_ERR_SCHEMACOMP;
3328             goto error;
3329 	}
3330 	xmlSchematronFreeParserCtxt(ctxt);
3331 	if (lint->timing) {
3332 	    endTimer(lint, "Compiling the schemas");
3333 	}
3334     }
3335 #endif
3336 
3337 #ifdef LIBXML_SCHEMAS_ENABLED
3338     if ((lint->relaxng != NULL) && (lint->sax == 0)
3339 #ifdef LIBXML_READER_ENABLED
3340         && (lint->stream == 0)
3341 #endif /* LIBXML_READER_ENABLED */
3342 	) {
3343 	xmlRelaxNGParserCtxtPtr ctxt;
3344 
3345         /* forces loading the DTDs */
3346 	lint->options |= XML_PARSE_DTDLOAD;
3347 	if (lint->timing) {
3348 	    startTimer(lint);
3349 	}
3350 	ctxt = xmlRelaxNGNewParserCtxt(lint->relaxng);
3351         if (ctxt == NULL) {
3352             lint->progresult = XMLLINT_ERR_MEM;
3353             goto error;
3354         }
3355         xmlRelaxNGSetResourceLoader(ctxt, xmllintResourceLoader, lint);
3356 	lint->relaxngschemas = xmlRelaxNGParse(ctxt);
3357 	if (lint->relaxngschemas == NULL) {
3358 	    fprintf(errStream, "Relax-NG schema %s failed to compile\n",
3359                     lint->relaxng);
3360             lint->progresult = XMLLINT_ERR_SCHEMACOMP;
3361             goto error;
3362 	}
3363 	xmlRelaxNGFreeParserCtxt(ctxt);
3364 	if (lint->timing) {
3365 	    endTimer(lint, "Compiling the schemas");
3366 	}
3367     } else if ((lint->schema != NULL)
3368 #ifdef LIBXML_READER_ENABLED
3369 		&& (lint->stream == 0)
3370 #endif
3371 	) {
3372 	xmlSchemaParserCtxtPtr ctxt;
3373 
3374 	if (lint->timing) {
3375 	    startTimer(lint);
3376 	}
3377 	ctxt = xmlSchemaNewParserCtxt(lint->schema);
3378         if (ctxt == NULL) {
3379             lint->progresult = XMLLINT_ERR_MEM;
3380             goto error;
3381         }
3382         xmlSchemaSetResourceLoader(ctxt, xmllintResourceLoader, lint);
3383 	lint->wxschemas = xmlSchemaParse(ctxt);
3384 	if (lint->wxschemas == NULL) {
3385 	    fprintf(errStream, "WXS schema %s failed to compile\n",
3386                     lint->schema);
3387             lint->progresult = XMLLINT_ERR_SCHEMACOMP;
3388             goto error;
3389 	}
3390 	xmlSchemaFreeParserCtxt(ctxt);
3391 	if (lint->timing) {
3392 	    endTimer(lint, "Compiling the schemas");
3393 	}
3394     }
3395 #endif /* LIBXML_SCHEMAS_ENABLED */
3396 
3397 #if defined(LIBXML_READER_ENABLED) && defined(LIBXML_PATTERN_ENABLED)
3398     if ((lint->pattern != NULL) && (lint->walker == 0)) {
3399         res = xmlPatternCompileSafe(BAD_CAST lint->pattern, NULL, 0, NULL,
3400                                     &lint->patternc);
3401 	if (lint->patternc == NULL) {
3402             if (res < 0) {
3403                 lint->progresult = XMLLINT_ERR_MEM;
3404             } else {
3405                 fprintf(errStream, "Pattern %s failed to compile\n",
3406                         lint->pattern);
3407                 lint->progresult = XMLLINT_ERR_SCHEMAPAT;
3408             }
3409             goto error;
3410 	}
3411     }
3412 #endif /* LIBXML_READER_ENABLED && LIBXML_PATTERN_ENABLED */
3413 
3414     /*
3415      * The main loop over input documents
3416      */
3417     for (i = 1; i < argc ; i++) {
3418         const char *filename = argv[i];
3419 #if HAVE_DECL_MMAP
3420         int memoryFd = -1;
3421 #endif
3422 
3423 	if ((filename[0] == '-') && (strcmp(filename, "-") != 0)) {
3424             i += skipArgs(filename);
3425             continue;
3426         }
3427 
3428 #if HAVE_DECL_MMAP
3429         if (lint->memory) {
3430             struct stat info;
3431             if (stat(filename, &info) < 0) {
3432                 lint->progresult = XMLLINT_ERR_RDFILE;
3433                 break;
3434             }
3435             memoryFd = open(filename, O_RDONLY);
3436             if (memoryFd < 0) {
3437                 lint->progresult = XMLLINT_ERR_RDFILE;
3438                 break;
3439             }
3440             lint->memoryData = mmap(NULL, info.st_size + 1, PROT_READ,
3441                                     MAP_SHARED, memoryFd, 0);
3442             if (lint->memoryData == (void *) MAP_FAILED) {
3443                 close(memoryFd);
3444                 fprintf(errStream, "mmap failure for file %s\n", filename);
3445                 lint->progresult = XMLLINT_ERR_RDFILE;
3446                 break;
3447             }
3448             lint->memorySize = info.st_size;
3449         }
3450 #endif /* HAVE_DECL_MMAP */
3451 
3452 	if ((lint->timing) && (lint->repeat > 1))
3453 	    startTimer(lint);
3454 
3455 #ifdef LIBXML_READER_ENABLED
3456         if (lint->stream != 0) {
3457             for (j = 0; j < lint->repeat; j++)
3458                 streamFile(lint, filename);
3459         } else
3460 #endif /* LIBXML_READER_ENABLED */
3461         {
3462             xmlParserCtxtPtr ctxt;
3463 
3464 #ifdef LIBXML_HTML_ENABLED
3465             if (lint->html) {
3466 #ifdef LIBXML_PUSH_ENABLED
3467                 if (lint->push) {
3468                     ctxt = htmlCreatePushParserCtxt(NULL, NULL, NULL, 0,
3469                                                     filename,
3470                                                     XML_CHAR_ENCODING_NONE);
3471                     htmlCtxtUseOptions(ctxt, lint->options);
3472                 } else
3473 #endif /* LIBXML_PUSH_ENABLED */
3474                 {
3475                     ctxt = htmlNewParserCtxt();
3476                 }
3477             } else
3478 #endif /* LIBXML_HTML_ENABLED */
3479             {
3480 #ifdef LIBXML_PUSH_ENABLED
3481                 if (lint->push) {
3482                     ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0,
3483                                                    filename);
3484                     xmlCtxtUseOptions(ctxt, lint->options);
3485                 } else
3486 #endif /* LIBXML_PUSH_ENABLED */
3487                 {
3488                     ctxt = xmlNewParserCtxt();
3489                 }
3490             }
3491             if (ctxt == NULL) {
3492                 lint->progresult = XMLLINT_ERR_MEM;
3493                 goto error;
3494             }
3495 
3496             if (lint->sax) {
3497                 const xmlSAXHandler *handler;
3498 
3499                 if (lint->noout) {
3500                     handler = &emptySAXHandler;
3501 #ifdef LIBXML_SAX1_ENABLED
3502                 } else if (lint->options & XML_PARSE_SAX1) {
3503                     handler = &debugSAXHandler;
3504 #endif
3505                 } else {
3506                     handler = &debugSAX2Handler;
3507                 }
3508 
3509                 *ctxt->sax = *handler;
3510                 ctxt->userData = lint;
3511             }
3512 
3513             xmlCtxtSetResourceLoader(ctxt, xmllintResourceLoader, lint);
3514             if (lint->maxAmpl > 0)
3515                 xmlCtxtSetMaxAmplification(ctxt, lint->maxAmpl);
3516 
3517             if (lint->htmlout) {
3518                 ctxt->_private = lint;
3519                 xmlCtxtSetErrorHandler(ctxt, xmlHTMLError, ctxt);
3520             }
3521 
3522             lint->ctxt = ctxt;
3523 
3524             for (j = 0; j < lint->repeat; j++) {
3525 #ifdef LIBXML_PUSH_ENABLED
3526                 if ((lint->push) && (j > 0))
3527                     xmlCtxtResetPush(ctxt, NULL, 0, NULL, NULL);
3528 #endif
3529                 if (lint->sax) {
3530                     testSAX(lint, filename);
3531                 } else {
3532                     parseAndPrintFile(lint, filename);
3533                 }
3534             }
3535 
3536             xmlFreeParserCtxt(ctxt);
3537         }
3538 
3539         if ((lint->timing) && (lint->repeat > 1)) {
3540             endTimer(lint, "%d iterations", lint->repeat);
3541         }
3542 
3543         files += 1;
3544 
3545 #if HAVE_DECL_MMAP
3546         if (lint->memory) {
3547             munmap(lint->memoryData, lint->memorySize);
3548             close(memoryFd);
3549         }
3550 #endif
3551     }
3552 
3553     if (lint->generate)
3554 	parseAndPrintFile(lint, NULL);
3555 
3556     if ((lint->htmlout) && (!lint->nowrap)) {
3557 	fprintf(errStream, "</body></html>\n");
3558     }
3559 
3560     if ((files == 0) && (!lint->generate) && (lint->version == 0)) {
3561 	usage(errStream, argv[0]);
3562         lint->progresult = XMLLINT_ERR_UNCLASS;
3563     }
3564 
3565 error:
3566 
3567     if (lint->htmlout)
3568         xmlFree(lint->htmlBuf);
3569 
3570 #ifdef LIBXML_SCHEMATRON_ENABLED
3571     if (lint->wxschematron != NULL)
3572 	xmlSchematronFree(lint->wxschematron);
3573 #endif
3574 #ifdef LIBXML_SCHEMAS_ENABLED
3575     if (lint->relaxngschemas != NULL)
3576 	xmlRelaxNGFree(lint->relaxngschemas);
3577     if (lint->wxschemas != NULL)
3578 	xmlSchemaFree(lint->wxschemas);
3579 #endif
3580 #if defined(LIBXML_READER_ENABLED) && defined(LIBXML_PATTERN_ENABLED)
3581     if (lint->patternc != NULL)
3582         xmlFreePattern(lint->patternc);
3583 #endif
3584 
3585     xmlCleanupParser();
3586 
3587     if ((lint->maxmem) && (xmllintMaxmemReached)) {
3588         fprintf(errStream, "Maximum memory exceeded (%d bytes)\n",
3589                 xmllintMaxmem);
3590     } else if (lint->progresult == XMLLINT_ERR_MEM) {
3591         fprintf(errStream, "Out-of-memory error reported\n");
3592     }
3593 
3594 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
3595     if ((lint->maxmem) &&
3596         (xmllintOom != (lint->progresult == XMLLINT_ERR_MEM))) {
3597         fprintf(stderr, "xmllint: malloc failure %s reported\n",
3598                 xmllintOom ? "not" : "erroneously");
3599         abort();
3600     }
3601 #endif
3602 
3603     return(lint->progresult);
3604 }
3605 
3606