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