1 /*
2  * runtest.c: C program to run libxml2 regression tests without
3  *            requiring make or Python, and reducing platform dependancies
4  *            to a strict minimum.
5  *
6  * To compile on Unixes:
7  * cc -o runtest `xml2-config --cflags` runtest.c `xml2-config --libs` -lpthread
8  *
9  * See Copyright for the status of this software.
10  *
11  * daniel@veillard.com
12  */
13 
14 #include "libxml.h"
15 #include <stdio.h>
16 
17 #if !defined(_WIN32) || defined(__CYGWIN__)
18 #include <unistd.h>
19 #endif
20 #include <string.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 
25 #include <libxml/parser.h>
26 #include <libxml/tree.h>
27 #include <libxml/uri.h>
28 
29 #ifdef LIBXML_OUTPUT_ENABLED
30 #ifdef LIBXML_READER_ENABLED
31 #include <libxml/xmlreader.h>
32 #endif
33 
34 #ifdef LIBXML_XINCLUDE_ENABLED
35 #include <libxml/xinclude.h>
36 #endif
37 
38 #ifdef LIBXML_XPATH_ENABLED
39 #include <libxml/xpath.h>
40 #include <libxml/xpathInternals.h>
41 #ifdef LIBXML_XPTR_ENABLED
42 #include <libxml/xpointer.h>
43 #endif
44 #endif
45 
46 #ifdef LIBXML_SCHEMAS_ENABLED
47 #include <libxml/relaxng.h>
48 #include <libxml/xmlschemas.h>
49 #include <libxml/xmlschemastypes.h>
50 #endif
51 
52 #ifdef LIBXML_PATTERN_ENABLED
53 #include <libxml/pattern.h>
54 #endif
55 
56 #ifdef LIBXML_C14N_ENABLED
57 #include <libxml/c14n.h>
58 #endif
59 
60 #ifdef LIBXML_HTML_ENABLED
61 #include <libxml/HTMLparser.h>
62 #include <libxml/HTMLtree.h>
63 
64 /*
65  * pseudo flag for the unification of HTML and XML tests
66  */
67 #define XML_PARSE_HTML 1 << 24
68 #endif
69 
70 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
71 #include <libxml/globals.h>
72 #include <libxml/threads.h>
73 #include <libxml/parser.h>
74 #include <libxml/catalog.h>
75 #include <string.h>
76 #endif
77 
78 /*
79  * O_BINARY is just for Windows compatibility - if it isn't defined
80  * on this system, avoid any compilation error
81  */
82 #ifdef	O_BINARY
83 #define RD_FLAGS	O_RDONLY | O_BINARY
84 #else
85 #define	RD_FLAGS	O_RDONLY
86 #endif
87 
88 typedef int (*functest) (const char *filename, const char *result,
89                          const char *error, int options);
90 
91 typedef struct testDesc testDesc;
92 typedef testDesc *testDescPtr;
93 struct testDesc {
94     const char *desc; /* descripton of the test */
95     functest    func; /* function implementing the test */
96     const char *in;   /* glob to path for input files */
97     const char *out;  /* output directory */
98     const char *suffix;/* suffix for output files */
99     const char *err;  /* suffix for error output files */
100     int     options;  /* parser options for the test */
101 };
102 
103 static int checkTestFile(const char *filename);
104 
105 #if defined(_WIN32) && !defined(__CYGWIN__)
106 
107 #include <windows.h>
108 #include <io.h>
109 
110 typedef struct
111 {
112       size_t gl_pathc;    /* Count of paths matched so far  */
113       char **gl_pathv;    /* List of matched pathnames.  */
114       size_t gl_offs;     /* Slots to reserve in 'gl_pathv'.  */
115 } glob_t;
116 
117 #define GLOB_DOOFFS 0
glob(const char * pattern,int flags,int errfunc (const char * epath,int eerrno),glob_t * pglob)118 static int glob(const char *pattern, int flags,
119                 int errfunc(const char *epath, int eerrno),
120                 glob_t *pglob) {
121     glob_t *ret;
122     WIN32_FIND_DATA FindFileData;
123     HANDLE hFind;
124     unsigned int nb_paths = 0;
125     char directory[500];
126     int len;
127 
128     if ((pattern == NULL) || (pglob == NULL)) return(-1);
129 
130     strncpy(directory, pattern, 499);
131     for (len = strlen(directory);len >= 0;len--) {
132         if (directory[len] == '/') {
133 	    len++;
134 	    directory[len] = 0;
135 	    break;
136 	}
137     }
138     if (len <= 0)
139         len = 0;
140 
141 
142     ret = pglob;
143     memset(ret, 0, sizeof(glob_t));
144 
145     hFind = FindFirstFileA(pattern, &FindFileData);
146     if (hFind == INVALID_HANDLE_VALUE)
147         return(0);
148     nb_paths = 20;
149     ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *));
150     if (ret->gl_pathv == NULL) {
151 	FindClose(hFind);
152         return(-1);
153     }
154     strncpy(directory + len, FindFileData.cFileName, 499 - len);
155     ret->gl_pathv[ret->gl_pathc] = strdup(directory);
156     if (ret->gl_pathv[ret->gl_pathc] == NULL)
157         goto done;
158     ret->gl_pathc++;
159     while(FindNextFileA(hFind, &FindFileData)) {
160         if (FindFileData.cFileName[0] == '.')
161 	    continue;
162         if (ret->gl_pathc + 2 > nb_paths) {
163             char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *));
164             if (tmp == NULL)
165                 break;
166             ret->gl_pathv = tmp;
167             nb_paths *= 2;
168 	}
169 	strncpy(directory + len, FindFileData.cFileName, 499 - len);
170 	ret->gl_pathv[ret->gl_pathc] = strdup(directory);
171         if (ret->gl_pathv[ret->gl_pathc] == NULL)
172             break;
173         ret->gl_pathc++;
174     }
175     ret->gl_pathv[ret->gl_pathc] = NULL;
176 
177 done:
178     FindClose(hFind);
179     return(0);
180 }
181 
182 
183 
globfree(glob_t * pglob)184 static void globfree(glob_t *pglob) {
185     unsigned int i;
186     if (pglob == NULL)
187         return;
188 
189     for (i = 0;i < pglob->gl_pathc;i++) {
190          if (pglob->gl_pathv[i] != NULL)
191              free(pglob->gl_pathv[i]);
192     }
193 }
194 
195 #else
196 #include <glob.h>
197 #endif
198 
199 /************************************************************************
200  *									*
201  *		Libxml2 specific routines				*
202  *									*
203  ************************************************************************/
204 
205 static int nb_tests = 0;
206 static int nb_errors = 0;
207 static int nb_leaks = 0;
208 static int extraMemoryFromResolver = 0;
209 
210 static int
fatalError(void)211 fatalError(void) {
212     fprintf(stderr, "Exitting tests on fatal error\n");
213     exit(1);
214 }
215 
216 /*
217  * We need to trap calls to the resolver to not account memory for the catalog
218  * which is shared to the current running test. We also don't want to have
219  * network downloads modifying tests.
220  */
221 static xmlParserInputPtr
testExternalEntityLoader(const char * URL,const char * ID,xmlParserCtxtPtr ctxt)222 testExternalEntityLoader(const char *URL, const char *ID,
223 			 xmlParserCtxtPtr ctxt) {
224     xmlParserInputPtr ret;
225 
226     if (checkTestFile(URL)) {
227 	ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
228     } else {
229 	int memused = xmlMemUsed();
230 	ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
231 	extraMemoryFromResolver += xmlMemUsed() - memused;
232     }
233 
234     return(ret);
235 }
236 
237 /*
238  * Trapping the error messages at the generic level to grab the equivalent of
239  * stderr messages on CLI tools.
240  */
241 static char testErrors[32769];
242 static int testErrorsSize = 0;
243 
244 static void XMLCDECL
testErrorHandler(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)245 testErrorHandler(void *ctx  ATTRIBUTE_UNUSED, const char *msg, ...) {
246     va_list args;
247     int res;
248 
249     if (testErrorsSize >= 32768)
250         return;
251     va_start(args, msg);
252     res = vsnprintf(&testErrors[testErrorsSize],
253                     32768 - testErrorsSize,
254 		    msg, args);
255     va_end(args);
256     if (testErrorsSize + res >= 32768) {
257         /* buffer is full */
258 	testErrorsSize = 32768;
259 	testErrors[testErrorsSize] = 0;
260     } else {
261         testErrorsSize += res;
262     }
263     testErrors[testErrorsSize] = 0;
264 }
265 
266 static void XMLCDECL
channel(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)267 channel(void *ctx  ATTRIBUTE_UNUSED, const char *msg, ...) {
268     va_list args;
269     int res;
270 
271     if (testErrorsSize >= 32768)
272         return;
273     va_start(args, msg);
274     res = vsnprintf(&testErrors[testErrorsSize],
275                     32768 - testErrorsSize,
276 		    msg, args);
277     va_end(args);
278     if (testErrorsSize + res >= 32768) {
279         /* buffer is full */
280 	testErrorsSize = 32768;
281 	testErrors[testErrorsSize] = 0;
282     } else {
283         testErrorsSize += res;
284     }
285     testErrors[testErrorsSize] = 0;
286 }
287 
288 /**
289  * xmlParserPrintFileContext:
290  * @input:  an xmlParserInputPtr input
291  *
292  * Displays current context within the input content for error tracking
293  */
294 
295 static void
xmlParserPrintFileContextInternal(xmlParserInputPtr input,xmlGenericErrorFunc chanl,void * data)296 xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
297 		xmlGenericErrorFunc chanl, void *data ) {
298     const xmlChar *cur, *base;
299     unsigned int n, col;	/* GCC warns if signed, because compared with sizeof() */
300     xmlChar  content[81]; /* space for 80 chars + line terminator */
301     xmlChar *ctnt;
302 
303     if (input == NULL) return;
304     cur = input->cur;
305     base = input->base;
306     /* skip backwards over any end-of-lines */
307     while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
308 	cur--;
309     }
310     n = 0;
311     /* search backwards for beginning-of-line (to max buff size) */
312     while ((n++ < (sizeof(content)-1)) && (cur > base) &&
313    (*(cur) != '\n') && (*(cur) != '\r'))
314         cur--;
315     if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
316     /* calculate the error position in terms of the current position */
317     col = input->cur - cur;
318     /* search forward for end-of-line (to max buff size) */
319     n = 0;
320     ctnt = content;
321     /* copy selected text to our buffer */
322     while ((*cur != 0) && (*(cur) != '\n') &&
323    (*(cur) != '\r') && (n < sizeof(content)-1)) {
324 		*ctnt++ = *cur++;
325 	n++;
326     }
327     *ctnt = 0;
328     /* print out the selected text */
329     chanl(data ,"%s\n", content);
330     /* create blank line with problem pointer */
331     n = 0;
332     ctnt = content;
333     /* (leave buffer space for pointer + line terminator) */
334     while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
335 	if (*(ctnt) != '\t')
336 	    *(ctnt) = ' ';
337 	ctnt++;
338     }
339     *ctnt++ = '^';
340     *ctnt = 0;
341     chanl(data ,"%s\n", content);
342 }
343 
344 static void
testStructuredErrorHandler(void * ctx ATTRIBUTE_UNUSED,xmlErrorPtr err)345 testStructuredErrorHandler(void *ctx  ATTRIBUTE_UNUSED, xmlErrorPtr err) {
346     char *file = NULL;
347     int line = 0;
348     int code = -1;
349     int domain;
350     void *data = NULL;
351     const char *str;
352     const xmlChar *name = NULL;
353     xmlNodePtr node;
354     xmlErrorLevel level;
355     xmlParserInputPtr input = NULL;
356     xmlParserInputPtr cur = NULL;
357     xmlParserCtxtPtr ctxt = NULL;
358 
359     if (err == NULL)
360         return;
361 
362     file = err->file;
363     line = err->line;
364     code = err->code;
365     domain = err->domain;
366     level = err->level;
367     node = err->node;
368     if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
369         (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
370 	(domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
371 	ctxt = err->ctxt;
372     }
373     str = err->message;
374 
375     if (code == XML_ERR_OK)
376         return;
377 
378     if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
379         name = node->name;
380 
381     /*
382      * Maintain the compatibility with the legacy error handling
383      */
384     if (ctxt != NULL) {
385         input = ctxt->input;
386         if ((input != NULL) && (input->filename == NULL) &&
387             (ctxt->inputNr > 1)) {
388             cur = input;
389             input = ctxt->inputTab[ctxt->inputNr - 2];
390         }
391         if (input != NULL) {
392             if (input->filename)
393                 channel(data, "%s:%d: ", input->filename, input->line);
394             else if ((line != 0) && (domain == XML_FROM_PARSER))
395                 channel(data, "Entity: line %d: ", input->line);
396         }
397     } else {
398         if (file != NULL)
399             channel(data, "%s:%d: ", file, line);
400         else if ((line != 0) && (domain == XML_FROM_PARSER))
401             channel(data, "Entity: line %d: ", line);
402     }
403     if (name != NULL) {
404         channel(data, "element %s: ", name);
405     }
406     if (code == XML_ERR_OK)
407         return;
408     switch (domain) {
409         case XML_FROM_PARSER:
410             channel(data, "parser ");
411             break;
412         case XML_FROM_NAMESPACE:
413             channel(data, "namespace ");
414             break;
415         case XML_FROM_DTD:
416         case XML_FROM_VALID:
417             channel(data, "validity ");
418             break;
419         case XML_FROM_HTML:
420             channel(data, "HTML parser ");
421             break;
422         case XML_FROM_MEMORY:
423             channel(data, "memory ");
424             break;
425         case XML_FROM_OUTPUT:
426             channel(data, "output ");
427             break;
428         case XML_FROM_IO:
429             channel(data, "I/O ");
430             break;
431         case XML_FROM_XINCLUDE:
432             channel(data, "XInclude ");
433             break;
434         case XML_FROM_XPATH:
435             channel(data, "XPath ");
436             break;
437         case XML_FROM_XPOINTER:
438             channel(data, "parser ");
439             break;
440         case XML_FROM_REGEXP:
441             channel(data, "regexp ");
442             break;
443         case XML_FROM_MODULE:
444             channel(data, "module ");
445             break;
446         case XML_FROM_SCHEMASV:
447             channel(data, "Schemas validity ");
448             break;
449         case XML_FROM_SCHEMASP:
450             channel(data, "Schemas parser ");
451             break;
452         case XML_FROM_RELAXNGP:
453             channel(data, "Relax-NG parser ");
454             break;
455         case XML_FROM_RELAXNGV:
456             channel(data, "Relax-NG validity ");
457             break;
458         case XML_FROM_CATALOG:
459             channel(data, "Catalog ");
460             break;
461         case XML_FROM_C14N:
462             channel(data, "C14N ");
463             break;
464         case XML_FROM_XSLT:
465             channel(data, "XSLT ");
466             break;
467         default:
468             break;
469     }
470     if (code == XML_ERR_OK)
471         return;
472     switch (level) {
473         case XML_ERR_NONE:
474             channel(data, ": ");
475             break;
476         case XML_ERR_WARNING:
477             channel(data, "warning : ");
478             break;
479         case XML_ERR_ERROR:
480             channel(data, "error : ");
481             break;
482         case XML_ERR_FATAL:
483             channel(data, "error : ");
484             break;
485     }
486     if (code == XML_ERR_OK)
487         return;
488     if (str != NULL) {
489         int len;
490 	len = xmlStrlen((const xmlChar *)str);
491 	if ((len > 0) && (str[len - 1] != '\n'))
492 	    channel(data, "%s\n", str);
493 	else
494 	    channel(data, "%s", str);
495     } else {
496         channel(data, "%s\n", "out of memory error");
497     }
498     if (code == XML_ERR_OK)
499         return;
500 
501     if (ctxt != NULL) {
502         xmlParserPrintFileContextInternal(input, channel, data);
503         if (cur != NULL) {
504             if (cur->filename)
505                 channel(data, "%s:%d: \n", cur->filename, cur->line);
506             else if ((line != 0) && (domain == XML_FROM_PARSER))
507                 channel(data, "Entity: line %d: \n", cur->line);
508             xmlParserPrintFileContextInternal(cur, channel, data);
509         }
510     }
511     if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
512         (err->int1 < 100) &&
513 	(err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
514 	xmlChar buf[150];
515 	int i;
516 
517 	channel(data, "%s\n", err->str1);
518 	for (i=0;i < err->int1;i++)
519 	     buf[i] = ' ';
520 	buf[i++] = '^';
521 	buf[i] = 0;
522 	channel(data, "%s\n", buf);
523     }
524 }
525 
526 static void
initializeLibxml2(void)527 initializeLibxml2(void) {
528     xmlGetWarningsDefaultValue = 0;
529     xmlPedanticParserDefault(0);
530 
531     xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
532     xmlInitParser();
533     xmlSetExternalEntityLoader(testExternalEntityLoader);
534     xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
535 #ifdef LIBXML_SCHEMAS_ENABLED
536     xmlSchemaInitTypes();
537     xmlRelaxNGInitTypes();
538 #endif
539 }
540 
541 
542 /************************************************************************
543  *									*
544  *		File name and path utilities				*
545  *									*
546  ************************************************************************/
547 
baseFilename(const char * filename)548 static const char *baseFilename(const char *filename) {
549     const char *cur;
550     if (filename == NULL)
551         return(NULL);
552     cur = &filename[strlen(filename)];
553     while ((cur > filename) && (*cur != '/'))
554         cur--;
555     if (*cur == '/')
556         return(cur + 1);
557     return(cur);
558 }
559 
resultFilename(const char * filename,const char * out,const char * suffix)560 static char *resultFilename(const char *filename, const char *out,
561                             const char *suffix) {
562     const char *base;
563     char res[500];
564     char suffixbuff[500];
565 
566 /*************
567     if ((filename[0] == 't') && (filename[1] == 'e') &&
568         (filename[2] == 's') && (filename[3] == 't') &&
569 	(filename[4] == '/'))
570 	filename = &filename[5];
571  *************/
572 
573     base = baseFilename(filename);
574     if (suffix == NULL)
575         suffix = ".tmp";
576     if (out == NULL)
577         out = "";
578 
579     strncpy(suffixbuff,suffix,499);
580 #ifdef VMS
581     if(strstr(base,".") && suffixbuff[0]=='.')
582       suffixbuff[0]='_';
583 #endif
584 
585     snprintf(res, 499, "%s%s%s", out, base, suffixbuff);
586     res[499] = 0;
587     return(strdup(res));
588 }
589 
checkTestFile(const char * filename)590 static int checkTestFile(const char *filename) {
591     struct stat buf;
592 
593     if (stat(filename, &buf) == -1)
594         return(0);
595 
596 #if defined(_WIN32) && !defined(__CYGWIN__)
597     if (!(buf.st_mode & _S_IFREG))
598         return(0);
599 #else
600     if (!S_ISREG(buf.st_mode))
601         return(0);
602 #endif
603 
604     return(1);
605 }
606 
compareFiles(const char * r1,const char * r2)607 static int compareFiles(const char *r1, const char *r2) {
608     int res1, res2;
609     int fd1, fd2;
610     char bytes1[4096];
611     char bytes2[4096];
612 
613     fd1 = open(r1, RD_FLAGS);
614     if (fd1 < 0)
615         return(-1);
616     fd2 = open(r2, RD_FLAGS);
617     if (fd2 < 0) {
618         close(fd1);
619         return(-1);
620     }
621     while (1) {
622         res1 = read(fd1, bytes1, 4096);
623         res2 = read(fd2, bytes2, 4096);
624 	if ((res1 != res2) || (res1 < 0)) {
625 	    close(fd1);
626 	    close(fd2);
627 	    return(1);
628 	}
629 	if (res1 == 0)
630 	    break;
631 	if (memcmp(bytes1, bytes2, res1) != 0) {
632 	    close(fd1);
633 	    close(fd2);
634 	    return(1);
635 	}
636     }
637     close(fd1);
638     close(fd2);
639     return(0);
640 }
641 
compareFileMem(const char * filename,const char * mem,int size)642 static int compareFileMem(const char *filename, const char *mem, int size) {
643     int res;
644     int fd;
645     char bytes[4096];
646     int idx = 0;
647     struct stat info;
648 
649     if (stat(filename, &info) < 0)
650 	return(-1);
651     if (info.st_size != size)
652         return(-1);
653     fd = open(filename, RD_FLAGS);
654     if (fd < 0)
655         return(-1);
656     while (idx < size) {
657         res = read(fd, bytes, 4096);
658 	if (res <= 0)
659 	    break;
660 	if (res + idx > size)
661 	    break;
662 	if (memcmp(bytes, &mem[idx], res) != 0) {
663 	    int ix;
664 	    for (ix=0; ix<res; ix++)
665 		if (bytes[ix] != mem[idx+ix])
666 			break;
667 	    fprintf(stderr,"Compare error at position %d\n", idx+ix);
668 	    close(fd);
669 	    return(1);
670 	}
671 	idx += res;
672     }
673     close(fd);
674     return(idx != size);
675 }
676 
loadMem(const char * filename,const char ** mem,int * size)677 static int loadMem(const char *filename, const char **mem, int *size) {
678     int fd, res;
679     struct stat info;
680     char *base;
681     int siz = 0;
682     if (stat(filename, &info) < 0)
683 	return(-1);
684     base = malloc(info.st_size + 1);
685     if (base == NULL)
686 	return(-1);
687     if ((fd = open(filename, RD_FLAGS)) < 0) {
688         free(base);
689 	return(-1);
690     }
691     while ((res = read(fd, &base[siz], info.st_size - siz)) > 0) {
692         siz += res;
693     }
694     close(fd);
695 #if !defined(_WIN32)
696     if (siz != info.st_size) {
697         free(base);
698 	return(-1);
699     }
700 #endif
701     base[siz] = 0;
702     *mem = base;
703     *size = siz;
704     return(0);
705 }
706 
unloadMem(const char * mem)707 static int unloadMem(const char *mem) {
708     free((char *)mem);
709     return(0);
710 }
711 
712 /************************************************************************
713  *									*
714  *		Tests implementations					*
715  *									*
716  ************************************************************************/
717 
718 /************************************************************************
719  *									*
720  *		Parse to SAX based tests				*
721  *									*
722  ************************************************************************/
723 
724 static FILE *SAXdebug = NULL;
725 
726 /*
727  * empty SAX block
728  */
729 static xmlSAXHandler emptySAXHandlerStruct = {
730     NULL, /* internalSubset */
731     NULL, /* isStandalone */
732     NULL, /* hasInternalSubset */
733     NULL, /* hasExternalSubset */
734     NULL, /* resolveEntity */
735     NULL, /* getEntity */
736     NULL, /* entityDecl */
737     NULL, /* notationDecl */
738     NULL, /* attributeDecl */
739     NULL, /* elementDecl */
740     NULL, /* unparsedEntityDecl */
741     NULL, /* setDocumentLocator */
742     NULL, /* startDocument */
743     NULL, /* endDocument */
744     NULL, /* startElement */
745     NULL, /* endElement */
746     NULL, /* reference */
747     NULL, /* characters */
748     NULL, /* ignorableWhitespace */
749     NULL, /* processingInstruction */
750     NULL, /* comment */
751     NULL, /* xmlParserWarning */
752     NULL, /* xmlParserError */
753     NULL, /* xmlParserError */
754     NULL, /* getParameterEntity */
755     NULL, /* cdataBlock; */
756     NULL, /* externalSubset; */
757     1,
758     NULL,
759     NULL, /* startElementNs */
760     NULL, /* endElementNs */
761     NULL  /* xmlStructuredErrorFunc */
762 };
763 
764 static xmlSAXHandlerPtr emptySAXHandler = &emptySAXHandlerStruct;
765 static int callbacks = 0;
766 static int quiet = 0;
767 
768 /**
769  * isStandaloneDebug:
770  * @ctxt:  An XML parser context
771  *
772  * Is this document tagged standalone ?
773  *
774  * Returns 1 if true
775  */
776 static int
isStandaloneDebug(void * ctx ATTRIBUTE_UNUSED)777 isStandaloneDebug(void *ctx ATTRIBUTE_UNUSED)
778 {
779     callbacks++;
780     if (quiet)
781 	return(0);
782     fprintf(SAXdebug, "SAX.isStandalone()\n");
783     return(0);
784 }
785 
786 /**
787  * hasInternalSubsetDebug:
788  * @ctxt:  An XML parser context
789  *
790  * Does this document has an internal subset
791  *
792  * Returns 1 if true
793  */
794 static int
hasInternalSubsetDebug(void * ctx ATTRIBUTE_UNUSED)795 hasInternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
796 {
797     callbacks++;
798     if (quiet)
799 	return(0);
800     fprintf(SAXdebug, "SAX.hasInternalSubset()\n");
801     return(0);
802 }
803 
804 /**
805  * hasExternalSubsetDebug:
806  * @ctxt:  An XML parser context
807  *
808  * Does this document has an external subset
809  *
810  * Returns 1 if true
811  */
812 static int
hasExternalSubsetDebug(void * ctx ATTRIBUTE_UNUSED)813 hasExternalSubsetDebug(void *ctx ATTRIBUTE_UNUSED)
814 {
815     callbacks++;
816     if (quiet)
817 	return(0);
818     fprintf(SAXdebug, "SAX.hasExternalSubset()\n");
819     return(0);
820 }
821 
822 /**
823  * internalSubsetDebug:
824  * @ctxt:  An XML parser context
825  *
826  * Does this document has an internal subset
827  */
828 static void
internalSubsetDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)829 internalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
830 	       const xmlChar *ExternalID, const xmlChar *SystemID)
831 {
832     callbacks++;
833     if (quiet)
834 	return;
835     fprintf(SAXdebug, "SAX.internalSubset(%s,", name);
836     if (ExternalID == NULL)
837 	fprintf(SAXdebug, " ,");
838     else
839 	fprintf(SAXdebug, " %s,", ExternalID);
840     if (SystemID == NULL)
841 	fprintf(SAXdebug, " )\n");
842     else
843 	fprintf(SAXdebug, " %s)\n", SystemID);
844 }
845 
846 /**
847  * externalSubsetDebug:
848  * @ctxt:  An XML parser context
849  *
850  * Does this document has an external subset
851  */
852 static void
externalSubsetDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * ExternalID,const xmlChar * SystemID)853 externalSubsetDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
854 	       const xmlChar *ExternalID, const xmlChar *SystemID)
855 {
856     callbacks++;
857     if (quiet)
858 	return;
859     fprintf(SAXdebug, "SAX.externalSubset(%s,", name);
860     if (ExternalID == NULL)
861 	fprintf(SAXdebug, " ,");
862     else
863 	fprintf(SAXdebug, " %s,", ExternalID);
864     if (SystemID == NULL)
865 	fprintf(SAXdebug, " )\n");
866     else
867 	fprintf(SAXdebug, " %s)\n", SystemID);
868 }
869 
870 /**
871  * resolveEntityDebug:
872  * @ctxt:  An XML parser context
873  * @publicId: The public ID of the entity
874  * @systemId: The system ID of the entity
875  *
876  * Special entity resolver, better left to the parser, it has
877  * more context than the application layer.
878  * The default behaviour is to NOT resolve the entities, in that case
879  * the ENTITY_REF nodes are built in the structure (and the parameter
880  * values).
881  *
882  * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
883  */
884 static xmlParserInputPtr
resolveEntityDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * publicId,const xmlChar * systemId)885 resolveEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *publicId, const xmlChar *systemId)
886 {
887     callbacks++;
888     if (quiet)
889 	return(NULL);
890     /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
891 
892 
893     fprintf(SAXdebug, "SAX.resolveEntity(");
894     if (publicId != NULL)
895 	fprintf(SAXdebug, "%s", (char *)publicId);
896     else
897 	fprintf(SAXdebug, " ");
898     if (systemId != NULL)
899 	fprintf(SAXdebug, ", %s)\n", (char *)systemId);
900     else
901 	fprintf(SAXdebug, ", )\n");
902 /*********
903     if (systemId != NULL) {
904         return(xmlNewInputFromFile(ctxt, (char *) systemId));
905     }
906  *********/
907     return(NULL);
908 }
909 
910 /**
911  * getEntityDebug:
912  * @ctxt:  An XML parser context
913  * @name: The entity name
914  *
915  * Get an entity by name
916  *
917  * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
918  */
919 static xmlEntityPtr
getEntityDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)920 getEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
921 {
922     callbacks++;
923     if (quiet)
924 	return(NULL);
925     fprintf(SAXdebug, "SAX.getEntity(%s)\n", name);
926     return(NULL);
927 }
928 
929 /**
930  * getParameterEntityDebug:
931  * @ctxt:  An XML parser context
932  * @name: The entity name
933  *
934  * Get a parameter entity by name
935  *
936  * Returns the xmlParserInputPtr
937  */
938 static xmlEntityPtr
getParameterEntityDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)939 getParameterEntityDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
940 {
941     callbacks++;
942     if (quiet)
943 	return(NULL);
944     fprintf(SAXdebug, "SAX.getParameterEntity(%s)\n", name);
945     return(NULL);
946 }
947 
948 
949 /**
950  * entityDeclDebug:
951  * @ctxt:  An XML parser context
952  * @name:  the entity name
953  * @type:  the entity type
954  * @publicId: The public ID of the entity
955  * @systemId: The system ID of the entity
956  * @content: the entity value (without processing).
957  *
958  * An entity definition has been parsed
959  */
960 static void
entityDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,int type,const xmlChar * publicId,const xmlChar * systemId,xmlChar * content)961 entityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
962           const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
963 {
964 const xmlChar *nullstr = BAD_CAST "(null)";
965     /* not all libraries handle printing null pointers nicely */
966     if (publicId == NULL)
967         publicId = nullstr;
968     if (systemId == NULL)
969         systemId = nullstr;
970     if (content == NULL)
971         content = (xmlChar *)nullstr;
972     callbacks++;
973     if (quiet)
974 	return;
975     fprintf(SAXdebug, "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
976             name, type, publicId, systemId, content);
977 }
978 
979 /**
980  * attributeDeclDebug:
981  * @ctxt:  An XML parser context
982  * @name:  the attribute name
983  * @type:  the attribute type
984  *
985  * An attribute definition has been parsed
986  */
987 static void
attributeDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * elem,const xmlChar * name,int type,int def,const xmlChar * defaultValue,xmlEnumerationPtr tree)988 attributeDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar * elem,
989                    const xmlChar * name, int type, int def,
990                    const xmlChar * defaultValue, xmlEnumerationPtr tree)
991 {
992     callbacks++;
993     if (quiet)
994         return;
995     if (defaultValue == NULL)
996         fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, NULL, ...)\n",
997                 elem, name, type, def);
998     else
999         fprintf(SAXdebug, "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
1000                 elem, name, type, def, defaultValue);
1001     xmlFreeEnumeration(tree);
1002 }
1003 
1004 /**
1005  * elementDeclDebug:
1006  * @ctxt:  An XML parser context
1007  * @name:  the element name
1008  * @type:  the element type
1009  * @content: the element value (without processing).
1010  *
1011  * An element definition has been parsed
1012  */
1013 static void
elementDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,int type,xmlElementContentPtr content ATTRIBUTE_UNUSED)1014 elementDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, int type,
1015 	    xmlElementContentPtr content ATTRIBUTE_UNUSED)
1016 {
1017     callbacks++;
1018     if (quiet)
1019 	return;
1020     fprintf(SAXdebug, "SAX.elementDecl(%s, %d, ...)\n",
1021             name, type);
1022 }
1023 
1024 /**
1025  * notationDeclDebug:
1026  * @ctxt:  An XML parser context
1027  * @name: The name of the notation
1028  * @publicId: The public ID of the entity
1029  * @systemId: The system ID of the entity
1030  *
1031  * What to do when a notation declaration has been parsed.
1032  */
1033 static void
notationDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId)1034 notationDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1035 	     const xmlChar *publicId, const xmlChar *systemId)
1036 {
1037     callbacks++;
1038     if (quiet)
1039 	return;
1040     fprintf(SAXdebug, "SAX.notationDecl(%s, %s, %s)\n",
1041             (char *) name, (char *) publicId, (char *) systemId);
1042 }
1043 
1044 /**
1045  * unparsedEntityDeclDebug:
1046  * @ctxt:  An XML parser context
1047  * @name: The name of the entity
1048  * @publicId: The public ID of the entity
1049  * @systemId: The system ID of the entity
1050  * @notationName: the name of the notation
1051  *
1052  * What to do when an unparsed entity declaration is parsed
1053  */
1054 static void
unparsedEntityDeclDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar * publicId,const xmlChar * systemId,const xmlChar * notationName)1055 unparsedEntityDeclDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name,
1056 		   const xmlChar *publicId, const xmlChar *systemId,
1057 		   const xmlChar *notationName)
1058 {
1059 const xmlChar *nullstr = BAD_CAST "(null)";
1060 
1061     if (publicId == NULL)
1062         publicId = nullstr;
1063     if (systemId == NULL)
1064         systemId = nullstr;
1065     if (notationName == NULL)
1066         notationName = nullstr;
1067     callbacks++;
1068     if (quiet)
1069 	return;
1070     fprintf(SAXdebug, "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
1071             (char *) name, (char *) publicId, (char *) systemId,
1072 	    (char *) notationName);
1073 }
1074 
1075 /**
1076  * setDocumentLocatorDebug:
1077  * @ctxt:  An XML parser context
1078  * @loc: A SAX Locator
1079  *
1080  * Receive the document locator at startup, actually xmlDefaultSAXLocator
1081  * Everything is available on the context, so this is useless in our case.
1082  */
1083 static void
setDocumentLocatorDebug(void * ctx ATTRIBUTE_UNUSED,xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)1084 setDocumentLocatorDebug(void *ctx ATTRIBUTE_UNUSED, xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
1085 {
1086     callbacks++;
1087     if (quiet)
1088 	return;
1089     fprintf(SAXdebug, "SAX.setDocumentLocator()\n");
1090 }
1091 
1092 /**
1093  * startDocumentDebug:
1094  * @ctxt:  An XML parser context
1095  *
1096  * called when the document start being processed.
1097  */
1098 static void
startDocumentDebug(void * ctx ATTRIBUTE_UNUSED)1099 startDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1100 {
1101     callbacks++;
1102     if (quiet)
1103 	return;
1104     fprintf(SAXdebug, "SAX.startDocument()\n");
1105 }
1106 
1107 /**
1108  * endDocumentDebug:
1109  * @ctxt:  An XML parser context
1110  *
1111  * called when the document end has been detected.
1112  */
1113 static void
endDocumentDebug(void * ctx ATTRIBUTE_UNUSED)1114 endDocumentDebug(void *ctx ATTRIBUTE_UNUSED)
1115 {
1116     callbacks++;
1117     if (quiet)
1118 	return;
1119     fprintf(SAXdebug, "SAX.endDocument()\n");
1120 }
1121 
1122 /**
1123  * startElementDebug:
1124  * @ctxt:  An XML parser context
1125  * @name:  The element name
1126  *
1127  * called when an opening tag has been processed.
1128  */
1129 static void
startElementDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar ** atts)1130 startElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1131 {
1132     int i;
1133 
1134     callbacks++;
1135     if (quiet)
1136 	return;
1137     fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1138     if (atts != NULL) {
1139         for (i = 0;(atts[i] != NULL);i++) {
1140 	    fprintf(SAXdebug, ", %s='", atts[i++]);
1141 	    if (atts[i] != NULL)
1142 	        fprintf(SAXdebug, "%s'", atts[i]);
1143 	}
1144     }
1145     fprintf(SAXdebug, ")\n");
1146 }
1147 
1148 /**
1149  * endElementDebug:
1150  * @ctxt:  An XML parser context
1151  * @name:  The element name
1152  *
1153  * called when the end of an element has been detected.
1154  */
1155 static void
endElementDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)1156 endElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1157 {
1158     callbacks++;
1159     if (quiet)
1160 	return;
1161     fprintf(SAXdebug, "SAX.endElement(%s)\n", (char *) name);
1162 }
1163 
1164 /**
1165  * charactersDebug:
1166  * @ctxt:  An XML parser context
1167  * @ch:  a xmlChar string
1168  * @len: the number of xmlChar
1169  *
1170  * receiving some chars from the parser.
1171  * Question: how much at a time ???
1172  */
1173 static void
charactersDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)1174 charactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1175 {
1176     char output[40];
1177     int i;
1178 
1179     callbacks++;
1180     if (quiet)
1181 	return;
1182     for (i = 0;(i<len) && (i < 30);i++)
1183 	output[i] = ch[i];
1184     output[i] = 0;
1185 
1186     fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1187 }
1188 
1189 /**
1190  * referenceDebug:
1191  * @ctxt:  An XML parser context
1192  * @name:  The entity name
1193  *
1194  * called when an entity reference is detected.
1195  */
1196 static void
referenceDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name)1197 referenceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name)
1198 {
1199     callbacks++;
1200     if (quiet)
1201 	return;
1202     fprintf(SAXdebug, "SAX.reference(%s)\n", name);
1203 }
1204 
1205 /**
1206  * ignorableWhitespaceDebug:
1207  * @ctxt:  An XML parser context
1208  * @ch:  a xmlChar string
1209  * @start: the first char in the string
1210  * @len: the number of xmlChar
1211  *
1212  * receiving some ignorable whitespaces from the parser.
1213  * Question: how much at a time ???
1214  */
1215 static void
ignorableWhitespaceDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)1216 ignorableWhitespaceDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1217 {
1218     char output[40];
1219     int i;
1220 
1221     callbacks++;
1222     if (quiet)
1223 	return;
1224     for (i = 0;(i<len) && (i < 30);i++)
1225 	output[i] = ch[i];
1226     output[i] = 0;
1227     fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
1228 }
1229 
1230 /**
1231  * processingInstructionDebug:
1232  * @ctxt:  An XML parser context
1233  * @target:  the target name
1234  * @data: the PI data's
1235  * @len: the number of xmlChar
1236  *
1237  * A processing instruction has been parsed.
1238  */
1239 static void
processingInstructionDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * target,const xmlChar * data)1240 processingInstructionDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *target,
1241                       const xmlChar *data)
1242 {
1243     callbacks++;
1244     if (quiet)
1245 	return;
1246     if (data != NULL)
1247 	fprintf(SAXdebug, "SAX.processingInstruction(%s, %s)\n",
1248 		(char *) target, (char *) data);
1249     else
1250 	fprintf(SAXdebug, "SAX.processingInstruction(%s, NULL)\n",
1251 		(char *) target);
1252 }
1253 
1254 /**
1255  * cdataBlockDebug:
1256  * @ctx: the user data (XML parser context)
1257  * @value:  The pcdata content
1258  * @len:  the block length
1259  *
1260  * called when a pcdata block has been parsed
1261  */
1262 static void
cdataBlockDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * value,int len)1263 cdataBlockDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value, int len)
1264 {
1265     callbacks++;
1266     if (quiet)
1267 	return;
1268     fprintf(SAXdebug, "SAX.pcdata(%.20s, %d)\n",
1269 	    (char *) value, len);
1270 }
1271 
1272 /**
1273  * commentDebug:
1274  * @ctxt:  An XML parser context
1275  * @value:  the comment content
1276  *
1277  * A comment has been parsed.
1278  */
1279 static void
commentDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * value)1280 commentDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *value)
1281 {
1282     callbacks++;
1283     if (quiet)
1284 	return;
1285     fprintf(SAXdebug, "SAX.comment(%s)\n", value);
1286 }
1287 
1288 /**
1289  * warningDebug:
1290  * @ctxt:  An XML parser context
1291  * @msg:  the message to display/transmit
1292  * @...:  extra parameters for the message display
1293  *
1294  * Display and format a warning messages, gives file, line, position and
1295  * extra parameters.
1296  */
1297 static void XMLCDECL
warningDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)1298 warningDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1299 {
1300     va_list args;
1301 
1302     callbacks++;
1303     if (quiet)
1304 	return;
1305     va_start(args, msg);
1306     fprintf(SAXdebug, "SAX.warning: ");
1307     vfprintf(SAXdebug, msg, args);
1308     va_end(args);
1309 }
1310 
1311 /**
1312  * errorDebug:
1313  * @ctxt:  An XML parser context
1314  * @msg:  the message to display/transmit
1315  * @...:  extra parameters for the message display
1316  *
1317  * Display and format a error messages, gives file, line, position and
1318  * extra parameters.
1319  */
1320 static void XMLCDECL
errorDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)1321 errorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1322 {
1323     va_list args;
1324 
1325     callbacks++;
1326     if (quiet)
1327 	return;
1328     va_start(args, msg);
1329     fprintf(SAXdebug, "SAX.error: ");
1330     vfprintf(SAXdebug, msg, args);
1331     va_end(args);
1332 }
1333 
1334 /**
1335  * fatalErrorDebug:
1336  * @ctxt:  An XML parser context
1337  * @msg:  the message to display/transmit
1338  * @...:  extra parameters for the message display
1339  *
1340  * Display and format a fatalError messages, gives file, line, position and
1341  * extra parameters.
1342  */
1343 static void XMLCDECL
fatalErrorDebug(void * ctx ATTRIBUTE_UNUSED,const char * msg,...)1344 fatalErrorDebug(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...)
1345 {
1346     va_list args;
1347 
1348     callbacks++;
1349     if (quiet)
1350 	return;
1351     va_start(args, msg);
1352     fprintf(SAXdebug, "SAX.fatalError: ");
1353     vfprintf(SAXdebug, msg, args);
1354     va_end(args);
1355 }
1356 
1357 static xmlSAXHandler debugSAXHandlerStruct = {
1358     internalSubsetDebug,
1359     isStandaloneDebug,
1360     hasInternalSubsetDebug,
1361     hasExternalSubsetDebug,
1362     resolveEntityDebug,
1363     getEntityDebug,
1364     entityDeclDebug,
1365     notationDeclDebug,
1366     attributeDeclDebug,
1367     elementDeclDebug,
1368     unparsedEntityDeclDebug,
1369     setDocumentLocatorDebug,
1370     startDocumentDebug,
1371     endDocumentDebug,
1372     startElementDebug,
1373     endElementDebug,
1374     referenceDebug,
1375     charactersDebug,
1376     ignorableWhitespaceDebug,
1377     processingInstructionDebug,
1378     commentDebug,
1379     warningDebug,
1380     errorDebug,
1381     fatalErrorDebug,
1382     getParameterEntityDebug,
1383     cdataBlockDebug,
1384     externalSubsetDebug,
1385     1,
1386     NULL,
1387     NULL,
1388     NULL,
1389     NULL
1390 };
1391 
1392 static xmlSAXHandlerPtr debugSAXHandler = &debugSAXHandlerStruct;
1393 
1394 /*
1395  * SAX2 specific callbacks
1396  */
1397 /**
1398  * startElementNsDebug:
1399  * @ctxt:  An XML parser context
1400  * @name:  The element name
1401  *
1402  * called when an opening tag has been processed.
1403  */
1404 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)1405 startElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1406                     const xmlChar *localname,
1407                     const xmlChar *prefix,
1408                     const xmlChar *URI,
1409 		    int nb_namespaces,
1410 		    const xmlChar **namespaces,
1411 		    int nb_attributes,
1412 		    int nb_defaulted,
1413 		    const xmlChar **attributes)
1414 {
1415     int i;
1416 
1417     callbacks++;
1418     if (quiet)
1419 	return;
1420     fprintf(SAXdebug, "SAX.startElementNs(%s", (char *) localname);
1421     if (prefix == NULL)
1422 	fprintf(SAXdebug, ", NULL");
1423     else
1424 	fprintf(SAXdebug, ", %s", (char *) prefix);
1425     if (URI == NULL)
1426 	fprintf(SAXdebug, ", NULL");
1427     else
1428 	fprintf(SAXdebug, ", '%s'", (char *) URI);
1429     fprintf(SAXdebug, ", %d", nb_namespaces);
1430 
1431     if (namespaces != NULL) {
1432         for (i = 0;i < nb_namespaces * 2;i++) {
1433 	    fprintf(SAXdebug, ", xmlns");
1434 	    if (namespaces[i] != NULL)
1435 	        fprintf(SAXdebug, ":%s", namespaces[i]);
1436 	    i++;
1437 	    fprintf(SAXdebug, "='%s'", namespaces[i]);
1438 	}
1439     }
1440     fprintf(SAXdebug, ", %d, %d", nb_attributes, nb_defaulted);
1441     if (attributes != NULL) {
1442         for (i = 0;i < nb_attributes * 5;i += 5) {
1443 	    if (attributes[i + 1] != NULL)
1444 		fprintf(SAXdebug, ", %s:%s='", attributes[i + 1], attributes[i]);
1445 	    else
1446 		fprintf(SAXdebug, ", %s='", attributes[i]);
1447 	    fprintf(SAXdebug, "%.4s...', %d", attributes[i + 3],
1448 		    (int)(attributes[i + 4] - attributes[i + 3]));
1449 	}
1450     }
1451     fprintf(SAXdebug, ")\n");
1452 }
1453 
1454 /**
1455  * endElementDebug:
1456  * @ctxt:  An XML parser context
1457  * @name:  The element name
1458  *
1459  * called when the end of an element has been detected.
1460  */
1461 static void
endElementNsDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * localname,const xmlChar * prefix,const xmlChar * URI)1462 endElementNsDebug(void *ctx ATTRIBUTE_UNUSED,
1463                   const xmlChar *localname,
1464                   const xmlChar *prefix,
1465                   const xmlChar *URI)
1466 {
1467     callbacks++;
1468     if (quiet)
1469 	return;
1470     fprintf(SAXdebug, "SAX.endElementNs(%s", (char *) localname);
1471     if (prefix == NULL)
1472 	fprintf(SAXdebug, ", NULL");
1473     else
1474 	fprintf(SAXdebug, ", %s", (char *) prefix);
1475     if (URI == NULL)
1476 	fprintf(SAXdebug, ", NULL)\n");
1477     else
1478 	fprintf(SAXdebug, ", '%s')\n", (char *) URI);
1479 }
1480 
1481 static xmlSAXHandler debugSAX2HandlerStruct = {
1482     internalSubsetDebug,
1483     isStandaloneDebug,
1484     hasInternalSubsetDebug,
1485     hasExternalSubsetDebug,
1486     resolveEntityDebug,
1487     getEntityDebug,
1488     entityDeclDebug,
1489     notationDeclDebug,
1490     attributeDeclDebug,
1491     elementDeclDebug,
1492     unparsedEntityDeclDebug,
1493     setDocumentLocatorDebug,
1494     startDocumentDebug,
1495     endDocumentDebug,
1496     NULL,
1497     NULL,
1498     referenceDebug,
1499     charactersDebug,
1500     ignorableWhitespaceDebug,
1501     processingInstructionDebug,
1502     commentDebug,
1503     warningDebug,
1504     errorDebug,
1505     fatalErrorDebug,
1506     getParameterEntityDebug,
1507     cdataBlockDebug,
1508     externalSubsetDebug,
1509     XML_SAX2_MAGIC,
1510     NULL,
1511     startElementNsDebug,
1512     endElementNsDebug,
1513     NULL
1514 };
1515 
1516 static xmlSAXHandlerPtr debugSAX2Handler = &debugSAX2HandlerStruct;
1517 
1518 #ifdef LIBXML_HTML_ENABLED
1519 /**
1520  * htmlstartElementDebug:
1521  * @ctxt:  An XML parser context
1522  * @name:  The element name
1523  *
1524  * called when an opening tag has been processed.
1525  */
1526 static void
htmlstartElementDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * name,const xmlChar ** atts)1527 htmlstartElementDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *name, const xmlChar **atts)
1528 {
1529     int i;
1530 
1531     fprintf(SAXdebug, "SAX.startElement(%s", (char *) name);
1532     if (atts != NULL) {
1533         for (i = 0;(atts[i] != NULL);i++) {
1534 	    fprintf(SAXdebug, ", %s", atts[i++]);
1535 	    if (atts[i] != NULL) {
1536 		unsigned char output[40];
1537 		const unsigned char *att = atts[i];
1538 		int outlen, attlen;
1539 	        fprintf(SAXdebug, "='");
1540 		while ((attlen = strlen((char*)att)) > 0) {
1541 		    outlen = sizeof output - 1;
1542 		    htmlEncodeEntities(output, &outlen, att, &attlen, '\'');
1543 		    output[outlen] = 0;
1544 		    fprintf(SAXdebug, "%s", (char *) output);
1545 		    att += attlen;
1546 		}
1547 		fprintf(SAXdebug, "'");
1548 	    }
1549 	}
1550     }
1551     fprintf(SAXdebug, ")\n");
1552 }
1553 
1554 /**
1555  * htmlcharactersDebug:
1556  * @ctxt:  An XML parser context
1557  * @ch:  a xmlChar string
1558  * @len: the number of xmlChar
1559  *
1560  * receiving some chars from the parser.
1561  * Question: how much at a time ???
1562  */
1563 static void
htmlcharactersDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)1564 htmlcharactersDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1565 {
1566     unsigned char output[40];
1567     int inlen = len, outlen = 30;
1568 
1569     htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1570     output[outlen] = 0;
1571 
1572     fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1573 }
1574 
1575 /**
1576  * htmlcdataDebug:
1577  * @ctxt:  An XML parser context
1578  * @ch:  a xmlChar string
1579  * @len: the number of xmlChar
1580  *
1581  * receiving some cdata chars from the parser.
1582  * Question: how much at a time ???
1583  */
1584 static void
htmlcdataDebug(void * ctx ATTRIBUTE_UNUSED,const xmlChar * ch,int len)1585 htmlcdataDebug(void *ctx ATTRIBUTE_UNUSED, const xmlChar *ch, int len)
1586 {
1587     unsigned char output[40];
1588     int inlen = len, outlen = 30;
1589 
1590     htmlEncodeEntities(output, &outlen, ch, &inlen, 0);
1591     output[outlen] = 0;
1592 
1593     fprintf(SAXdebug, "SAX.cdata(%s, %d)\n", output, len);
1594 }
1595 
1596 static xmlSAXHandler debugHTMLSAXHandlerStruct = {
1597     internalSubsetDebug,
1598     isStandaloneDebug,
1599     hasInternalSubsetDebug,
1600     hasExternalSubsetDebug,
1601     resolveEntityDebug,
1602     getEntityDebug,
1603     entityDeclDebug,
1604     notationDeclDebug,
1605     attributeDeclDebug,
1606     elementDeclDebug,
1607     unparsedEntityDeclDebug,
1608     setDocumentLocatorDebug,
1609     startDocumentDebug,
1610     endDocumentDebug,
1611     htmlstartElementDebug,
1612     endElementDebug,
1613     referenceDebug,
1614     htmlcharactersDebug,
1615     ignorableWhitespaceDebug,
1616     processingInstructionDebug,
1617     commentDebug,
1618     warningDebug,
1619     errorDebug,
1620     fatalErrorDebug,
1621     getParameterEntityDebug,
1622     htmlcdataDebug,
1623     externalSubsetDebug,
1624     1,
1625     NULL,
1626     NULL,
1627     NULL,
1628     NULL
1629 };
1630 
1631 static xmlSAXHandlerPtr debugHTMLSAXHandler = &debugHTMLSAXHandlerStruct;
1632 #endif /* LIBXML_HTML_ENABLED */
1633 
1634 #ifdef LIBXML_SAX1_ENABLED
1635 /**
1636  * saxParseTest:
1637  * @filename: the file to parse
1638  * @result: the file with expected result
1639  * @err: the file with error messages
1640  *
1641  * Parse a file using the SAX API and check for errors.
1642  *
1643  * Returns 0 in case of success, an error code otherwise
1644  */
1645 static int
saxParseTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options)1646 saxParseTest(const char *filename, const char *result,
1647              const char *err ATTRIBUTE_UNUSED,
1648              int options) {
1649     int ret;
1650     char *temp;
1651 
1652     nb_tests++;
1653     temp = resultFilename(filename, "", ".res");
1654     if (temp == NULL) {
1655         fprintf(stderr, "out of memory\n");
1656         fatalError();
1657     }
1658     SAXdebug = fopen(temp, "wb");
1659     if (SAXdebug == NULL) {
1660         fprintf(stderr, "Failed to write to %s\n", temp);
1661 	free(temp);
1662 	return(-1);
1663     }
1664 
1665     /* for SAX we really want the callbacks though the context handlers */
1666     xmlSetStructuredErrorFunc(NULL, NULL);
1667     xmlSetGenericErrorFunc(NULL, testErrorHandler);
1668 
1669 #ifdef LIBXML_HTML_ENABLED
1670     if (options & XML_PARSE_HTML) {
1671 	htmlSAXParseFile(filename, NULL, emptySAXHandler, NULL);
1672 	ret = 0;
1673     } else
1674 #endif
1675     ret = xmlSAXUserParseFile(emptySAXHandler, NULL, filename);
1676     if (ret == XML_WAR_UNDECLARED_ENTITY) {
1677         fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1678         ret = 0;
1679     }
1680     if (ret != 0) {
1681         fprintf(stderr, "Failed to parse %s\n", filename);
1682 	ret = 1;
1683 	goto done;
1684     }
1685 #ifdef LIBXML_HTML_ENABLED
1686     if (options & XML_PARSE_HTML) {
1687 	htmlSAXParseFile(filename, NULL, debugHTMLSAXHandler, NULL);
1688 	ret = 0;
1689     } else
1690 #endif
1691     if (options & XML_PARSE_SAX1) {
1692 	ret = xmlSAXUserParseFile(debugSAXHandler, NULL, filename);
1693     } else {
1694 	ret = xmlSAXUserParseFile(debugSAX2Handler, NULL, filename);
1695     }
1696     if (ret == XML_WAR_UNDECLARED_ENTITY) {
1697         fprintf(SAXdebug, "xmlSAXUserParseFile returned error %d\n", ret);
1698         ret = 0;
1699     }
1700     fclose(SAXdebug);
1701     if (compareFiles(temp, result)) {
1702         fprintf(stderr, "Got a difference for %s\n", filename);
1703         ret = 1;
1704     }
1705 
1706 done:
1707     if (temp != NULL) {
1708         unlink(temp);
1709         free(temp);
1710     }
1711 
1712     /* switch back to structured error handling */
1713     xmlSetGenericErrorFunc(NULL, NULL);
1714     xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
1715 
1716     return(ret);
1717 }
1718 #endif
1719 
1720 /************************************************************************
1721  *									*
1722  *		Parse to tree based tests				*
1723  *									*
1724  ************************************************************************/
1725 /**
1726  * oldParseTest:
1727  * @filename: the file to parse
1728  * @result: the file with expected result
1729  * @err: the file with error messages: unused
1730  *
1731  * Parse a file using the old xmlParseFile API, then serialize back
1732  * reparse the result and serialize again, then check for deviation
1733  * in serialization.
1734  *
1735  * Returns 0 in case of success, an error code otherwise
1736  */
1737 static int
oldParseTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)1738 oldParseTest(const char *filename, const char *result,
1739              const char *err ATTRIBUTE_UNUSED,
1740 	     int options ATTRIBUTE_UNUSED) {
1741     xmlDocPtr doc;
1742     char *temp;
1743     int res = 0;
1744 
1745     nb_tests++;
1746     /*
1747      * base of the test, parse with the old API
1748      */
1749 #ifdef LIBXML_SAX1_ENABLED
1750     doc = xmlParseFile(filename);
1751 #else
1752     doc = xmlReadFile(filename, NULL, 0);
1753 #endif
1754     if (doc == NULL)
1755         return(1);
1756     temp = resultFilename(filename, "", ".res");
1757     if (temp == NULL) {
1758         fprintf(stderr, "out of memory\n");
1759         fatalError();
1760     }
1761     xmlSaveFile(temp, doc);
1762     if (compareFiles(temp, result)) {
1763         res = 1;
1764     }
1765     xmlFreeDoc(doc);
1766 
1767     /*
1768      * Parse the saved result to make sure the round trip is okay
1769      */
1770 #ifdef LIBXML_SAX1_ENABLED
1771     doc = xmlParseFile(temp);
1772 #else
1773     doc = xmlReadFile(temp, NULL, 0);
1774 #endif
1775     if (doc == NULL)
1776         return(1);
1777     xmlSaveFile(temp, doc);
1778     if (compareFiles(temp, result)) {
1779         res = 1;
1780     }
1781     xmlFreeDoc(doc);
1782 
1783     if (temp != NULL) {
1784         unlink(temp);
1785         free(temp);
1786     }
1787     return(res);
1788 }
1789 
1790 #ifdef LIBXML_PUSH_ENABLED
1791 /**
1792  * pushParseTest:
1793  * @filename: the file to parse
1794  * @result: the file with expected result
1795  * @err: the file with error messages: unused
1796  *
1797  * Parse a file using the Push API, then serialize back
1798  * to check for content.
1799  *
1800  * Returns 0 in case of success, an error code otherwise
1801  */
1802 static int
pushParseTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options)1803 pushParseTest(const char *filename, const char *result,
1804              const char *err ATTRIBUTE_UNUSED,
1805 	     int options) {
1806     xmlParserCtxtPtr ctxt;
1807     xmlDocPtr doc;
1808     const char *base;
1809     int size, res;
1810     int cur = 0;
1811 
1812     nb_tests++;
1813     /*
1814      * load the document in memory and work from there.
1815      */
1816     if (loadMem(filename, &base, &size) != 0) {
1817         fprintf(stderr, "Failed to load %s\n", filename);
1818 	return(-1);
1819     }
1820 
1821 #ifdef LIBXML_HTML_ENABLED
1822     if (options & XML_PARSE_HTML)
1823 	ctxt = htmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename,
1824 	                                XML_CHAR_ENCODING_NONE);
1825     else
1826 #endif
1827     ctxt = xmlCreatePushParserCtxt(NULL, NULL, base + cur, 4, filename);
1828     xmlCtxtUseOptions(ctxt, options);
1829     cur += 4;
1830     while (cur < size) {
1831         if (cur + 1024 >= size) {
1832 #ifdef LIBXML_HTML_ENABLED
1833 	    if (options & XML_PARSE_HTML)
1834 		htmlParseChunk(ctxt, base + cur, size - cur, 1);
1835 	    else
1836 #endif
1837 	    xmlParseChunk(ctxt, base + cur, size - cur, 1);
1838 	    break;
1839 	} else {
1840 #ifdef LIBXML_HTML_ENABLED
1841 	    if (options & XML_PARSE_HTML)
1842 		htmlParseChunk(ctxt, base + cur, 1024, 0);
1843 	    else
1844 #endif
1845 	    xmlParseChunk(ctxt, base + cur, 1024, 0);
1846 	    cur += 1024;
1847 	}
1848     }
1849     doc = ctxt->myDoc;
1850 #ifdef LIBXML_HTML_ENABLED
1851     if (options & XML_PARSE_HTML)
1852         res = 1;
1853     else
1854 #endif
1855     res = ctxt->wellFormed;
1856     xmlFreeParserCtxt(ctxt);
1857     free((char *)base);
1858     if (!res) {
1859 	xmlFreeDoc(doc);
1860 	fprintf(stderr, "Failed to parse %s\n", filename);
1861 	return(-1);
1862     }
1863 #ifdef LIBXML_HTML_ENABLED
1864     if (options & XML_PARSE_HTML)
1865 	htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1866     else
1867 #endif
1868     xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1869     xmlFreeDoc(doc);
1870     res = compareFileMem(result, base, size);
1871     if ((base == NULL) || (res != 0)) {
1872 	if (base != NULL)
1873 	    xmlFree((char *)base);
1874         fprintf(stderr, "Result for %s failed\n", filename);
1875 	return(-1);
1876     }
1877     xmlFree((char *)base);
1878     if (err != NULL) {
1879 	res = compareFileMem(err, testErrors, testErrorsSize);
1880 	if (res != 0) {
1881 	    fprintf(stderr, "Error for %s failed\n", filename);
1882 	    return(-1);
1883 	}
1884     }
1885     return(0);
1886 }
1887 #endif
1888 
1889 /**
1890  * memParseTest:
1891  * @filename: the file to parse
1892  * @result: the file with expected result
1893  * @err: the file with error messages: unused
1894  *
1895  * Parse a file using the old xmlReadMemory API, then serialize back
1896  * reparse the result and serialize again, then check for deviation
1897  * in serialization.
1898  *
1899  * Returns 0 in case of success, an error code otherwise
1900  */
1901 static int
memParseTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)1902 memParseTest(const char *filename, const char *result,
1903              const char *err ATTRIBUTE_UNUSED,
1904 	     int options ATTRIBUTE_UNUSED) {
1905     xmlDocPtr doc;
1906     const char *base;
1907     int size, res;
1908 
1909     nb_tests++;
1910     /*
1911      * load and parse the memory
1912      */
1913     if (loadMem(filename, &base, &size) != 0) {
1914         fprintf(stderr, "Failed to load %s\n", filename);
1915 	return(-1);
1916     }
1917 
1918     doc = xmlReadMemory(base, size, filename, NULL, 0);
1919     unloadMem(base);
1920     if (doc == NULL) {
1921         return(1);
1922     }
1923     xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
1924     xmlFreeDoc(doc);
1925     res = compareFileMem(result, base, size);
1926     if ((base == NULL) || (res != 0)) {
1927 	if (base != NULL)
1928 	    xmlFree((char *)base);
1929         fprintf(stderr, "Result for %s failed\n", filename);
1930 	return(-1);
1931     }
1932     xmlFree((char *)base);
1933     return(0);
1934 }
1935 
1936 /**
1937  * noentParseTest:
1938  * @filename: the file to parse
1939  * @result: the file with expected result
1940  * @err: the file with error messages: unused
1941  *
1942  * Parse a file with entity resolution, then serialize back
1943  * reparse the result and serialize again, then check for deviation
1944  * in serialization.
1945  *
1946  * Returns 0 in case of success, an error code otherwise
1947  */
1948 static int
noentParseTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options)1949 noentParseTest(const char *filename, const char *result,
1950                const char *err  ATTRIBUTE_UNUSED,
1951 	       int options) {
1952     xmlDocPtr doc;
1953     char *temp;
1954     int res = 0;
1955 
1956     nb_tests++;
1957     /*
1958      * base of the test, parse with the old API
1959      */
1960     doc = xmlReadFile(filename, NULL, options);
1961     if (doc == NULL)
1962         return(1);
1963     temp = resultFilename(filename, "", ".res");
1964     if (temp == NULL) {
1965         fprintf(stderr, "Out of memory\n");
1966         fatalError();
1967     }
1968     xmlSaveFile(temp, doc);
1969     if (compareFiles(temp, result)) {
1970         res = 1;
1971     }
1972     xmlFreeDoc(doc);
1973 
1974     /*
1975      * Parse the saved result to make sure the round trip is okay
1976      */
1977     doc = xmlReadFile(filename, NULL, options);
1978     if (doc == NULL)
1979         return(1);
1980     xmlSaveFile(temp, doc);
1981     if (compareFiles(temp, result)) {
1982         res = 1;
1983     }
1984     xmlFreeDoc(doc);
1985 
1986     if (temp != NULL) {
1987         unlink(temp);
1988         free(temp);
1989     }
1990     return(res);
1991 }
1992 
1993 /**
1994  * errParseTest:
1995  * @filename: the file to parse
1996  * @result: the file with expected result
1997  * @err: the file with error messages
1998  *
1999  * Parse a file using the xmlReadFile API and check for errors.
2000  *
2001  * Returns 0 in case of success, an error code otherwise
2002  */
2003 static int
errParseTest(const char * filename,const char * result,const char * err,int options)2004 errParseTest(const char *filename, const char *result, const char *err,
2005              int options) {
2006     xmlDocPtr doc;
2007     const char *base = NULL;
2008     int size, res = 0;
2009 
2010     nb_tests++;
2011 #ifdef LIBXML_HTML_ENABLED
2012     if (options & XML_PARSE_HTML) {
2013         doc = htmlReadFile(filename, NULL, options);
2014     } else
2015 #endif
2016 #ifdef LIBXML_XINCLUDE_ENABLED
2017     if (options & XML_PARSE_XINCLUDE) {
2018 	doc = xmlReadFile(filename, NULL, options);
2019 	xmlXIncludeProcessFlags(doc, options);
2020     } else
2021 #endif
2022     {
2023 	xmlGetWarningsDefaultValue = 1;
2024 	doc = xmlReadFile(filename, NULL, options);
2025     }
2026     xmlGetWarningsDefaultValue = 0;
2027     if (result) {
2028 	if (doc == NULL) {
2029 	    base = "";
2030 	    size = 0;
2031 	} else {
2032 #ifdef LIBXML_HTML_ENABLED
2033 	    if (options & XML_PARSE_HTML) {
2034 		htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2035 	    } else
2036 #endif
2037 	    xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2038 	}
2039 	res = compareFileMem(result, base, size);
2040     }
2041     if (doc != NULL) {
2042 	if (base != NULL)
2043 	    xmlFree((char *)base);
2044 	xmlFreeDoc(doc);
2045     }
2046     if (res != 0) {
2047         fprintf(stderr, "Result for %s failed\n", filename);
2048 	return(-1);
2049     }
2050     if (err != NULL) {
2051 	res = compareFileMem(err, testErrors, testErrorsSize);
2052 	if (res != 0) {
2053 	    fprintf(stderr, "Error for %s failed\n", filename);
2054 	    return(-1);
2055 	}
2056     } else if (options & XML_PARSE_DTDVALID) {
2057         if (testErrorsSize != 0)
2058 	    fprintf(stderr, "Validation for %s failed\n", filename);
2059     }
2060 
2061     return(0);
2062 }
2063 
2064 #ifdef LIBXML_READER_ENABLED
2065 /************************************************************************
2066  *									*
2067  *		Reader based tests					*
2068  *									*
2069  ************************************************************************/
2070 
processNode(FILE * out,xmlTextReaderPtr reader)2071 static void processNode(FILE *out, xmlTextReaderPtr reader) {
2072     const xmlChar *name, *value;
2073     int type, empty;
2074 
2075     type = xmlTextReaderNodeType(reader);
2076     empty = xmlTextReaderIsEmptyElement(reader);
2077 
2078     name = xmlTextReaderConstName(reader);
2079     if (name == NULL)
2080 	name = BAD_CAST "--";
2081 
2082     value = xmlTextReaderConstValue(reader);
2083 
2084 
2085     fprintf(out, "%d %d %s %d %d",
2086 	    xmlTextReaderDepth(reader),
2087 	    type,
2088 	    name,
2089 	    empty,
2090 	    xmlTextReaderHasValue(reader));
2091     if (value == NULL)
2092 	fprintf(out, "\n");
2093     else {
2094 	fprintf(out, " %s\n", value);
2095     }
2096 }
2097 static int
streamProcessTest(const char * filename,const char * result,const char * err,xmlTextReaderPtr reader,const char * rng,int options)2098 streamProcessTest(const char *filename, const char *result, const char *err,
2099                   xmlTextReaderPtr reader, const char *rng, int options) {
2100     int ret;
2101     char *temp = NULL;
2102     FILE *t = NULL;
2103 
2104     if (reader == NULL)
2105         return(-1);
2106 
2107     nb_tests++;
2108     if (result != NULL) {
2109 	temp = resultFilename(filename, "", ".res");
2110 	if (temp == NULL) {
2111 	    fprintf(stderr, "Out of memory\n");
2112 	    fatalError();
2113 	}
2114 	t = fopen(temp, "wb");
2115 	if (t == NULL) {
2116 	    fprintf(stderr, "Can't open temp file %s\n", temp);
2117 	    free(temp);
2118 	    return(-1);
2119 	}
2120     }
2121 #ifdef LIBXML_SCHEMAS_ENABLED
2122     if (rng != NULL) {
2123 	ret = xmlTextReaderRelaxNGValidate(reader, rng);
2124 	if (ret < 0) {
2125 	    testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
2126 	                     rng);
2127 	    fclose(t);
2128             if (temp != NULL) {
2129                 unlink(temp);
2130                 free(temp);
2131             }
2132 	    return(0);
2133 	}
2134     }
2135 #endif
2136     xmlGetWarningsDefaultValue = 1;
2137     ret = xmlTextReaderRead(reader);
2138     while (ret == 1) {
2139 	if ((t != NULL) && (rng == NULL))
2140 	    processNode(t, reader);
2141         ret = xmlTextReaderRead(reader);
2142     }
2143     if (ret != 0) {
2144         testErrorHandler(NULL, "%s : failed to parse\n", filename);
2145     }
2146     if (rng != NULL) {
2147         if (xmlTextReaderIsValid(reader) != 1) {
2148 	    testErrorHandler(NULL, "%s fails to validate\n", filename);
2149 	} else {
2150 	    testErrorHandler(NULL, "%s validates\n", filename);
2151 	}
2152     }
2153     xmlGetWarningsDefaultValue = 0;
2154     if (t != NULL) {
2155         fclose(t);
2156 	ret = compareFiles(temp, result);
2157         if (temp != NULL) {
2158             unlink(temp);
2159             free(temp);
2160         }
2161 	if (ret) {
2162 	    fprintf(stderr, "Result for %s failed\n", filename);
2163 	    return(-1);
2164 	}
2165     }
2166     if (err != NULL) {
2167 	ret = compareFileMem(err, testErrors, testErrorsSize);
2168 	if (ret != 0) {
2169 	    fprintf(stderr, "Error for %s failed\n", filename);
2170 	    printf("%s", testErrors);
2171 	    return(-1);
2172 	}
2173     }
2174 
2175     return(0);
2176 }
2177 
2178 /**
2179  * streamParseTest:
2180  * @filename: the file to parse
2181  * @result: the file with expected result
2182  * @err: the file with error messages
2183  *
2184  * Parse a file using the reader API and check for errors.
2185  *
2186  * Returns 0 in case of success, an error code otherwise
2187  */
2188 static int
streamParseTest(const char * filename,const char * result,const char * err,int options)2189 streamParseTest(const char *filename, const char *result, const char *err,
2190                 int options) {
2191     xmlTextReaderPtr reader;
2192     int ret;
2193 
2194     reader = xmlReaderForFile(filename, NULL, options);
2195     ret = streamProcessTest(filename, result, err, reader, NULL, options);
2196     xmlFreeTextReader(reader);
2197     return(ret);
2198 }
2199 
2200 /**
2201  * walkerParseTest:
2202  * @filename: the file to parse
2203  * @result: the file with expected result
2204  * @err: the file with error messages
2205  *
2206  * Parse a file using the walker, i.e. a reader built from a atree.
2207  *
2208  * Returns 0 in case of success, an error code otherwise
2209  */
2210 static int
walkerParseTest(const char * filename,const char * result,const char * err,int options)2211 walkerParseTest(const char *filename, const char *result, const char *err,
2212                 int options) {
2213     xmlDocPtr doc;
2214     xmlTextReaderPtr reader;
2215     int ret;
2216 
2217     doc = xmlReadFile(filename, NULL, options);
2218     if (doc == NULL) {
2219         fprintf(stderr, "Failed to parse %s\n", filename);
2220 	return(-1);
2221     }
2222     reader = xmlReaderWalker(doc);
2223     ret = streamProcessTest(filename, result, err, reader, NULL, options);
2224     xmlFreeTextReader(reader);
2225     xmlFreeDoc(doc);
2226     return(ret);
2227 }
2228 
2229 /**
2230  * streamMemParseTest:
2231  * @filename: the file to parse
2232  * @result: the file with expected result
2233  * @err: the file with error messages
2234  *
2235  * Parse a file using the reader API from memory and check for errors.
2236  *
2237  * Returns 0 in case of success, an error code otherwise
2238  */
2239 static int
streamMemParseTest(const char * filename,const char * result,const char * err,int options)2240 streamMemParseTest(const char *filename, const char *result, const char *err,
2241                    int options) {
2242     xmlTextReaderPtr reader;
2243     int ret;
2244     const char *base;
2245     int size;
2246 
2247     /*
2248      * load and parse the memory
2249      */
2250     if (loadMem(filename, &base, &size) != 0) {
2251         fprintf(stderr, "Failed to load %s\n", filename);
2252 	return(-1);
2253     }
2254     reader = xmlReaderForMemory(base, size, filename, NULL, options);
2255     ret = streamProcessTest(filename, result, err, reader, NULL, options);
2256     free((char *)base);
2257     xmlFreeTextReader(reader);
2258     return(ret);
2259 }
2260 #endif
2261 
2262 #ifdef LIBXML_XPATH_ENABLED
2263 #ifdef LIBXML_DEBUG_ENABLED
2264 /************************************************************************
2265  *									*
2266  *		XPath and XPointer based tests				*
2267  *									*
2268  ************************************************************************/
2269 
2270 static FILE *xpathOutput;
2271 static xmlDocPtr xpathDocument;
2272 
2273 static void
testXPath(const char * str,int xptr,int expr)2274 testXPath(const char *str, int xptr, int expr) {
2275     xmlXPathObjectPtr res;
2276     xmlXPathContextPtr ctxt;
2277 
2278     nb_tests++;
2279 #if defined(LIBXML_XPTR_ENABLED)
2280     if (xptr) {
2281 	ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
2282 	res = xmlXPtrEval(BAD_CAST str, ctxt);
2283     } else {
2284 #endif
2285 	ctxt = xmlXPathNewContext(xpathDocument);
2286 	ctxt->node = xmlDocGetRootElement(xpathDocument);
2287 	if (expr)
2288 	    res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
2289 	else {
2290 	    /* res = xmlXPathEval(BAD_CAST str, ctxt); */
2291 	    xmlXPathCompExprPtr comp;
2292 
2293 	    comp = xmlXPathCompile(BAD_CAST str);
2294 	    if (comp != NULL) {
2295 		res = xmlXPathCompiledEval(comp, ctxt);
2296 		xmlXPathFreeCompExpr(comp);
2297 	    } else
2298 		res = NULL;
2299 	}
2300 #if defined(LIBXML_XPTR_ENABLED)
2301     }
2302 #endif
2303     xmlXPathDebugDumpObject(xpathOutput, res, 0);
2304     xmlXPathFreeObject(res);
2305     xmlXPathFreeContext(ctxt);
2306 }
2307 
2308 /**
2309  * xpathExprTest:
2310  * @filename: the file to parse
2311  * @result: the file with expected result
2312  * @err: the file with error messages
2313  *
2314  * Parse a file containing XPath standalone expressions and evaluate them
2315  *
2316  * Returns 0 in case of success, an error code otherwise
2317  */
2318 static int
xpathCommonTest(const char * filename,const char * result,int xptr,int expr)2319 xpathCommonTest(const char *filename, const char *result,
2320                 int xptr, int expr) {
2321     FILE *input;
2322     char expression[5000];
2323     int len, ret = 0;
2324     char *temp;
2325 
2326     temp = resultFilename(filename, "", ".res");
2327     if (temp == NULL) {
2328         fprintf(stderr, "Out of memory\n");
2329         fatalError();
2330     }
2331     xpathOutput = fopen(temp, "wb");
2332     if (xpathOutput == NULL) {
2333 	fprintf(stderr, "failed to open output file %s\n", temp);
2334         free(temp);
2335 	return(-1);
2336     }
2337 
2338     input = fopen(filename, "rb");
2339     if (input == NULL) {
2340         xmlGenericError(xmlGenericErrorContext,
2341 		"Cannot open %s for reading\n", filename);
2342         free(temp);
2343 	return(-1);
2344     }
2345     while (fgets(expression, 4500, input) != NULL) {
2346 	len = strlen(expression);
2347 	len--;
2348 	while ((len >= 0) &&
2349 	       ((expression[len] == '\n') || (expression[len] == '\t') ||
2350 		(expression[len] == '\r') || (expression[len] == ' '))) len--;
2351 	expression[len + 1] = 0;
2352 	if (len >= 0) {
2353 	    fprintf(xpathOutput,
2354 	            "\n========================\nExpression: %s\n",
2355 		    expression) ;
2356 	    testXPath(expression, xptr, expr);
2357 	}
2358     }
2359 
2360     fclose(input);
2361     fclose(xpathOutput);
2362     if (result != NULL) {
2363 	ret = compareFiles(temp, result);
2364 	if (ret) {
2365 	    fprintf(stderr, "Result for %s failed\n", filename);
2366 	}
2367     }
2368 
2369     if (temp != NULL) {
2370         unlink(temp);
2371         free(temp);
2372     }
2373     return(ret);
2374 }
2375 
2376 /**
2377  * xpathExprTest:
2378  * @filename: the file to parse
2379  * @result: the file with expected result
2380  * @err: the file with error messages
2381  *
2382  * Parse a file containing XPath standalone expressions and evaluate them
2383  *
2384  * Returns 0 in case of success, an error code otherwise
2385  */
2386 static int
xpathExprTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)2387 xpathExprTest(const char *filename, const char *result,
2388               const char *err ATTRIBUTE_UNUSED,
2389               int options ATTRIBUTE_UNUSED) {
2390     return(xpathCommonTest(filename, result, 0, 1));
2391 }
2392 
2393 /**
2394  * xpathDocTest:
2395  * @filename: the file to parse
2396  * @result: the file with expected result
2397  * @err: the file with error messages
2398  *
2399  * Parse a file containing XPath expressions and evaluate them against
2400  * a set of corresponding documents.
2401  *
2402  * Returns 0 in case of success, an error code otherwise
2403  */
2404 static int
xpathDocTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options)2405 xpathDocTest(const char *filename,
2406              const char *resul ATTRIBUTE_UNUSED,
2407              const char *err ATTRIBUTE_UNUSED,
2408              int options) {
2409 
2410     char pattern[500];
2411     char result[500];
2412     glob_t globbuf;
2413     size_t i;
2414     int ret = 0, res;
2415 
2416     xpathDocument = xmlReadFile(filename, NULL,
2417                                 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2418     if (xpathDocument == NULL) {
2419         fprintf(stderr, "Failed to load %s\n", filename);
2420 	return(-1);
2421     }
2422 
2423     snprintf(pattern, 499, "./test/XPath/tests/%s*", baseFilename(filename));
2424     pattern[499] = 0;
2425     globbuf.gl_offs = 0;
2426     glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2427     for (i = 0;i < globbuf.gl_pathc;i++) {
2428         snprintf(result, 499, "result/XPath/tests/%s",
2429 	         baseFilename(globbuf.gl_pathv[i]));
2430 	res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
2431 	if (res != 0)
2432 	    ret = res;
2433     }
2434     globfree(&globbuf);
2435 
2436     xmlFreeDoc(xpathDocument);
2437     return(ret);
2438 }
2439 
2440 #ifdef LIBXML_XPTR_ENABLED
2441 /**
2442  * xptrDocTest:
2443  * @filename: the file to parse
2444  * @result: the file with expected result
2445  * @err: the file with error messages
2446  *
2447  * Parse a file containing XPath expressions and evaluate them against
2448  * a set of corresponding documents.
2449  *
2450  * Returns 0 in case of success, an error code otherwise
2451  */
2452 static int
xptrDocTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options)2453 xptrDocTest(const char *filename,
2454             const char *resul ATTRIBUTE_UNUSED,
2455             const char *err ATTRIBUTE_UNUSED,
2456             int options) {
2457 
2458     char pattern[500];
2459     char result[500];
2460     glob_t globbuf;
2461     size_t i;
2462     int ret = 0, res;
2463 
2464     xpathDocument = xmlReadFile(filename, NULL,
2465                                 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2466     if (xpathDocument == NULL) {
2467         fprintf(stderr, "Failed to load %s\n", filename);
2468 	return(-1);
2469     }
2470 
2471     snprintf(pattern, 499, "./test/XPath/xptr/%s*", baseFilename(filename));
2472     pattern[499] = 0;
2473     globbuf.gl_offs = 0;
2474     glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2475     for (i = 0;i < globbuf.gl_pathc;i++) {
2476         snprintf(result, 499, "result/XPath/xptr/%s",
2477 	         baseFilename(globbuf.gl_pathv[i]));
2478 	res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
2479 	if (res != 0)
2480 	    ret = res;
2481     }
2482     globfree(&globbuf);
2483 
2484     xmlFreeDoc(xpathDocument);
2485     return(ret);
2486 }
2487 #endif /* LIBXML_XPTR_ENABLED */
2488 
2489 /**
2490  * xmlidDocTest:
2491  * @filename: the file to parse
2492  * @result: the file with expected result
2493  * @err: the file with error messages
2494  *
2495  * Parse a file containing xml:id and check for errors and verify
2496  * that XPath queries will work on them as expected.
2497  *
2498  * Returns 0 in case of success, an error code otherwise
2499  */
2500 static int
xmlidDocTest(const char * filename,const char * result,const char * err,int options)2501 xmlidDocTest(const char *filename,
2502              const char *result,
2503              const char *err,
2504              int options) {
2505 
2506     int res = 0;
2507     int ret = 0;
2508     char *temp;
2509 
2510     xpathDocument = xmlReadFile(filename, NULL,
2511                                 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2512     if (xpathDocument == NULL) {
2513         fprintf(stderr, "Failed to load %s\n", filename);
2514 	return(-1);
2515     }
2516 
2517     temp = resultFilename(filename, "", ".res");
2518     if (temp == NULL) {
2519         fprintf(stderr, "Out of memory\n");
2520         fatalError();
2521     }
2522     xpathOutput = fopen(temp, "wb");
2523     if (xpathOutput == NULL) {
2524 	fprintf(stderr, "failed to open output file %s\n", temp);
2525         xmlFreeDoc(xpathDocument);
2526         free(temp);
2527 	return(-1);
2528     }
2529 
2530     testXPath("id('bar')", 0, 0);
2531 
2532     fclose(xpathOutput);
2533     if (result != NULL) {
2534 	ret = compareFiles(temp, result);
2535 	if (ret) {
2536 	    fprintf(stderr, "Result for %s failed\n", filename);
2537 	    res = 1;
2538 	}
2539     }
2540 
2541     if (temp != NULL) {
2542         unlink(temp);
2543         free(temp);
2544     }
2545     xmlFreeDoc(xpathDocument);
2546 
2547     if (err != NULL) {
2548 	ret = compareFileMem(err, testErrors, testErrorsSize);
2549 	if (ret != 0) {
2550 	    fprintf(stderr, "Error for %s failed\n", filename);
2551 	    res = 1;
2552 	}
2553     }
2554     return(res);
2555 }
2556 
2557 #endif /* LIBXML_DEBUG_ENABLED */
2558 #endif /* XPATH */
2559 /************************************************************************
2560  *									*
2561  *			URI based tests					*
2562  *									*
2563  ************************************************************************/
2564 
2565 static void
handleURI(const char * str,const char * base,FILE * o)2566 handleURI(const char *str, const char *base, FILE *o) {
2567     int ret;
2568     xmlURIPtr uri;
2569     xmlChar *res = NULL;
2570 
2571     uri = xmlCreateURI();
2572 
2573     if (base == NULL) {
2574 	ret = xmlParseURIReference(uri, str);
2575 	if (ret != 0)
2576 	    fprintf(o, "%s : error %d\n", str, ret);
2577 	else {
2578 	    xmlNormalizeURIPath(uri->path);
2579 	    xmlPrintURI(o, uri);
2580 	    fprintf(o, "\n");
2581 	}
2582     } else {
2583 	res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
2584 	if (res != NULL) {
2585 	    fprintf(o, "%s\n", (char *) res);
2586 	}
2587 	else
2588 	    fprintf(o, "::ERROR::\n");
2589     }
2590     if (res != NULL)
2591 	xmlFree(res);
2592     xmlFreeURI(uri);
2593 }
2594 
2595 /**
2596  * uriCommonTest:
2597  * @filename: the file to parse
2598  * @result: the file with expected result
2599  * @err: the file with error messages
2600  *
2601  * Parse a file containing URI and check for errors
2602  *
2603  * Returns 0 in case of success, an error code otherwise
2604  */
2605 static int
uriCommonTest(const char * filename,const char * result,const char * err,const char * base)2606 uriCommonTest(const char *filename,
2607              const char *result,
2608              const char *err,
2609              const char *base) {
2610     char *temp;
2611     FILE *o, *f;
2612     char str[1024];
2613     int res = 0, i, ret;
2614 
2615     temp = resultFilename(filename, "", ".res");
2616     if (temp == NULL) {
2617         fprintf(stderr, "Out of memory\n");
2618         fatalError();
2619     }
2620     o = fopen(temp, "wb");
2621     if (o == NULL) {
2622 	fprintf(stderr, "failed to open output file %s\n", temp);
2623         free(temp);
2624 	return(-1);
2625     }
2626     f = fopen(filename, "rb");
2627     if (f == NULL) {
2628 	fprintf(stderr, "failed to open input file %s\n", filename);
2629 	fclose(o);
2630         if (temp != NULL) {
2631             unlink(temp);
2632             free(temp);
2633         }
2634 	return(-1);
2635     }
2636 
2637     while (1) {
2638 	/*
2639 	 * read one line in string buffer.
2640 	 */
2641 	if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2642 	   break;
2643 
2644 	/*
2645 	 * remove the ending spaces
2646 	 */
2647 	i = strlen(str);
2648 	while ((i > 0) &&
2649 	       ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2650 		(str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2651 	    i--;
2652 	    str[i] = 0;
2653 	}
2654 	nb_tests++;
2655 	handleURI(str, base, o);
2656     }
2657 
2658     fclose(f);
2659     fclose(o);
2660 
2661     if (result != NULL) {
2662 	ret = compareFiles(temp, result);
2663 	if (ret) {
2664 	    fprintf(stderr, "Result for %s failed\n", filename);
2665 	    res = 1;
2666 	}
2667     }
2668     if (err != NULL) {
2669 	ret = compareFileMem(err, testErrors, testErrorsSize);
2670 	if (ret != 0) {
2671 	    fprintf(stderr, "Error for %s failed\n", filename);
2672 	    res = 1;
2673 	}
2674     }
2675 
2676     if (temp != NULL) {
2677         unlink(temp);
2678         free(temp);
2679     }
2680     return(res);
2681 }
2682 
2683 /**
2684  * uriParseTest:
2685  * @filename: the file to parse
2686  * @result: the file with expected result
2687  * @err: the file with error messages
2688  *
2689  * Parse a file containing URI and check for errors
2690  *
2691  * Returns 0 in case of success, an error code otherwise
2692  */
2693 static int
uriParseTest(const char * filename,const char * result,const char * err,int options ATTRIBUTE_UNUSED)2694 uriParseTest(const char *filename,
2695              const char *result,
2696              const char *err,
2697              int options ATTRIBUTE_UNUSED) {
2698     return(uriCommonTest(filename, result, err, NULL));
2699 }
2700 
2701 /**
2702  * uriBaseTest:
2703  * @filename: the file to parse
2704  * @result: the file with expected result
2705  * @err: the file with error messages
2706  *
2707  * Parse a file containing URI, compose them against a fixed base and
2708  * check for errors
2709  *
2710  * Returns 0 in case of success, an error code otherwise
2711  */
2712 static int
uriBaseTest(const char * filename,const char * result,const char * err,int options ATTRIBUTE_UNUSED)2713 uriBaseTest(const char *filename,
2714              const char *result,
2715              const char *err,
2716              int options ATTRIBUTE_UNUSED) {
2717     return(uriCommonTest(filename, result, err,
2718                          "http://foo.com/path/to/index.html?orig#help"));
2719 }
2720 
2721 static int urip_success = 1;
2722 static int urip_current = 0;
2723 static const char *urip_testURLs[] = {
2724     "urip://example.com/a b.html",
2725     "urip://example.com/a%20b.html",
2726     "file:///path/to/a b.html",
2727     "file:///path/to/a%20b.html",
2728     "/path/to/a b.html",
2729     "/path/to/a%20b.html",
2730     "urip://example.com/r" "\xe9" "sum" "\xe9" ".html",
2731     "urip://example.com/test?a=1&b=2%263&c=4#foo",
2732     NULL
2733 };
2734 static const char *urip_rcvsURLs[] = {
2735     /* it is an URI the strings must be escaped */
2736     "urip://example.com/a%20b.html",
2737     /* check that % escaping is not broken */
2738     "urip://example.com/a%20b.html",
2739     /* it's an URI path the strings must be escaped */
2740     "file:///path/to/a%20b.html",
2741     /* check that % escaping is not broken */
2742     "file:///path/to/a%20b.html",
2743     /* this is not an URI, this is a path, so this should not be escaped */
2744     "/path/to/a b.html",
2745     /* check that paths with % are not broken */
2746     "/path/to/a%20b.html",
2747     /* out of context the encoding can't be guessed byte by byte conversion */
2748     "urip://example.com/r%E9sum%E9.html",
2749     /* verify we don't destroy URIs especially the query part */
2750     "urip://example.com/test?a=1&b=2%263&c=4#foo",
2751     NULL
2752 };
2753 static const char *urip_res = "<list/>";
2754 static const char *urip_cur = NULL;
2755 static int urip_rlen;
2756 
2757 /**
2758  * uripMatch:
2759  * @URI: an URI to test
2760  *
2761  * Check for an urip: query
2762  *
2763  * Returns 1 if yes and 0 if another Input module should be used
2764  */
2765 static int
uripMatch(const char * URI)2766 uripMatch(const char * URI) {
2767     if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2768         return(0);
2769     /* Verify we received the escaped URL */
2770     if (strcmp(urip_rcvsURLs[urip_current], URI))
2771 	urip_success = 0;
2772     return(1);
2773 }
2774 
2775 /**
2776  * uripOpen:
2777  * @URI: an URI to test
2778  *
2779  * Return a pointer to the urip: query handler, in this example simply
2780  * the urip_current pointer...
2781  *
2782  * Returns an Input context or NULL in case or error
2783  */
2784 static void *
uripOpen(const char * URI)2785 uripOpen(const char * URI) {
2786     if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2787         return(NULL);
2788     /* Verify we received the escaped URL */
2789     if (strcmp(urip_rcvsURLs[urip_current], URI))
2790 	urip_success = 0;
2791     urip_cur = urip_res;
2792     urip_rlen = strlen(urip_res);
2793     return((void *) urip_cur);
2794 }
2795 
2796 /**
2797  * uripClose:
2798  * @context: the read context
2799  *
2800  * Close the urip: query handler
2801  *
2802  * Returns 0 or -1 in case of error
2803  */
2804 static int
uripClose(void * context)2805 uripClose(void * context) {
2806     if (context == NULL) return(-1);
2807     urip_cur = NULL;
2808     urip_rlen = 0;
2809     return(0);
2810 }
2811 
2812 /**
2813  * uripRead:
2814  * @context: the read context
2815  * @buffer: where to store data
2816  * @len: number of bytes to read
2817  *
2818  * Implement an urip: query read.
2819  *
2820  * Returns the number of bytes read or -1 in case of error
2821  */
2822 static int
uripRead(void * context,char * buffer,int len)2823 uripRead(void * context, char * buffer, int len) {
2824    const char *ptr = (const char *) context;
2825 
2826    if ((context == NULL) || (buffer == NULL) || (len < 0))
2827        return(-1);
2828 
2829    if (len > urip_rlen) len = urip_rlen;
2830    memcpy(buffer, ptr, len);
2831    urip_rlen -= len;
2832    return(len);
2833 }
2834 
2835 static int
urip_checkURL(const char * URL)2836 urip_checkURL(const char *URL) {
2837     xmlDocPtr doc;
2838 
2839     doc = xmlReadFile(URL, NULL, 0);
2840     if (doc == NULL)
2841         return(-1);
2842     xmlFreeDoc(doc);
2843     return(1);
2844 }
2845 
2846 /**
2847  * uriPathTest:
2848  * @filename: ignored
2849  * @result: ignored
2850  * @err: ignored
2851  *
2852  * Run a set of tests to check how Path and URI are handled before
2853  * being passed to the I/O layer
2854  *
2855  * Returns 0 in case of success, an error code otherwise
2856  */
2857 static int
uriPathTest(const char * filename ATTRIBUTE_UNUSED,const char * result ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)2858 uriPathTest(const char *filename ATTRIBUTE_UNUSED,
2859              const char *result ATTRIBUTE_UNUSED,
2860              const char *err ATTRIBUTE_UNUSED,
2861              int options ATTRIBUTE_UNUSED) {
2862     int parsed;
2863     int failures = 0;
2864 
2865     /*
2866      * register the new I/O handlers
2867      */
2868     if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0)
2869     {
2870         fprintf(stderr, "failed to register HTTP handler\n");
2871 	return(-1);
2872     }
2873 
2874     for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) {
2875         urip_success = 1;
2876         parsed = urip_checkURL(urip_testURLs[urip_current]);
2877 	if (urip_success != 1) {
2878 	    fprintf(stderr, "failed the URL passing test for %s",
2879 	            urip_testURLs[urip_current]);
2880 	    failures++;
2881 	} else if (parsed != 1) {
2882 	    fprintf(stderr, "failed the parsing test for %s",
2883 	            urip_testURLs[urip_current]);
2884 	    failures++;
2885 	}
2886 	nb_tests++;
2887     }
2888 
2889     xmlPopInputCallbacks();
2890     return(failures);
2891 }
2892 
2893 #ifdef LIBXML_SCHEMAS_ENABLED
2894 /************************************************************************
2895  *									*
2896  *			Schemas tests					*
2897  *									*
2898  ************************************************************************/
2899 static int
schemasOneTest(const char * sch,const char * filename,const char * result,const char * err,int options,xmlSchemaPtr schemas)2900 schemasOneTest(const char *sch,
2901                const char *filename,
2902                const char *result,
2903 	       const char *err,
2904 	       int options,
2905 	       xmlSchemaPtr schemas) {
2906     xmlDocPtr doc;
2907     xmlSchemaValidCtxtPtr ctxt;
2908     int ret = 0;
2909     int validResult = 0;
2910     char *temp;
2911     FILE *schemasOutput;
2912 
2913     doc = xmlReadFile(filename, NULL, options);
2914     if (doc == NULL) {
2915         fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
2916 	return(-1);
2917     }
2918 
2919     temp = resultFilename(result, "", ".res");
2920     if (temp == NULL) {
2921         fprintf(stderr, "Out of memory\n");
2922         fatalError();
2923     }
2924     schemasOutput = fopen(temp, "wb");
2925     if (schemasOutput == NULL) {
2926 	fprintf(stderr, "failed to open output file %s\n", temp);
2927 	xmlFreeDoc(doc);
2928         free(temp);
2929 	return(-1);
2930     }
2931 
2932     ctxt = xmlSchemaNewValidCtxt(schemas);
2933     xmlSchemaSetValidErrors(ctxt,
2934          (xmlSchemaValidityErrorFunc) testErrorHandler,
2935          (xmlSchemaValidityWarningFunc) testErrorHandler,
2936 	 ctxt);
2937     validResult = xmlSchemaValidateDoc(ctxt, doc);
2938     if (validResult == 0) {
2939 	fprintf(schemasOutput, "%s validates\n", filename);
2940     } else if (validResult > 0) {
2941 	fprintf(schemasOutput, "%s fails to validate\n", filename);
2942     } else {
2943 	fprintf(schemasOutput, "%s validation generated an internal error\n",
2944 	       filename);
2945     }
2946     fclose(schemasOutput);
2947     if (result) {
2948 	if (compareFiles(temp, result)) {
2949 	    fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
2950 	    ret = 1;
2951 	}
2952     }
2953     if (temp != NULL) {
2954         unlink(temp);
2955         free(temp);
2956     }
2957 
2958     if ((validResult != 0) && (err != NULL)) {
2959 	if (compareFileMem(err, testErrors, testErrorsSize)) {
2960 	    fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
2961 	    ret = 1;
2962 	}
2963     }
2964 
2965     xmlSchemaFreeValidCtxt(ctxt);
2966     xmlFreeDoc(doc);
2967     return(ret);
2968 }
2969 /**
2970  * schemasTest:
2971  * @filename: the schemas file
2972  * @result: the file with expected result
2973  * @err: the file with error messages
2974  *
2975  * Parse a file containing URI, compose them against a fixed base and
2976  * check for errors
2977  *
2978  * Returns 0 in case of success, an error code otherwise
2979  */
2980 static int
schemasTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * errr ATTRIBUTE_UNUSED,int options)2981 schemasTest(const char *filename,
2982             const char *resul ATTRIBUTE_UNUSED,
2983             const char *errr ATTRIBUTE_UNUSED,
2984             int options) {
2985     const char *base = baseFilename(filename);
2986     const char *base2;
2987     const char *instance;
2988     xmlSchemaParserCtxtPtr ctxt;
2989     xmlSchemaPtr schemas;
2990     int res = 0, len, ret;
2991     char pattern[500];
2992     char prefix[500];
2993     char result[500];
2994     char err[500];
2995     glob_t globbuf;
2996     size_t i;
2997     char count = 0;
2998 
2999     /* first compile the schemas if possible */
3000     ctxt = xmlSchemaNewParserCtxt(filename);
3001     xmlSchemaSetParserErrors(ctxt,
3002          (xmlSchemaValidityErrorFunc) testErrorHandler,
3003          (xmlSchemaValidityWarningFunc) testErrorHandler,
3004 	 ctxt);
3005     schemas = xmlSchemaParse(ctxt);
3006     xmlSchemaFreeParserCtxt(ctxt);
3007 
3008     /*
3009      * most of the mess is about the output filenames generated by the Makefile
3010      */
3011     len = strlen(base);
3012     if ((len > 499) || (len < 5)) {
3013         xmlSchemaFree(schemas);
3014 	return(-1);
3015     }
3016     len -= 4; /* remove trailing .xsd */
3017     if (base[len - 2] == '_') {
3018         len -= 2; /* remove subtest number */
3019     }
3020     if (base[len - 2] == '_') {
3021         len -= 2; /* remove subtest number */
3022     }
3023     memcpy(prefix, base, len);
3024     prefix[len] = 0;
3025 
3026     snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix);
3027     pattern[499] = 0;
3028 
3029     if (base[len] == '_') {
3030         len += 2;
3031 	memcpy(prefix, base, len);
3032 	prefix[len] = 0;
3033     }
3034 
3035     globbuf.gl_offs = 0;
3036     glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3037     for (i = 0;i < globbuf.gl_pathc;i++) {
3038         testErrorsSize = 0;
3039 	testErrors[0] = 0;
3040         instance = globbuf.gl_pathv[i];
3041 	base2 = baseFilename(instance);
3042 	len = strlen(base2);
3043 	if ((len > 6) && (base2[len - 6] == '_')) {
3044 	    count = base2[len - 5];
3045 	    snprintf(result, 499, "result/schemas/%s_%c",
3046 		     prefix, count);
3047 	    result[499] = 0;
3048 	    snprintf(err, 499, "result/schemas/%s_%c.err",
3049 		     prefix, count);
3050 	    err[499] = 0;
3051 	} else {
3052 	    fprintf(stderr, "don't know how to process %s\n", instance);
3053 	    continue;
3054 	}
3055 	if (schemas == NULL) {
3056 	} else {
3057 	    nb_tests++;
3058 	    ret = schemasOneTest(filename, instance, result, err,
3059 	                         options, schemas);
3060 	    if (ret != 0)
3061 		res = ret;
3062 	}
3063     }
3064     globfree(&globbuf);
3065     xmlSchemaFree(schemas);
3066 
3067     return(res);
3068 }
3069 
3070 /************************************************************************
3071  *									*
3072  *			Schemas tests					*
3073  *									*
3074  ************************************************************************/
3075 static int
rngOneTest(const char * sch,const char * filename,const char * result,const char * err,int options,xmlRelaxNGPtr schemas)3076 rngOneTest(const char *sch,
3077                const char *filename,
3078                const char *result,
3079 	       const char *err,
3080 	       int options,
3081 	       xmlRelaxNGPtr schemas) {
3082     xmlDocPtr doc;
3083     xmlRelaxNGValidCtxtPtr ctxt;
3084     int ret = 0;
3085     char *temp;
3086     FILE *schemasOutput;
3087 
3088     doc = xmlReadFile(filename, NULL, options);
3089     if (doc == NULL) {
3090         fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3091 	return(-1);
3092     }
3093 
3094     temp = resultFilename(result, "", ".res");
3095     if (temp == NULL) {
3096         fprintf(stderr, "Out of memory\n");
3097         fatalError();
3098     }
3099     schemasOutput = fopen(temp, "wb");
3100     if (schemasOutput == NULL) {
3101 	fprintf(stderr, "failed to open output file %s\n", temp);
3102 	xmlFreeDoc(doc);
3103         free(temp);
3104 	return(-1);
3105     }
3106 
3107     ctxt = xmlRelaxNGNewValidCtxt(schemas);
3108     xmlRelaxNGSetValidErrors(ctxt,
3109          (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3110          (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3111 	 ctxt);
3112     ret = xmlRelaxNGValidateDoc(ctxt, doc);
3113     if (ret == 0) {
3114 	testErrorHandler(NULL, "%s validates\n", filename);
3115     } else if (ret > 0) {
3116 	testErrorHandler(NULL, "%s fails to validate\n", filename);
3117     } else {
3118 	testErrorHandler(NULL, "%s validation generated an internal error\n",
3119 	       filename);
3120     }
3121     fclose(schemasOutput);
3122     ret = 0;
3123     if (result) {
3124 	if (compareFiles(temp, result)) {
3125 	    fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3126 	    ret = 1;
3127 	}
3128     }
3129     if (temp != NULL) {
3130         unlink(temp);
3131         free(temp);
3132     }
3133 
3134     if (err != NULL) {
3135 	if (compareFileMem(err, testErrors, testErrorsSize)) {
3136 	    fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3137 	    ret = 1;
3138 	    printf("%s", testErrors);
3139 	}
3140     }
3141 
3142 
3143     xmlRelaxNGFreeValidCtxt(ctxt);
3144     xmlFreeDoc(doc);
3145     return(ret);
3146 }
3147 /**
3148  * rngTest:
3149  * @filename: the schemas file
3150  * @result: the file with expected result
3151  * @err: the file with error messages
3152  *
3153  * Parse an RNG schemas and then apply it to the related .xml
3154  *
3155  * Returns 0 in case of success, an error code otherwise
3156  */
3157 static int
rngTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * errr ATTRIBUTE_UNUSED,int options)3158 rngTest(const char *filename,
3159             const char *resul ATTRIBUTE_UNUSED,
3160             const char *errr ATTRIBUTE_UNUSED,
3161             int options) {
3162     const char *base = baseFilename(filename);
3163     const char *base2;
3164     const char *instance;
3165     xmlRelaxNGParserCtxtPtr ctxt;
3166     xmlRelaxNGPtr schemas;
3167     int res = 0, len, ret = 0;
3168     char pattern[500];
3169     char prefix[500];
3170     char result[500];
3171     char err[500];
3172     glob_t globbuf;
3173     size_t i;
3174     char count = 0;
3175 
3176     /* first compile the schemas if possible */
3177     ctxt = xmlRelaxNGNewParserCtxt(filename);
3178     xmlRelaxNGSetParserErrors(ctxt,
3179          (xmlRelaxNGValidityErrorFunc) testErrorHandler,
3180          (xmlRelaxNGValidityWarningFunc) testErrorHandler,
3181 	 ctxt);
3182     schemas = xmlRelaxNGParse(ctxt);
3183     xmlRelaxNGFreeParserCtxt(ctxt);
3184 
3185     /*
3186      * most of the mess is about the output filenames generated by the Makefile
3187      */
3188     len = strlen(base);
3189     if ((len > 499) || (len < 5)) {
3190         xmlRelaxNGFree(schemas);
3191 	return(-1);
3192     }
3193     len -= 4; /* remove trailing .rng */
3194     memcpy(prefix, base, len);
3195     prefix[len] = 0;
3196 
3197     snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3198     pattern[499] = 0;
3199 
3200     globbuf.gl_offs = 0;
3201     glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3202     for (i = 0;i < globbuf.gl_pathc;i++) {
3203         testErrorsSize = 0;
3204 	testErrors[0] = 0;
3205         instance = globbuf.gl_pathv[i];
3206 	base2 = baseFilename(instance);
3207 	len = strlen(base2);
3208 	if ((len > 6) && (base2[len - 6] == '_')) {
3209 	    count = base2[len - 5];
3210 	    snprintf(result, 499, "result/relaxng/%s_%c",
3211 		     prefix, count);
3212 	    result[499] = 0;
3213 	    snprintf(err, 499, "result/relaxng/%s_%c.err",
3214 		     prefix, count);
3215 	    err[499] = 0;
3216 	} else {
3217 	    fprintf(stderr, "don't know how to process %s\n", instance);
3218 	    continue;
3219 	}
3220 	if (schemas == NULL) {
3221 	} else {
3222 	    nb_tests++;
3223 	    ret = rngOneTest(filename, instance, result, err,
3224 	                         options, schemas);
3225 	    if (res != 0)
3226 		ret = res;
3227 	}
3228     }
3229     globfree(&globbuf);
3230     xmlRelaxNGFree(schemas);
3231 
3232     return(ret);
3233 }
3234 
3235 #ifdef LIBXML_READER_ENABLED
3236 /**
3237  * rngStreamTest:
3238  * @filename: the schemas file
3239  * @result: the file with expected result
3240  * @err: the file with error messages
3241  *
3242  * Parse a set of files with streaming, applying an RNG schemas
3243  *
3244  * Returns 0 in case of success, an error code otherwise
3245  */
3246 static int
rngStreamTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * errr ATTRIBUTE_UNUSED,int options)3247 rngStreamTest(const char *filename,
3248             const char *resul ATTRIBUTE_UNUSED,
3249             const char *errr ATTRIBUTE_UNUSED,
3250             int options) {
3251     const char *base = baseFilename(filename);
3252     const char *base2;
3253     const char *instance;
3254     int res = 0, len, ret;
3255     char pattern[500];
3256     char prefix[500];
3257     char result[500];
3258     char err[500];
3259     glob_t globbuf;
3260     size_t i;
3261     char count = 0;
3262     xmlTextReaderPtr reader;
3263     int disable_err = 0;
3264 
3265     /*
3266      * most of the mess is about the output filenames generated by the Makefile
3267      */
3268     len = strlen(base);
3269     if ((len > 499) || (len < 5)) {
3270 	fprintf(stderr, "len(base) == %d !\n", len);
3271 	return(-1);
3272     }
3273     len -= 4; /* remove trailing .rng */
3274     memcpy(prefix, base, len);
3275     prefix[len] = 0;
3276 
3277     /*
3278      * strictly unifying the error messages is nearly impossible this
3279      * hack is also done in the Makefile
3280      */
3281     if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
3282         (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) ||
3283         (!strcmp(prefix, "tutor8_2")))
3284 	disable_err = 1;
3285 
3286     snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix);
3287     pattern[499] = 0;
3288 
3289     globbuf.gl_offs = 0;
3290     glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3291     for (i = 0;i < globbuf.gl_pathc;i++) {
3292         testErrorsSize = 0;
3293 	testErrors[0] = 0;
3294         instance = globbuf.gl_pathv[i];
3295 	base2 = baseFilename(instance);
3296 	len = strlen(base2);
3297 	if ((len > 6) && (base2[len - 6] == '_')) {
3298 	    count = base2[len - 5];
3299 	    snprintf(result, 499, "result/relaxng/%s_%c",
3300 		     prefix, count);
3301 	    result[499] = 0;
3302 	    snprintf(err, 499, "result/relaxng/%s_%c.err",
3303 		     prefix, count);
3304 	    err[499] = 0;
3305 	} else {
3306 	    fprintf(stderr, "don't know how to process %s\n", instance);
3307 	    continue;
3308 	}
3309 	reader = xmlReaderForFile(instance, NULL, options);
3310 	if (reader == NULL) {
3311 	    fprintf(stderr, "Failed to build reder for %s\n", instance);
3312 	}
3313 	if (disable_err == 1)
3314 	    ret = streamProcessTest(instance, result, NULL, reader, filename,
3315 	                            options);
3316 	else
3317 	    ret = streamProcessTest(instance, result, err, reader, filename,
3318 	                            options);
3319 	xmlFreeTextReader(reader);
3320 	if (ret != 0) {
3321 	    fprintf(stderr, "instance %s failed\n", instance);
3322 	    res = ret;
3323 	}
3324     }
3325     globfree(&globbuf);
3326 
3327     return(res);
3328 }
3329 #endif /* READER */
3330 
3331 #endif
3332 
3333 #ifdef LIBXML_PATTERN_ENABLED
3334 #ifdef LIBXML_READER_ENABLED
3335 /************************************************************************
3336  *									*
3337  *			Patterns tests					*
3338  *									*
3339  ************************************************************************/
patternNode(FILE * out,xmlTextReaderPtr reader,const char * pattern,xmlPatternPtr patternc,xmlStreamCtxtPtr patstream)3340 static void patternNode(FILE *out, xmlTextReaderPtr reader,
3341                         const char *pattern, xmlPatternPtr patternc,
3342 			xmlStreamCtxtPtr patstream) {
3343     xmlChar *path = NULL;
3344     int match = -1;
3345     int type, empty;
3346 
3347     type = xmlTextReaderNodeType(reader);
3348     empty = xmlTextReaderIsEmptyElement(reader);
3349 
3350     if (type == XML_READER_TYPE_ELEMENT) {
3351 	/* do the check only on element start */
3352 	match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3353 
3354 	if (match) {
3355 	    path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3356 	    fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3357 	}
3358     }
3359     if (patstream != NULL) {
3360 	int ret;
3361 
3362 	if (type == XML_READER_TYPE_ELEMENT) {
3363 	    ret = xmlStreamPush(patstream,
3364 				xmlTextReaderConstLocalName(reader),
3365 				xmlTextReaderConstNamespaceUri(reader));
3366 	    if (ret < 0) {
3367 		fprintf(out, "xmlStreamPush() failure\n");
3368 		xmlFreeStreamCtxt(patstream);
3369 		patstream = NULL;
3370 	    } else if (ret != match) {
3371 		if (path == NULL) {
3372 		    path = xmlGetNodePath(
3373 				   xmlTextReaderCurrentNode(reader));
3374 		}
3375 		fprintf(out,
3376 			"xmlPatternMatch and xmlStreamPush disagree\n");
3377 		fprintf(out,
3378 			"  pattern %s node %s\n",
3379 			pattern, path);
3380 	    }
3381 
3382 
3383 	}
3384 	if ((type == XML_READER_TYPE_END_ELEMENT) ||
3385 	    ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3386 	    ret = xmlStreamPop(patstream);
3387 	    if (ret < 0) {
3388 		fprintf(out, "xmlStreamPop() failure\n");
3389 		xmlFreeStreamCtxt(patstream);
3390 		patstream = NULL;
3391 	    }
3392 	}
3393     }
3394     if (path != NULL)
3395 	xmlFree(path);
3396 }
3397 
3398 /**
3399  * patternTest:
3400  * @filename: the schemas file
3401  * @result: the file with expected result
3402  * @err: the file with error messages
3403  *
3404  * Parse a set of files with streaming, applying an RNG schemas
3405  *
3406  * Returns 0 in case of success, an error code otherwise
3407  */
3408 static int
patternTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options)3409 patternTest(const char *filename,
3410             const char *resul ATTRIBUTE_UNUSED,
3411             const char *err ATTRIBUTE_UNUSED,
3412             int options) {
3413     xmlPatternPtr patternc = NULL;
3414     xmlStreamCtxtPtr patstream = NULL;
3415     FILE *o, *f;
3416     char str[1024];
3417     char xml[500];
3418     char result[500];
3419     int len, i;
3420     int ret = 0, res;
3421     char *temp;
3422     xmlTextReaderPtr reader;
3423     xmlDocPtr doc;
3424 
3425     len = strlen(filename);
3426     len -= 4;
3427     memcpy(xml, filename, len);
3428     xml[len] = 0;
3429     snprintf(result, 499, "result/pattern/%s", baseFilename(xml));
3430     result[499] = 0;
3431     memcpy(xml + len, ".xml", 5);
3432 
3433     if (!checkTestFile(xml)) {
3434 	fprintf(stderr, "Missing xml file %s\n", xml);
3435 	return(-1);
3436     }
3437     if (!checkTestFile(result)) {
3438 	fprintf(stderr, "Missing result file %s\n", result);
3439 	return(-1);
3440     }
3441     f = fopen(filename, "rb");
3442     if (f == NULL) {
3443         fprintf(stderr, "Failed to open %s\n", filename);
3444 	return(-1);
3445     }
3446     temp = resultFilename(filename, "", ".res");
3447     if (temp == NULL) {
3448         fprintf(stderr, "Out of memory\n");
3449         fatalError();
3450     }
3451     o = fopen(temp, "wb");
3452     if (o == NULL) {
3453 	fprintf(stderr, "failed to open output file %s\n", temp);
3454 	fclose(f);
3455         free(temp);
3456 	return(-1);
3457     }
3458     while (1) {
3459 	/*
3460 	 * read one line in string buffer.
3461 	 */
3462 	if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3463 	   break;
3464 
3465 	/*
3466 	 * remove the ending spaces
3467 	 */
3468 	i = strlen(str);
3469 	while ((i > 0) &&
3470 	       ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3471 		(str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3472 	    i--;
3473 	    str[i] = 0;
3474 	}
3475 	doc = xmlReadFile(xml, NULL, options);
3476 	if (doc == NULL) {
3477 	    fprintf(stderr, "Failed to parse %s\n", xml);
3478 	    ret = 1;
3479 	} else {
3480 	    xmlNodePtr root;
3481 	    const xmlChar *namespaces[22];
3482 	    int j;
3483 	    xmlNsPtr ns;
3484 
3485 	    root = xmlDocGetRootElement(doc);
3486 	    for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3487 		namespaces[j++] = ns->href;
3488 		namespaces[j++] = ns->prefix;
3489 	    }
3490 	    namespaces[j++] = NULL;
3491 	    namespaces[j] = NULL;
3492 
3493 	    patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3494 					 0, &namespaces[0]);
3495 	    if (patternc == NULL) {
3496 		testErrorHandler(NULL,
3497 			"Pattern %s failed to compile\n", str);
3498 		xmlFreeDoc(doc);
3499 		ret = 1;
3500 		continue;
3501 	    }
3502 	    patstream = xmlPatternGetStreamCtxt(patternc);
3503 	    if (patstream != NULL) {
3504 		ret = xmlStreamPush(patstream, NULL, NULL);
3505 		if (ret < 0) {
3506 		    fprintf(stderr, "xmlStreamPush() failure\n");
3507 		    xmlFreeStreamCtxt(patstream);
3508 		    patstream = NULL;
3509 		}
3510 	    }
3511 	    nb_tests++;
3512 
3513 	    reader = xmlReaderWalker(doc);
3514 	    res = xmlTextReaderRead(reader);
3515 	    while (res == 1) {
3516 		patternNode(o, reader, str, patternc, patstream);
3517 		res = xmlTextReaderRead(reader);
3518 	    }
3519 	    if (res != 0) {
3520 		fprintf(o, "%s : failed to parse\n", filename);
3521 	    }
3522 	    xmlFreeTextReader(reader);
3523 	    xmlFreeDoc(doc);
3524 	    xmlFreeStreamCtxt(patstream);
3525 	    patstream = NULL;
3526 	    xmlFreePattern(patternc);
3527 
3528 	}
3529     }
3530 
3531     fclose(f);
3532     fclose(o);
3533 
3534     ret = compareFiles(temp, result);
3535     if (ret) {
3536 	fprintf(stderr, "Result for %s failed\n", filename);
3537 	ret = 1;
3538     }
3539     if (temp != NULL) {
3540         unlink(temp);
3541         free(temp);
3542     }
3543     return(ret);
3544 }
3545 #endif /* READER */
3546 #endif /* PATTERN */
3547 #ifdef LIBXML_C14N_ENABLED
3548 /************************************************************************
3549  *									*
3550  *			Canonicalization tests				*
3551  *									*
3552  ************************************************************************/
3553 static xmlXPathObjectPtr
load_xpath_expr(xmlDocPtr parent_doc,const char * filename)3554 load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
3555     xmlXPathObjectPtr xpath;
3556     xmlDocPtr doc;
3557     xmlChar *expr;
3558     xmlXPathContextPtr ctx;
3559     xmlNodePtr node;
3560     xmlNsPtr ns;
3561 
3562     /*
3563      * load XPath expr as a file
3564      */
3565     xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3566     xmlSubstituteEntitiesDefault(1);
3567 
3568     doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
3569     if (doc == NULL) {
3570 	fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3571 	return(NULL);
3572     }
3573 
3574     /*
3575      * Check the document is of the right kind
3576      */
3577     if(xmlDocGetRootElement(doc) == NULL) {
3578         fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3579 	xmlFreeDoc(doc);
3580 	return(NULL);
3581     }
3582 
3583     node = doc->children;
3584     while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3585 	node = node->next;
3586     }
3587 
3588     if(node == NULL) {
3589         fprintf(stderr,"Error: XPath element expected in the file  \"%s\"\n", filename);
3590 	xmlFreeDoc(doc);
3591 	return(NULL);
3592     }
3593 
3594     expr = xmlNodeGetContent(node);
3595     if(expr == NULL) {
3596         fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3597 	xmlFreeDoc(doc);
3598 	return(NULL);
3599     }
3600 
3601     ctx = xmlXPathNewContext(parent_doc);
3602     if(ctx == NULL) {
3603         fprintf(stderr,"Error: unable to create new context\n");
3604         xmlFree(expr);
3605         xmlFreeDoc(doc);
3606         return(NULL);
3607     }
3608 
3609     /*
3610      * Register namespaces
3611      */
3612     ns = node->nsDef;
3613     while(ns != NULL) {
3614 	if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3615 	    fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href);
3616     xmlFree(expr);
3617 	    xmlXPathFreeContext(ctx);
3618 	    xmlFreeDoc(doc);
3619 	    return(NULL);
3620 	}
3621 	ns = ns->next;
3622     }
3623 
3624     /*
3625      * Evaluate xpath
3626      */
3627     xpath = xmlXPathEvalExpression(expr, ctx);
3628     if(xpath == NULL) {
3629         fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3630 xmlFree(expr);
3631         xmlXPathFreeContext(ctx);
3632         xmlFreeDoc(doc);
3633         return(NULL);
3634     }
3635 
3636     /* print_xpath_nodes(xpath->nodesetval); */
3637 
3638     xmlFree(expr);
3639     xmlXPathFreeContext(ctx);
3640     xmlFreeDoc(doc);
3641     return(xpath);
3642 }
3643 
3644 /*
3645  * Macro used to grow the current buffer.
3646  */
3647 #define xxx_growBufferReentrant() {						\
3648     buffer_size *= 2;							\
3649     buffer = (xmlChar **)						\
3650 	xmlRealloc(buffer, buffer_size * sizeof(xmlChar*));	\
3651     if (buffer == NULL) {						\
3652 	perror("realloc failed");					\
3653 	return(NULL);							\
3654     }									\
3655 }
3656 
3657 static xmlChar **
parse_list(xmlChar * str)3658 parse_list(xmlChar *str) {
3659     xmlChar **buffer;
3660     xmlChar **out = NULL;
3661     int buffer_size = 0;
3662     int len;
3663 
3664     if(str == NULL) {
3665 	return(NULL);
3666     }
3667 
3668     len = xmlStrlen(str);
3669     if((str[0] == '\'') && (str[len - 1] == '\'')) {
3670 	str[len - 1] = '\0';
3671 	str++;
3672     }
3673     /*
3674      * allocate an translation buffer.
3675      */
3676     buffer_size = 1000;
3677     buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3678     if (buffer == NULL) {
3679 	perror("malloc failed");
3680 	return(NULL);
3681     }
3682     out = buffer;
3683 
3684     while(*str != '\0') {
3685 	if (out - buffer > buffer_size - 10) {
3686 	    int indx = out - buffer;
3687 
3688 	    xxx_growBufferReentrant();
3689 	    out = &buffer[indx];
3690 	}
3691 	(*out++) = str;
3692 	while(*str != ',' && *str != '\0') ++str;
3693 	if(*str == ',') *(str++) = '\0';
3694     }
3695     (*out) = NULL;
3696     return buffer;
3697 }
3698 
3699 static int
c14nRunTest(const char * xml_filename,int with_comments,int mode,const char * xpath_filename,const char * ns_filename,const char * result_file)3700 c14nRunTest(const char* xml_filename, int with_comments, int mode,
3701 	    const char* xpath_filename, const char *ns_filename,
3702 	    const char* result_file) {
3703     xmlDocPtr doc;
3704     xmlXPathObjectPtr xpath = NULL;
3705     xmlChar *result = NULL;
3706     int ret;
3707     xmlChar **inclusive_namespaces = NULL;
3708     const char *nslist = NULL;
3709     int nssize;
3710 
3711 
3712     /*
3713      * build an XML tree from a the file; we need to add default
3714      * attributes and resolve all character and entities references
3715      */
3716     xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3717     xmlSubstituteEntitiesDefault(1);
3718 
3719     doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
3720     if (doc == NULL) {
3721 	fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3722 	return(-1);
3723     }
3724 
3725     /*
3726      * Check the document is of the right kind
3727      */
3728     if(xmlDocGetRootElement(doc) == NULL) {
3729         fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3730 	xmlFreeDoc(doc);
3731 	return(-1);
3732     }
3733 
3734     /*
3735      * load xpath file if specified
3736      */
3737     if(xpath_filename) {
3738 	xpath = load_xpath_expr(doc, xpath_filename);
3739 	if(xpath == NULL) {
3740 	    fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3741 	    xmlFreeDoc(doc);
3742 	    return(-1);
3743 	}
3744     }
3745 
3746     if (ns_filename != NULL) {
3747         if (loadMem(ns_filename, &nslist, &nssize)) {
3748 	    fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3749 	    if(xpath != NULL) xmlXPathFreeObject(xpath);
3750 	    xmlFreeDoc(doc);
3751 	    return(-1);
3752 	}
3753         inclusive_namespaces = parse_list((xmlChar *) nslist);
3754     }
3755 
3756     /*
3757      * Canonical form
3758      */
3759     /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
3760     ret = xmlC14NDocDumpMemory(doc,
3761 	    (xpath) ? xpath->nodesetval : NULL,
3762 	    mode, inclusive_namespaces,
3763 	    with_comments, &result);
3764     if (ret >= 0) {
3765 	if(result != NULL) {
3766 	    if (compareFileMem(result_file, (const char *) result, ret)) {
3767 		fprintf(stderr, "Result mismatch for %s\n", xml_filename);
3768 		fprintf(stderr, "RESULT:\n%s\n", (const char*)result);
3769 	        ret = -1;
3770 	    }
3771 	}
3772     } else {
3773 	fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3774 	ret = -1;
3775     }
3776 
3777     /*
3778      * Cleanup
3779      */
3780     if (result != NULL) xmlFree(result);
3781     if(xpath != NULL) xmlXPathFreeObject(xpath);
3782     if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3783     if (nslist != NULL) free((char *) nslist);
3784     xmlFreeDoc(doc);
3785 
3786     return(ret);
3787 }
3788 
3789 static int
c14nCommonTest(const char * filename,int with_comments,int mode,const char * subdir)3790 c14nCommonTest(const char *filename, int with_comments, int mode,
3791                const char *subdir) {
3792     char buf[500];
3793     char prefix[500];
3794     const char *base;
3795     int len;
3796     char *result = NULL;
3797     char *xpath = NULL;
3798     char *ns = NULL;
3799     int ret = 0;
3800 
3801     base = baseFilename(filename);
3802     len = strlen(base);
3803     len -= 4;
3804     memcpy(prefix, base, len);
3805     prefix[len] = 0;
3806 
3807     snprintf(buf, 499, "result/c14n/%s/%s", subdir,prefix);
3808     if (!checkTestFile(buf)) {
3809         fprintf(stderr, "Missing result file %s", buf);
3810 	return(-1);
3811     }
3812     result = strdup(buf);
3813     snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir,prefix);
3814     if (checkTestFile(buf)) {
3815 	xpath = strdup(buf);
3816     }
3817     snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir,prefix);
3818     if (checkTestFile(buf)) {
3819 	ns = strdup(buf);
3820     }
3821 
3822     nb_tests++;
3823     if (c14nRunTest(filename, with_comments, mode,
3824                     xpath, ns, result) < 0)
3825         ret = 1;
3826 
3827     if (result != NULL) free(result);
3828     if (xpath != NULL) free(xpath);
3829     if (ns != NULL) free(ns);
3830     return(ret);
3831 }
3832 
3833 static int
c14nWithCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)3834 c14nWithCommentTest(const char *filename,
3835                     const char *resul ATTRIBUTE_UNUSED,
3836 		    const char *err ATTRIBUTE_UNUSED,
3837 		    int options ATTRIBUTE_UNUSED) {
3838     return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments"));
3839 }
3840 static int
c14nWithoutCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)3841 c14nWithoutCommentTest(const char *filename,
3842                     const char *resul ATTRIBUTE_UNUSED,
3843 		    const char *err ATTRIBUTE_UNUSED,
3844 		    int options ATTRIBUTE_UNUSED) {
3845     return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments"));
3846 }
3847 static int
c14nExcWithoutCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)3848 c14nExcWithoutCommentTest(const char *filename,
3849                     const char *resul ATTRIBUTE_UNUSED,
3850 		    const char *err ATTRIBUTE_UNUSED,
3851 		    int options ATTRIBUTE_UNUSED) {
3852     return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments"));
3853 }
3854 static int
c14n11WithoutCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)3855 c14n11WithoutCommentTest(const char *filename,
3856                     const char *resul ATTRIBUTE_UNUSED,
3857 		    const char *err ATTRIBUTE_UNUSED,
3858 		    int options ATTRIBUTE_UNUSED) {
3859     return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments"));
3860 }
3861 #endif
3862 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined (LIBXML_SAX1_ENABLED)
3863 /************************************************************************
3864  *									*
3865  *			Catalog and threads test			*
3866  *									*
3867  ************************************************************************/
3868 
3869 /*
3870  * mostly a cut and paste from testThreads.c
3871  */
3872 #define	MAX_ARGC	20
3873 
3874 static const char *catalog = "test/threads/complex.xml";
3875 static const char *testfiles[] = {
3876     "test/threads/abc.xml",
3877     "test/threads/acb.xml",
3878     "test/threads/bac.xml",
3879     "test/threads/bca.xml",
3880     "test/threads/cab.xml",
3881     "test/threads/cba.xml",
3882     "test/threads/invalid.xml",
3883 };
3884 
3885 static const char *Okay = "OK";
3886 static const char *Failed = "Failed";
3887 
3888 #ifndef xmlDoValidityCheckingDefaultValue
3889 #error xmlDoValidityCheckingDefaultValue is not a macro
3890 #endif
3891 #ifndef xmlGenericErrorContext
3892 #error xmlGenericErrorContext is not a macro
3893 #endif
3894 
3895 static void *
thread_specific_data(void * private_data)3896 thread_specific_data(void *private_data)
3897 {
3898     xmlDocPtr myDoc;
3899     const char *filename = (const char *) private_data;
3900     int okay = 1;
3901 
3902     if (!strcmp(filename, "test/threads/invalid.xml")) {
3903         xmlDoValidityCheckingDefaultValue = 0;
3904         xmlGenericErrorContext = stdout;
3905     } else {
3906         xmlDoValidityCheckingDefaultValue = 1;
3907         xmlGenericErrorContext = stderr;
3908     }
3909     myDoc = xmlParseFile(filename);
3910     if (myDoc) {
3911         xmlFreeDoc(myDoc);
3912     } else {
3913         printf("parse failed\n");
3914         okay = 0;
3915     }
3916     if (!strcmp(filename, "test/threads/invalid.xml")) {
3917         if (xmlDoValidityCheckingDefaultValue != 0) {
3918             printf("ValidityCheckingDefaultValue override failed\n");
3919             okay = 0;
3920         }
3921         if (xmlGenericErrorContext != stdout) {
3922             printf("xmlGenericErrorContext override failed\n");
3923             okay = 0;
3924         }
3925     } else {
3926         if (xmlDoValidityCheckingDefaultValue != 1) {
3927             printf("ValidityCheckingDefaultValue override failed\n");
3928             okay = 0;
3929         }
3930         if (xmlGenericErrorContext != stderr) {
3931             printf("xmlGenericErrorContext override failed\n");
3932             okay = 0;
3933         }
3934     }
3935     if (okay == 0)
3936         return ((void *) Failed);
3937     return ((void *) Okay);
3938 }
3939 
3940 #if defined WIN32
3941 #include <windows.h>
3942 #include <string.h>
3943 
3944 #define TEST_REPEAT_COUNT 500
3945 
3946 static HANDLE tid[MAX_ARGC];
3947 
3948 static DWORD WINAPI
win32_thread_specific_data(void * private_data)3949 win32_thread_specific_data(void *private_data)
3950 {
3951     return((DWORD) thread_specific_data(private_data));
3952 }
3953 
3954 static int
testThread(void)3955 testThread(void)
3956 {
3957     unsigned int i, repeat;
3958     unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
3959     DWORD results[MAX_ARGC];
3960     BOOL ret;
3961     int res = 0;
3962 
3963     xmlInitParser();
3964     for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
3965         xmlLoadCatalog(catalog);
3966         nb_tests++;
3967 
3968         for (i = 0; i < num_threads; i++) {
3969             results[i] = 0;
3970             tid[i] = (HANDLE) - 1;
3971         }
3972 
3973         for (i = 0; i < num_threads; i++) {
3974             DWORD useless;
3975 
3976             tid[i] = CreateThread(NULL, 0,
3977                                   win32_thread_specific_data,
3978 				  (void *) testfiles[i], 0,
3979                                   &useless);
3980             if (tid[i] == NULL) {
3981                 fprintf(stderr, "CreateThread failed\n");
3982                 return(1);
3983             }
3984         }
3985 
3986         if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
3987             WAIT_FAILED) {
3988             fprintf(stderr, "WaitForMultipleObjects failed\n");
3989 	    return(1);
3990 	}
3991 
3992         for (i = 0; i < num_threads; i++) {
3993             ret = GetExitCodeThread(tid[i], &results[i]);
3994             if (ret == 0) {
3995                 fprintf(stderr, "GetExitCodeThread failed\n");
3996                 return(1);
3997             }
3998             CloseHandle(tid[i]);
3999         }
4000 
4001         xmlCatalogCleanup();
4002         for (i = 0; i < num_threads; i++) {
4003             if (results[i] != (DWORD) Okay) {
4004                 fprintf(stderr, "Thread %d handling %s failed\n",
4005 		        i, testfiles[i]);
4006 	        res = 1;
4007 	    }
4008         }
4009     }
4010 
4011     return (res);
4012 }
4013 
4014 #elif defined __BEOS__
4015 #include <OS.h>
4016 
4017 static thread_id tid[MAX_ARGC];
4018 
4019 static int
testThread(void)4020 testThread(void)
4021 {
4022     unsigned int i, repeat;
4023     unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4024     void *results[MAX_ARGC];
4025     status_t ret;
4026     int res = 0;
4027 
4028     xmlInitParser();
4029     for (repeat = 0; repeat < 500; repeat++) {
4030         xmlLoadCatalog(catalog);
4031         for (i = 0; i < num_threads; i++) {
4032             results[i] = NULL;
4033             tid[i] = (thread_id) - 1;
4034         }
4035         for (i = 0; i < num_threads; i++) {
4036             tid[i] =
4037                 spawn_thread(thread_specific_data, "xmlTestThread",
4038                              B_NORMAL_PRIORITY, (void *) testfiles[i]);
4039             if (tid[i] < B_OK) {
4040                 fprintf(stderr, "beos_thread_create failed\n");
4041                 return (1);
4042             }
4043             printf("beos_thread_create %d -> %d\n", i, tid[i]);
4044         }
4045         for (i = 0; i < num_threads; i++) {
4046             ret = wait_for_thread(tid[i], &results[i]);
4047             printf("beos_thread_wait %d -> %d\n", i, ret);
4048             if (ret != B_OK) {
4049                 fprintf(stderr, "beos_thread_wait failed\n");
4050                 return (1);
4051             }
4052         }
4053 
4054         xmlCatalogCleanup();
4055         ret = B_OK;
4056         for (i = 0; i < num_threads; i++)
4057             if (results[i] != (void *) Okay) {
4058                 printf("Thread %d handling %s failed\n", i, testfiles[i]);
4059                 ret = B_ERROR;
4060             }
4061     }
4062     if (ret != B_OK)
4063         return(1);
4064     return (0);
4065 }
4066 
4067 #elif defined HAVE_PTHREAD_H
4068 #include <pthread.h>
4069 
4070 static pthread_t tid[MAX_ARGC];
4071 
4072 static int
testThread(void)4073 testThread(void)
4074 {
4075     unsigned int i, repeat;
4076     unsigned int num_threads = sizeof(testfiles) / sizeof(testfiles[0]);
4077     void *results[MAX_ARGC];
4078     int ret;
4079     int res = 0;
4080 
4081     xmlInitParser();
4082 
4083     for (repeat = 0; repeat < 500; repeat++) {
4084         xmlLoadCatalog(catalog);
4085         nb_tests++;
4086 
4087         for (i = 0; i < num_threads; i++) {
4088             results[i] = NULL;
4089             tid[i] = (pthread_t) - 1;
4090         }
4091 
4092         for (i = 0; i < num_threads; i++) {
4093             ret = pthread_create(&tid[i], 0, thread_specific_data,
4094                                  (void *) testfiles[i]);
4095             if (ret != 0) {
4096                 fprintf(stderr, "pthread_create failed\n");
4097                 return (1);
4098             }
4099         }
4100         for (i = 0; i < num_threads; i++) {
4101             ret = pthread_join(tid[i], &results[i]);
4102             if (ret != 0) {
4103                 fprintf(stderr, "pthread_join failed\n");
4104                 return (1);
4105             }
4106         }
4107 
4108         xmlCatalogCleanup();
4109         for (i = 0; i < num_threads; i++)
4110             if (results[i] != (void *) Okay) {
4111                 fprintf(stderr, "Thread %d handling %s failed\n",
4112                         i, testfiles[i]);
4113                 res = 1;
4114             }
4115     }
4116     return (res);
4117 }
4118 
4119 #else
4120 static int
testThread(void)4121 testThread(void)
4122 {
4123     fprintf(stderr,
4124             "Specific platform thread support not detected\n");
4125     return (-1);
4126 }
4127 #endif
4128 static int
threadsTest(const char * filename ATTRIBUTE_UNUSED,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)4129 threadsTest(const char *filename ATTRIBUTE_UNUSED,
4130 	    const char *resul ATTRIBUTE_UNUSED,
4131 	    const char *err ATTRIBUTE_UNUSED,
4132 	    int options ATTRIBUTE_UNUSED) {
4133     return(testThread());
4134 }
4135 #endif
4136 /************************************************************************
4137  *									*
4138  *			Tests Descriptions				*
4139  *									*
4140  ************************************************************************/
4141 
4142 static
4143 testDesc testDescriptions[] = {
4144     { "XML regression tests" ,
4145       oldParseTest, "./test/*", "result/", "", NULL,
4146       0 },
4147     { "XML regression tests on memory" ,
4148       memParseTest, "./test/*", "result/", "", NULL,
4149       0 },
4150     { "XML entity subst regression tests" ,
4151       noentParseTest, "./test/*", "result/noent/", "", NULL,
4152       XML_PARSE_NOENT },
4153     { "XML Namespaces regression tests",
4154       errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4155       0 },
4156     { "Error cases regression tests",
4157       errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4158       0 },
4159 #ifdef LIBXML_READER_ENABLED
4160     { "Error cases stream regression tests",
4161       streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4162       0 },
4163     { "Reader regression tests",
4164       streamParseTest, "./test/*", "result/", ".rdr", NULL,
4165       0 },
4166     { "Reader entities substitution regression tests",
4167       streamParseTest, "./test/*", "result/", ".rde", NULL,
4168       XML_PARSE_NOENT },
4169     { "Reader on memory regression tests",
4170       streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4171       0 },
4172     { "Walker regression tests",
4173       walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4174       0 },
4175 #endif
4176 #ifdef LIBXML_SAX1_ENABLED
4177     { "SAX1 callbacks regression tests" ,
4178       saxParseTest, "./test/*", "result/", ".sax", NULL,
4179       XML_PARSE_SAX1 },
4180     { "SAX2 callbacks regression tests" ,
4181       saxParseTest, "./test/*", "result/", ".sax2", NULL,
4182       0 },
4183 #endif
4184 #ifdef LIBXML_PUSH_ENABLED
4185     { "XML push regression tests" ,
4186       pushParseTest, "./test/*", "result/", "", NULL,
4187       0 },
4188 #endif
4189 #ifdef LIBXML_HTML_ENABLED
4190     { "HTML regression tests" ,
4191       errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4192       XML_PARSE_HTML },
4193 #ifdef LIBXML_PUSH_ENABLED
4194     { "Push HTML regression tests" ,
4195       pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4196       XML_PARSE_HTML },
4197 #endif
4198 #ifdef LIBXML_SAX1_ENABLED
4199     { "HTML SAX regression tests" ,
4200       saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4201       XML_PARSE_HTML },
4202 #endif
4203 #endif
4204 #ifdef LIBXML_VALID_ENABLED
4205     { "Valid documents regression tests" ,
4206       errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4207       XML_PARSE_DTDVALID },
4208     { "Validity checking regression tests" ,
4209       errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4210       XML_PARSE_DTDVALID },
4211 #ifdef LIBXML_READER_ENABLED
4212     { "Streaming validity checking regression tests" ,
4213       streamParseTest, "./test/valid/*.xml", "result/valid/", NULL, ".err.rdr",
4214       XML_PARSE_DTDVALID },
4215     { "Streaming validity error checking regression tests" ,
4216       streamParseTest, "./test/VC/*", "result/VC/", NULL, ".rdr",
4217       XML_PARSE_DTDVALID },
4218 #endif
4219     { "General documents valid regression tests" ,
4220       errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4221       XML_PARSE_DTDVALID },
4222 #endif
4223 #ifdef LIBXML_XINCLUDE_ENABLED
4224     { "XInclude regression tests" ,
4225       errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4226       /* Ignore errors at this point ".err", */
4227       XML_PARSE_XINCLUDE },
4228 #ifdef LIBXML_READER_ENABLED
4229     { "XInclude xmlReader regression tests",
4230       streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4231       /* Ignore errors at this point ".err", */
4232       NULL, XML_PARSE_XINCLUDE },
4233 #endif
4234     { "XInclude regression tests stripping include nodes" ,
4235       errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4236       /* Ignore errors at this point ".err", */
4237       XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4238 #ifdef LIBXML_READER_ENABLED
4239     { "XInclude xmlReader regression tests stripping include nodes",
4240       streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4241       /* Ignore errors at this point ".err", */
4242       NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4243 #endif
4244 #endif
4245 #ifdef LIBXML_XPATH_ENABLED
4246 #ifdef LIBXML_DEBUG_ENABLED
4247     { "XPath expressions regression tests" ,
4248       xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4249       0 },
4250     { "XPath document queries regression tests" ,
4251       xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4252       0 },
4253 #ifdef LIBXML_XPTR_ENABLED
4254     { "XPointer document queries regression tests" ,
4255       xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4256       0 },
4257 #endif
4258     { "xml:id regression tests" ,
4259       xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4260       0 },
4261 #endif
4262 #endif
4263     { "URI parsing tests" ,
4264       uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4265       0 },
4266     { "URI base composition tests" ,
4267       uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4268       0 },
4269     { "Path URI conversion tests" ,
4270       uriPathTest, NULL, NULL, NULL, NULL,
4271       0 },
4272 #ifdef LIBXML_SCHEMAS_ENABLED
4273     { "Schemas regression tests" ,
4274       schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4275       0 },
4276     { "Relax-NG regression tests" ,
4277       rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4278       XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4279 #ifdef LIBXML_READER_ENABLED
4280     { "Relax-NG streaming regression tests" ,
4281       rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4282       XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4283 #endif
4284 #endif
4285 #ifdef LIBXML_PATTERN_ENABLED
4286 #ifdef LIBXML_READER_ENABLED
4287     { "Pattern regression tests" ,
4288       patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4289       0 },
4290 #endif
4291 #endif
4292 #ifdef LIBXML_C14N_ENABLED
4293     { "C14N with comments regression tests" ,
4294       c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4295       0 },
4296     { "C14N without comments regression tests" ,
4297       c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4298       0 },
4299     { "C14N exclusive without comments regression tests" ,
4300       c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4301       0 },
4302     { "C14N 1.1 without comments regression tests" ,
4303       c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL,
4304       0 },
4305 #endif
4306 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED) && defined(LIBXML_SAX1_ENABLED)
4307     { "Catalog and Threads regression tests" ,
4308       threadsTest, NULL, NULL, NULL, NULL,
4309       0 },
4310 #endif
4311     {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4312 };
4313 
4314 /************************************************************************
4315  *									*
4316  *		The main code driving the tests				*
4317  *									*
4318  ************************************************************************/
4319 
4320 static int
launchTests(testDescPtr tst)4321 launchTests(testDescPtr tst) {
4322     int res = 0, err = 0;
4323     size_t i;
4324     char *result;
4325     char *error;
4326     int mem;
4327 
4328     if (tst == NULL) return(-1);
4329     if (tst->in != NULL) {
4330 	glob_t globbuf;
4331 
4332 	globbuf.gl_offs = 0;
4333 	glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4334 	for (i = 0;i < globbuf.gl_pathc;i++) {
4335 	    if (!checkTestFile(globbuf.gl_pathv[i]))
4336 	        continue;
4337 	    if (tst->suffix != NULL) {
4338 		result = resultFilename(globbuf.gl_pathv[i], tst->out,
4339 					tst->suffix);
4340 		if (result == NULL) {
4341 		    fprintf(stderr, "Out of memory !\n");
4342 		    fatalError();
4343 		}
4344 	    } else {
4345 	        result = NULL;
4346 	    }
4347 	    if (tst->err != NULL) {
4348 		error = resultFilename(globbuf.gl_pathv[i], tst->out,
4349 		                        tst->err);
4350 		if (error == NULL) {
4351 		    fprintf(stderr, "Out of memory !\n");
4352 		    fatalError();
4353 		}
4354 	    } else {
4355 	        error = NULL;
4356 	    }
4357 	    if ((result) &&(!checkTestFile(result))) {
4358 	        fprintf(stderr, "Missing result file %s\n", result);
4359 	    } else if ((error) &&(!checkTestFile(error))) {
4360 	        fprintf(stderr, "Missing error file %s\n", error);
4361 	    } else {
4362 		mem = xmlMemUsed();
4363 		extraMemoryFromResolver = 0;
4364 		testErrorsSize = 0;
4365 		testErrors[0] = 0;
4366 		res = tst->func(globbuf.gl_pathv[i], result, error,
4367 		                tst->options | XML_PARSE_COMPACT);
4368 		xmlResetLastError();
4369 		if (res != 0) {
4370 		    fprintf(stderr, "File %s generated an error\n",
4371 		            globbuf.gl_pathv[i]);
4372 		    nb_errors++;
4373 		    err++;
4374 		}
4375 		else if (xmlMemUsed() != mem) {
4376 		    if ((xmlMemUsed() != mem) &&
4377 		        (extraMemoryFromResolver == 0)) {
4378 			fprintf(stderr, "File %s leaked %d bytes\n",
4379 				globbuf.gl_pathv[i], xmlMemUsed() - mem);
4380 			nb_leaks++;
4381 			err++;
4382 		    }
4383 		}
4384 		testErrorsSize = 0;
4385 	    }
4386 	    if (result)
4387 		free(result);
4388 	    if (error)
4389 		free(error);
4390 	}
4391 	globfree(&globbuf);
4392     } else {
4393         testErrorsSize = 0;
4394 	testErrors[0] = 0;
4395 	extraMemoryFromResolver = 0;
4396         res = tst->func(NULL, NULL, NULL, tst->options);
4397 	if (res != 0) {
4398 	    nb_errors++;
4399 	    err++;
4400 	}
4401     }
4402     return(err);
4403 }
4404 
4405 static int verbose = 0;
4406 static int tests_quiet = 0;
4407 
4408 static int
runtest(int i)4409 runtest(int i) {
4410     int ret = 0, res;
4411     int old_errors, old_tests, old_leaks;
4412 
4413     old_errors = nb_errors;
4414     old_tests = nb_tests;
4415     old_leaks = nb_leaks;
4416     if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
4417 	printf("## %s\n", testDescriptions[i].desc);
4418     res = launchTests(&testDescriptions[i]);
4419     if (res != 0)
4420 	ret++;
4421     if (verbose) {
4422 	if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4423 	    printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4424 	else
4425 	    printf("Ran %d tests, %d errors, %d leaks\n",
4426 		   nb_tests - old_tests,
4427 		   nb_errors - old_errors,
4428 		   nb_leaks - old_leaks);
4429     }
4430     return(ret);
4431 }
4432 
4433 int
main(int argc ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)4434 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4435     int i, a, ret = 0;
4436     int subset = 0;
4437 
4438     initializeLibxml2();
4439 
4440     for (a = 1; a < argc;a++) {
4441         if (!strcmp(argv[a], "-v"))
4442 	    verbose = 1;
4443         else if (!strcmp(argv[a], "-quiet"))
4444 	    tests_quiet = 1;
4445 	else {
4446 	    for (i = 0; testDescriptions[i].func != NULL; i++) {
4447 	        if (strstr(testDescriptions[i].desc, argv[a])) {
4448 		    ret += runtest(i);
4449 		    subset++;
4450 		}
4451 	    }
4452 	}
4453     }
4454     if (subset == 0) {
4455 	for (i = 0; testDescriptions[i].func != NULL; i++) {
4456 	    ret += runtest(i);
4457 	}
4458     }
4459     if ((nb_errors == 0) && (nb_leaks == 0)) {
4460         ret = 0;
4461 	printf("Total %d tests, no errors\n",
4462 	       nb_tests);
4463     } else {
4464         ret = 1;
4465 	printf("Total %d tests, %d errors, %d leaks\n",
4466 	       nb_tests, nb_errors, nb_leaks);
4467     }
4468     xmlCleanupParser();
4469     xmlMemoryDump();
4470 
4471     return(ret);
4472 }
4473 
4474 #else /* ! LIBXML_OUTPUT_ENABLED */
4475 int
main(int argc ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)4476 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4477     fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4478     return(1);
4479 }
4480 #endif
4481