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