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