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