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