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