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