VirtualBox

source: vbox/trunk/src/libs/libxml2-2.6.30/runtest.c@ 8172

最後變更 在這個檔案從8172是 6076,由 vboxsync 提交於 17 年 前

Merged dmik/s2 branch (r25959:26751) to the trunk.

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

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