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