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