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