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