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