VirtualBox

source: vbox/trunk/src/libs/libxml2-2.12.6/runtest.c

Last change on this file was 104106, checked in by vboxsync, 8 weeks ago

libxml2-2.9.14: Applied and adjusted our libxml2 changes to 2.9.14. bugref:10640

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

© 2023 Oracle
ContactPrivacy policyTerms of Use