VirtualBox

source: vbox/trunk/src/libs/libxml2-2.9.14/runtest.c@ 98101

Last change on this file since 98101 was 95312, checked in by vboxsync, 2 years ago

libs/{curl,libxml2}: OSE export fixes, bugref:8515

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette