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