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