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] = (char) ch[i];
1235 output[i] = 0;
1236
1237 fprintf(SAXdebug, "SAX.characters(%s, %d)\n", output, len);
1238 }
1239
1240 /**
1241 * referenceDebug:
1242 * @ctxt: An XML parser context
1243 * @name: The entity name
1244 *
1245 * called when an entity reference is detected.
1246 */
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] = (char) ch[i];
1277 output[i] = 0;
1278 fprintf(SAXdebug, "SAX.ignorableWhitespace(%s, %d)\n", output, len);
1279 }
1280
1281 /**
1282 * processingInstructionDebug:
1283 * @ctxt: An XML parser context
1284 * @target: the target name
1285 * @data: the PI data's
1286 * @len: the number of xmlChar
1287 *
1288 * A processing instruction has been parsed.
1289 */
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 /**
2136 * fdParseTest:
2137 * @filename: the file to parse
2138 * @result: the file with expected result
2139 * @err: the file with error messages
2140 *
2141 * Parse a file using the xmlReadFd API and check for errors.
2142 *
2143 * Returns 0 in case of success, an error code otherwise
2144 */
2145 static int
fdParseTest(const char * filename,const char * result,const char * err,int options)2146 fdParseTest(const char *filename, const char *result, const char *err,
2147 int options) {
2148 xmlDocPtr doc;
2149 const char *base = NULL;
2150 int size, res = 0;
2151
2152 nb_tests++;
2153 int fd = open(filename, RD_FLAGS);
2154 #ifdef LIBXML_HTML_ENABLED
2155 if (options & XML_PARSE_HTML) {
2156 doc = htmlReadFd(fd, filename, NULL, options);
2157 } else
2158 #endif
2159 {
2160 xmlGetWarningsDefaultValue = 1;
2161 doc = xmlReadFd(fd, filename, NULL, options);
2162 }
2163 close(fd);
2164 xmlGetWarningsDefaultValue = 0;
2165 if (result) {
2166 if (doc == NULL) {
2167 base = "";
2168 size = 0;
2169 } else {
2170 #ifdef LIBXML_HTML_ENABLED
2171 if (options & XML_PARSE_HTML) {
2172 htmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2173 } else
2174 #endif
2175 xmlDocDumpMemory(doc, (xmlChar **) &base, &size);
2176 }
2177 res = compareFileMem(result, base, size);
2178 }
2179 if (doc != NULL) {
2180 if (base != NULL)
2181 xmlFree((char *)base);
2182 xmlFreeDoc(doc);
2183 }
2184 if (res != 0) {
2185 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2186 return(-1);
2187 }
2188 if (err != NULL) {
2189 res = compareFileMem(err, testErrors, testErrorsSize);
2190 if (res != 0) {
2191 fprintf(stderr, "Error for %s failed\n", filename);
2192 return(-1);
2193 }
2194 } else if (options & XML_PARSE_DTDVALID) {
2195 if (testErrorsSize != 0)
2196 fprintf(stderr, "Validation for %s failed\n", filename);
2197 }
2198
2199 return(0);
2200 }
2201
2202
2203
2204 #ifdef LIBXML_READER_ENABLED
2205 /************************************************************************
2206 * *
2207 * Reader based tests *
2208 * *
2209 ************************************************************************/
2210
processNode(FILE * out,xmlTextReaderPtr reader)2211 static void processNode(FILE *out, xmlTextReaderPtr reader) {
2212 const xmlChar *name, *value;
2213 int type, empty;
2214
2215 type = xmlTextReaderNodeType(reader);
2216 empty = xmlTextReaderIsEmptyElement(reader);
2217
2218 name = xmlTextReaderConstName(reader);
2219 if (name == NULL)
2220 name = BAD_CAST "--";
2221
2222 value = xmlTextReaderConstValue(reader);
2223
2224
2225 fprintf(out, "%d %d %s %d %d",
2226 xmlTextReaderDepth(reader),
2227 type,
2228 name,
2229 empty,
2230 xmlTextReaderHasValue(reader));
2231 if (value == NULL)
2232 fprintf(out, "\n");
2233 else {
2234 fprintf(out, " %s\n", value);
2235 }
2236 }
2237 static int
streamProcessTest(const char * filename,const char * result,const char * err,xmlTextReaderPtr reader,const char * rng,int options ATTRIBUTE_UNUSED)2238 streamProcessTest(const char *filename, const char *result, const char *err,
2239 xmlTextReaderPtr reader, const char *rng,
2240 int options ATTRIBUTE_UNUSED) {
2241 int ret;
2242 char *temp = NULL;
2243 FILE *t = NULL;
2244
2245 if (reader == NULL)
2246 return(-1);
2247
2248 nb_tests++;
2249 if (result != NULL) {
2250 temp = resultFilename(filename, temp_directory, ".res");
2251 if (temp == NULL) {
2252 fprintf(stderr, "Out of memory\n");
2253 fatalError();
2254 }
2255 t = fopen(temp, "wb");
2256 if (t == NULL) {
2257 fprintf(stderr, "Can't open temp file %s\n", temp);
2258 free(temp);
2259 return(-1);
2260 }
2261 }
2262 #ifdef LIBXML_SCHEMAS_ENABLED
2263 if (rng != NULL) {
2264 ret = xmlTextReaderRelaxNGValidate(reader, rng);
2265 if (ret < 0) {
2266 testErrorHandler(NULL, "Relax-NG schema %s failed to compile\n",
2267 rng);
2268 fclose(t);
2269 if (temp != NULL) {
2270 unlink(temp);
2271 free(temp);
2272 }
2273 return(0);
2274 }
2275 }
2276 #endif
2277 xmlGetWarningsDefaultValue = 1;
2278 ret = xmlTextReaderRead(reader);
2279 while (ret == 1) {
2280 if ((t != NULL) && (rng == NULL))
2281 processNode(t, reader);
2282 ret = xmlTextReaderRead(reader);
2283 }
2284 if (ret != 0) {
2285 testErrorHandler(NULL, "%s : failed to parse\n", filename);
2286 }
2287 if (rng != NULL) {
2288 if (xmlTextReaderIsValid(reader) != 1) {
2289 testErrorHandler(NULL, "%s fails to validate\n", filename);
2290 } else {
2291 testErrorHandler(NULL, "%s validates\n", filename);
2292 }
2293 }
2294 xmlGetWarningsDefaultValue = 0;
2295 if (t != NULL) {
2296 fclose(t);
2297 ret = compareFiles(temp, result);
2298 if (temp != NULL) {
2299 unlink(temp);
2300 free(temp);
2301 }
2302 if (ret) {
2303 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2304 return(-1);
2305 }
2306 }
2307 if (err != NULL) {
2308 ret = compareFileMem(err, testErrors, testErrorsSize);
2309 if (ret != 0) {
2310 fprintf(stderr, "Error for %s failed\n", filename);
2311 printf("%s", testErrors);
2312 return(-1);
2313 }
2314 }
2315
2316 return(0);
2317 }
2318
2319 /**
2320 * streamParseTest:
2321 * @filename: the file to parse
2322 * @result: the file with expected result
2323 * @err: the file with error messages
2324 *
2325 * Parse a file using the reader API and check for errors.
2326 *
2327 * Returns 0 in case of success, an error code otherwise
2328 */
2329 static int
streamParseTest(const char * filename,const char * result,const char * err,int options)2330 streamParseTest(const char *filename, const char *result, const char *err,
2331 int options) {
2332 xmlTextReaderPtr reader;
2333 int ret;
2334
2335 reader = xmlReaderForFile(filename, NULL, options);
2336 ret = streamProcessTest(filename, result, err, reader, NULL, options);
2337 xmlFreeTextReader(reader);
2338 return(ret);
2339 }
2340
2341 /**
2342 * walkerParseTest:
2343 * @filename: the file to parse
2344 * @result: the file with expected result
2345 * @err: the file with error messages
2346 *
2347 * Parse a file using the walker, i.e. a reader built from a atree.
2348 *
2349 * Returns 0 in case of success, an error code otherwise
2350 */
2351 static int
walkerParseTest(const char * filename,const char * result,const char * err,int options)2352 walkerParseTest(const char *filename, const char *result, const char *err,
2353 int options) {
2354 xmlDocPtr doc;
2355 xmlTextReaderPtr reader;
2356 int ret;
2357
2358 doc = xmlReadFile(filename, NULL, options);
2359 if (doc == NULL) {
2360 fprintf(stderr, "Failed to parse %s\n", filename);
2361 return(-1);
2362 }
2363 reader = xmlReaderWalker(doc);
2364 ret = streamProcessTest(filename, result, err, reader, NULL, options);
2365 xmlFreeTextReader(reader);
2366 xmlFreeDoc(doc);
2367 return(ret);
2368 }
2369
2370 /**
2371 * streamMemParseTest:
2372 * @filename: the file to parse
2373 * @result: the file with expected result
2374 * @err: the file with error messages
2375 *
2376 * Parse a file using the reader API from memory and check for errors.
2377 *
2378 * Returns 0 in case of success, an error code otherwise
2379 */
2380 static int
streamMemParseTest(const char * filename,const char * result,const char * err,int options)2381 streamMemParseTest(const char *filename, const char *result, const char *err,
2382 int options) {
2383 xmlTextReaderPtr reader;
2384 int ret;
2385 const char *base;
2386 int size;
2387
2388 /*
2389 * load and parse the memory
2390 */
2391 if (loadMem(filename, &base, &size) != 0) {
2392 fprintf(stderr, "Failed to load %s\n", filename);
2393 return(-1);
2394 }
2395 reader = xmlReaderForMemory(base, size, filename, NULL, options);
2396 ret = streamProcessTest(filename, result, err, reader, NULL, options);
2397 free((char *)base);
2398 xmlFreeTextReader(reader);
2399 return(ret);
2400 }
2401 #endif
2402
2403 #ifdef LIBXML_XPATH_ENABLED
2404 #ifdef LIBXML_DEBUG_ENABLED
2405 /************************************************************************
2406 * *
2407 * XPath and XPointer based tests *
2408 * *
2409 ************************************************************************/
2410
2411 static FILE *xpathOutput;
2412 static xmlDocPtr xpathDocument;
2413
2414 static void
ignoreGenericError(void * ctx ATTRIBUTE_UNUSED,const char * msg ATTRIBUTE_UNUSED,...)2415 ignoreGenericError(void *ctx ATTRIBUTE_UNUSED,
2416 const char *msg ATTRIBUTE_UNUSED, ...) {
2417 }
2418
2419 static void
testXPath(const char * str,int xptr,int expr)2420 testXPath(const char *str, int xptr, int expr) {
2421 xmlGenericErrorFunc handler = ignoreGenericError;
2422 xmlXPathObjectPtr res;
2423 xmlXPathContextPtr ctxt;
2424
2425 /* Don't print generic errors to stderr. */
2426 initGenericErrorDefaultFunc(&handler);
2427
2428 nb_tests++;
2429 #if defined(LIBXML_XPTR_ENABLED)
2430 if (xptr) {
2431 ctxt = xmlXPtrNewContext(xpathDocument, NULL, NULL);
2432 res = xmlXPtrEval(BAD_CAST str, ctxt);
2433 } else {
2434 #endif
2435 ctxt = xmlXPathNewContext(xpathDocument);
2436 ctxt->node = xmlDocGetRootElement(xpathDocument);
2437 if (expr)
2438 res = xmlXPathEvalExpression(BAD_CAST str, ctxt);
2439 else {
2440 /* res = xmlXPathEval(BAD_CAST str, ctxt); */
2441 xmlXPathCompExprPtr comp;
2442
2443 comp = xmlXPathCompile(BAD_CAST str);
2444 if (comp != NULL) {
2445 res = xmlXPathCompiledEval(comp, ctxt);
2446 xmlXPathFreeCompExpr(comp);
2447 } else
2448 res = NULL;
2449 }
2450 #if defined(LIBXML_XPTR_ENABLED)
2451 }
2452 #endif
2453 xmlXPathDebugDumpObject(xpathOutput, res, 0);
2454 xmlXPathFreeObject(res);
2455 xmlXPathFreeContext(ctxt);
2456
2457 /* Reset generic error handler. */
2458 initGenericErrorDefaultFunc(NULL);
2459 }
2460
2461 /**
2462 * xpathExprTest:
2463 * @filename: the file to parse
2464 * @result: the file with expected result
2465 * @err: the file with error messages
2466 *
2467 * Parse a file containing XPath standalone expressions and evaluate them
2468 *
2469 * Returns 0 in case of success, an error code otherwise
2470 */
2471 static int
xpathCommonTest(const char * filename,const char * result,int xptr,int expr)2472 xpathCommonTest(const char *filename, const char *result,
2473 int xptr, int expr) {
2474 FILE *input;
2475 char expression[5000];
2476 int len, ret = 0;
2477 char *temp;
2478
2479 temp = resultFilename(filename, temp_directory, ".res");
2480 if (temp == NULL) {
2481 fprintf(stderr, "Out of memory\n");
2482 fatalError();
2483 }
2484 xpathOutput = fopen(temp, "wb");
2485 if (xpathOutput == NULL) {
2486 fprintf(stderr, "failed to open output file %s\n", temp);
2487 free(temp);
2488 return(-1);
2489 }
2490
2491 input = fopen(filename, "rb");
2492 if (input == NULL) {
2493 xmlGenericError(xmlGenericErrorContext,
2494 "Cannot open %s for reading\n", filename);
2495 free(temp);
2496 return(-1);
2497 }
2498 while (fgets(expression, 4500, input) != NULL) {
2499 len = strlen(expression);
2500 len--;
2501 while ((len >= 0) &&
2502 ((expression[len] == '\n') || (expression[len] == '\t') ||
2503 (expression[len] == '\r') || (expression[len] == ' '))) len--;
2504 expression[len + 1] = 0;
2505 if (len >= 0) {
2506 fprintf(xpathOutput,
2507 "\n========================\nExpression: %s\n",
2508 expression) ;
2509 testXPath(expression, xptr, expr);
2510 }
2511 }
2512
2513 fclose(input);
2514 fclose(xpathOutput);
2515 if (result != NULL) {
2516 ret = compareFiles(temp, result);
2517 if (ret) {
2518 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2519 }
2520 }
2521
2522 if (temp != NULL) {
2523 unlink(temp);
2524 free(temp);
2525 }
2526 return(ret);
2527 }
2528
2529 /**
2530 * xpathExprTest:
2531 * @filename: the file to parse
2532 * @result: the file with expected result
2533 * @err: the file with error messages
2534 *
2535 * Parse a file containing XPath standalone expressions and evaluate them
2536 *
2537 * Returns 0 in case of success, an error code otherwise
2538 */
2539 static int
xpathExprTest(const char * filename,const char * result,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)2540 xpathExprTest(const char *filename, const char *result,
2541 const char *err ATTRIBUTE_UNUSED,
2542 int options ATTRIBUTE_UNUSED) {
2543 return(xpathCommonTest(filename, result, 0, 1));
2544 }
2545
2546 /**
2547 * xpathDocTest:
2548 * @filename: the file to parse
2549 * @result: the file with expected result
2550 * @err: the file with error messages
2551 *
2552 * Parse a file containing XPath expressions and evaluate them against
2553 * a set of corresponding documents.
2554 *
2555 * Returns 0 in case of success, an error code otherwise
2556 */
2557 static int
xpathDocTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options)2558 xpathDocTest(const char *filename,
2559 const char *resul ATTRIBUTE_UNUSED,
2560 const char *err ATTRIBUTE_UNUSED,
2561 int options) {
2562
2563 char pattern[500];
2564 char result[500];
2565 glob_t globbuf;
2566 size_t i;
2567 int ret = 0, res;
2568
2569 xpathDocument = xmlReadFile(filename, NULL,
2570 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2571 if (xpathDocument == NULL) {
2572 fprintf(stderr, "Failed to load %s\n", filename);
2573 return(-1);
2574 }
2575
2576 res = snprintf(pattern, 499, "./test/XPath/tests/%s*",
2577 baseFilename(filename));
2578 if (res >= 499)
2579 pattern[499] = 0;
2580 globbuf.gl_offs = 0;
2581 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2582 for (i = 0;i < globbuf.gl_pathc;i++) {
2583 res = snprintf(result, 499, "result/XPath/tests/%s",
2584 baseFilename(globbuf.gl_pathv[i]));
2585 if (res >= 499)
2586 result[499] = 0;
2587 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 0, 0);
2588 if (res != 0)
2589 ret = res;
2590 }
2591 globfree(&globbuf);
2592
2593 xmlFreeDoc(xpathDocument);
2594 return(ret);
2595 }
2596
2597 #ifdef LIBXML_XPTR_ENABLED
2598 /**
2599 * xptrDocTest:
2600 * @filename: the file to parse
2601 * @result: the file with expected result
2602 * @err: the file with error messages
2603 *
2604 * Parse a file containing XPath expressions and evaluate them against
2605 * a set of corresponding documents.
2606 *
2607 * Returns 0 in case of success, an error code otherwise
2608 */
2609 static int
xptrDocTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options)2610 xptrDocTest(const char *filename,
2611 const char *resul ATTRIBUTE_UNUSED,
2612 const char *err ATTRIBUTE_UNUSED,
2613 int options) {
2614
2615 char pattern[500];
2616 char result[500];
2617 glob_t globbuf;
2618 size_t i;
2619 int ret = 0, res;
2620
2621 xpathDocument = xmlReadFile(filename, NULL,
2622 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2623 if (xpathDocument == NULL) {
2624 fprintf(stderr, "Failed to load %s\n", filename);
2625 return(-1);
2626 }
2627
2628 res = snprintf(pattern, 499, "./test/XPath/xptr/%s*",
2629 baseFilename(filename));
2630 if (res >= 499)
2631 pattern[499] = 0;
2632 globbuf.gl_offs = 0;
2633 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
2634 for (i = 0;i < globbuf.gl_pathc;i++) {
2635 res = snprintf(result, 499, "result/XPath/xptr/%s",
2636 baseFilename(globbuf.gl_pathv[i]));
2637 if (res >= 499)
2638 result[499] = 0;
2639 res = xpathCommonTest(globbuf.gl_pathv[i], &result[0], 1, 0);
2640 if (res != 0)
2641 ret = res;
2642 }
2643 globfree(&globbuf);
2644
2645 xmlFreeDoc(xpathDocument);
2646 return(ret);
2647 }
2648 #endif /* LIBXML_XPTR_ENABLED */
2649
2650 /**
2651 * xmlidDocTest:
2652 * @filename: the file to parse
2653 * @result: the file with expected result
2654 * @err: the file with error messages
2655 *
2656 * Parse a file containing xml:id and check for errors and verify
2657 * that XPath queries will work on them as expected.
2658 *
2659 * Returns 0 in case of success, an error code otherwise
2660 */
2661 static int
xmlidDocTest(const char * filename,const char * result,const char * err,int options)2662 xmlidDocTest(const char *filename,
2663 const char *result,
2664 const char *err,
2665 int options) {
2666
2667 int res = 0;
2668 int ret = 0;
2669 char *temp;
2670
2671 xpathDocument = xmlReadFile(filename, NULL,
2672 options | XML_PARSE_DTDATTR | XML_PARSE_NOENT);
2673 if (xpathDocument == NULL) {
2674 fprintf(stderr, "Failed to load %s\n", filename);
2675 return(-1);
2676 }
2677
2678 temp = resultFilename(filename, temp_directory, ".res");
2679 if (temp == NULL) {
2680 fprintf(stderr, "Out of memory\n");
2681 fatalError();
2682 }
2683 xpathOutput = fopen(temp, "wb");
2684 if (xpathOutput == NULL) {
2685 fprintf(stderr, "failed to open output file %s\n", temp);
2686 xmlFreeDoc(xpathDocument);
2687 free(temp);
2688 return(-1);
2689 }
2690
2691 testXPath("id('bar')", 0, 0);
2692
2693 fclose(xpathOutput);
2694 if (result != NULL) {
2695 ret = compareFiles(temp, result);
2696 if (ret) {
2697 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2698 res = 1;
2699 }
2700 }
2701
2702 if (temp != NULL) {
2703 unlink(temp);
2704 free(temp);
2705 }
2706 xmlFreeDoc(xpathDocument);
2707
2708 if (err != NULL) {
2709 ret = compareFileMem(err, testErrors, testErrorsSize);
2710 if (ret != 0) {
2711 fprintf(stderr, "Error for %s failed\n", filename);
2712 res = 1;
2713 }
2714 }
2715 return(res);
2716 }
2717
2718 #endif /* LIBXML_DEBUG_ENABLED */
2719 #endif /* XPATH */
2720 /************************************************************************
2721 * *
2722 * URI based tests *
2723 * *
2724 ************************************************************************/
2725
2726 static void
handleURI(const char * str,const char * base,FILE * o)2727 handleURI(const char *str, const char *base, FILE *o) {
2728 int ret;
2729 xmlURIPtr uri;
2730 xmlChar *res = NULL;
2731
2732 uri = xmlCreateURI();
2733
2734 if (base == NULL) {
2735 ret = xmlParseURIReference(uri, str);
2736 if (ret != 0)
2737 fprintf(o, "%s : error %d\n", str, ret);
2738 else {
2739 xmlNormalizeURIPath(uri->path);
2740 xmlPrintURI(o, uri);
2741 fprintf(o, "\n");
2742 }
2743 } else {
2744 res = xmlBuildURI((xmlChar *)str, (xmlChar *) base);
2745 if (res != NULL) {
2746 fprintf(o, "%s\n", (char *) res);
2747 }
2748 else
2749 fprintf(o, "::ERROR::\n");
2750 }
2751 if (res != NULL)
2752 xmlFree(res);
2753 xmlFreeURI(uri);
2754 }
2755
2756 /**
2757 * uriCommonTest:
2758 * @filename: the file to parse
2759 * @result: the file with expected result
2760 * @err: the file with error messages
2761 *
2762 * Parse a file containing URI and check for errors
2763 *
2764 * Returns 0 in case of success, an error code otherwise
2765 */
2766 static int
uriCommonTest(const char * filename,const char * result,const char * err,const char * base)2767 uriCommonTest(const char *filename,
2768 const char *result,
2769 const char *err,
2770 const char *base) {
2771 char *temp;
2772 FILE *o, *f;
2773 char str[1024];
2774 int res = 0, i, ret;
2775
2776 temp = resultFilename(filename, temp_directory, ".res");
2777 if (temp == NULL) {
2778 fprintf(stderr, "Out of memory\n");
2779 fatalError();
2780 }
2781 o = fopen(temp, "wb");
2782 if (o == NULL) {
2783 fprintf(stderr, "failed to open output file %s\n", temp);
2784 free(temp);
2785 return(-1);
2786 }
2787 f = fopen(filename, "rb");
2788 if (f == NULL) {
2789 fprintf(stderr, "failed to open input file %s\n", filename);
2790 fclose(o);
2791 if (temp != NULL) {
2792 unlink(temp);
2793 free(temp);
2794 }
2795 return(-1);
2796 }
2797
2798 while (1) {
2799 /*
2800 * read one line in string buffer.
2801 */
2802 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
2803 break;
2804
2805 /*
2806 * remove the ending spaces
2807 */
2808 i = strlen(str);
2809 while ((i > 0) &&
2810 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
2811 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
2812 i--;
2813 str[i] = 0;
2814 }
2815 nb_tests++;
2816 handleURI(str, base, o);
2817 }
2818
2819 fclose(f);
2820 fclose(o);
2821
2822 if (result != NULL) {
2823 ret = compareFiles(temp, result);
2824 if (ret) {
2825 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
2826 res = 1;
2827 }
2828 }
2829 if (err != NULL) {
2830 ret = compareFileMem(err, testErrors, testErrorsSize);
2831 if (ret != 0) {
2832 fprintf(stderr, "Error for %s failed\n", filename);
2833 res = 1;
2834 }
2835 }
2836
2837 if (temp != NULL) {
2838 unlink(temp);
2839 free(temp);
2840 }
2841 return(res);
2842 }
2843
2844 /**
2845 * uriParseTest:
2846 * @filename: the file to parse
2847 * @result: the file with expected result
2848 * @err: the file with error messages
2849 *
2850 * Parse a file containing URI and check for errors
2851 *
2852 * Returns 0 in case of success, an error code otherwise
2853 */
2854 static int
uriParseTest(const char * filename,const char * result,const char * err,int options ATTRIBUTE_UNUSED)2855 uriParseTest(const char *filename,
2856 const char *result,
2857 const char *err,
2858 int options ATTRIBUTE_UNUSED) {
2859 return(uriCommonTest(filename, result, err, NULL));
2860 }
2861
2862 /**
2863 * uriBaseTest:
2864 * @filename: the file to parse
2865 * @result: the file with expected result
2866 * @err: the file with error messages
2867 *
2868 * Parse a file containing URI, compose them against a fixed base and
2869 * check for errors
2870 *
2871 * Returns 0 in case of success, an error code otherwise
2872 */
2873 static int
uriBaseTest(const char * filename,const char * result,const char * err,int options ATTRIBUTE_UNUSED)2874 uriBaseTest(const char *filename,
2875 const char *result,
2876 const char *err,
2877 int options ATTRIBUTE_UNUSED) {
2878 return(uriCommonTest(filename, result, err,
2879 "http://foo.com/path/to/index.html?orig#help"));
2880 }
2881
2882 static int urip_success = 1;
2883 static int urip_current = 0;
2884 static const char *urip_testURLs[] = {
2885 "urip://example.com/a b.html",
2886 "urip://example.com/a%20b.html",
2887 "file:///path/to/a b.html",
2888 "file:///path/to/a%20b.html",
2889 "/path/to/a b.html",
2890 "/path/to/a%20b.html",
2891 "urip://example.com/r" "\xe9" "sum" "\xe9" ".html",
2892 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2893 NULL
2894 };
2895 static const char *urip_rcvsURLs[] = {
2896 /* it is an URI the strings must be escaped */
2897 "urip://example.com/a%20b.html",
2898 /* check that % escaping is not broken */
2899 "urip://example.com/a%20b.html",
2900 /* it's an URI path the strings must be escaped */
2901 "file:///path/to/a%20b.html",
2902 /* check that % escaping is not broken */
2903 "file:///path/to/a%20b.html",
2904 /* this is not an URI, this is a path, so this should not be escaped */
2905 "/path/to/a b.html",
2906 /* check that paths with % are not broken */
2907 "/path/to/a%20b.html",
2908 /* out of context the encoding can't be guessed byte by byte conversion */
2909 "urip://example.com/r%E9sum%E9.html",
2910 /* verify we don't destroy URIs especially the query part */
2911 "urip://example.com/test?a=1&b=2%263&c=4#foo",
2912 NULL
2913 };
2914 static const char *urip_res = "<list/>";
2915 static const char *urip_cur = NULL;
2916 static int urip_rlen;
2917
2918 /**
2919 * uripMatch:
2920 * @URI: an URI to test
2921 *
2922 * Check for an urip: query
2923 *
2924 * Returns 1 if yes and 0 if another Input module should be used
2925 */
2926 static int
uripMatch(const char * URI)2927 uripMatch(const char * URI) {
2928 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2929 return(0);
2930 /* Verify we received the escaped URL */
2931 if (strcmp(urip_rcvsURLs[urip_current], URI))
2932 urip_success = 0;
2933 return(1);
2934 }
2935
2936 /**
2937 * uripOpen:
2938 * @URI: an URI to test
2939 *
2940 * Return a pointer to the urip: query handler, in this example simply
2941 * the urip_current pointer...
2942 *
2943 * Returns an Input context or NULL in case or error
2944 */
2945 static void *
uripOpen(const char * URI)2946 uripOpen(const char * URI) {
2947 if ((URI == NULL) || (!strcmp(URI, "file:///etc/xml/catalog")))
2948 return(NULL);
2949 /* Verify we received the escaped URL */
2950 if (strcmp(urip_rcvsURLs[urip_current], URI))
2951 urip_success = 0;
2952 urip_cur = urip_res;
2953 urip_rlen = strlen(urip_res);
2954 return((void *) urip_cur);
2955 }
2956
2957 /**
2958 * uripClose:
2959 * @context: the read context
2960 *
2961 * Close the urip: query handler
2962 *
2963 * Returns 0 or -1 in case of error
2964 */
2965 static int
uripClose(void * context)2966 uripClose(void * context) {
2967 if (context == NULL) return(-1);
2968 urip_cur = NULL;
2969 urip_rlen = 0;
2970 return(0);
2971 }
2972
2973 /**
2974 * uripRead:
2975 * @context: the read context
2976 * @buffer: where to store data
2977 * @len: number of bytes to read
2978 *
2979 * Implement an urip: query read.
2980 *
2981 * Returns the number of bytes read or -1 in case of error
2982 */
2983 static int
uripRead(void * context,char * buffer,int len)2984 uripRead(void * context, char * buffer, int len) {
2985 const char *ptr = (const char *) context;
2986
2987 if ((context == NULL) || (buffer == NULL) || (len < 0))
2988 return(-1);
2989
2990 if (len > urip_rlen) len = urip_rlen;
2991 memcpy(buffer, ptr, len);
2992 urip_rlen -= len;
2993 return(len);
2994 }
2995
2996 static int
urip_checkURL(const char * URL)2997 urip_checkURL(const char *URL) {
2998 xmlDocPtr doc;
2999
3000 doc = xmlReadFile(URL, NULL, 0);
3001 if (doc == NULL)
3002 return(-1);
3003 xmlFreeDoc(doc);
3004 return(1);
3005 }
3006
3007 /**
3008 * uriPathTest:
3009 * @filename: ignored
3010 * @result: ignored
3011 * @err: ignored
3012 *
3013 * Run a set of tests to check how Path and URI are handled before
3014 * being passed to the I/O layer
3015 *
3016 * Returns 0 in case of success, an error code otherwise
3017 */
3018 static int
uriPathTest(const char * filename ATTRIBUTE_UNUSED,const char * result ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)3019 uriPathTest(const char *filename ATTRIBUTE_UNUSED,
3020 const char *result ATTRIBUTE_UNUSED,
3021 const char *err ATTRIBUTE_UNUSED,
3022 int options ATTRIBUTE_UNUSED) {
3023 int parsed;
3024 int failures = 0;
3025
3026 /*
3027 * register the new I/O handlers
3028 */
3029 if (xmlRegisterInputCallbacks(uripMatch, uripOpen, uripRead, uripClose) < 0)
3030 {
3031 fprintf(stderr, "failed to register HTTP handler\n");
3032 return(-1);
3033 }
3034
3035 for (urip_current = 0;urip_testURLs[urip_current] != NULL;urip_current++) {
3036 urip_success = 1;
3037 parsed = urip_checkURL(urip_testURLs[urip_current]);
3038 if (urip_success != 1) {
3039 fprintf(stderr, "failed the URL passing test for %s",
3040 urip_testURLs[urip_current]);
3041 failures++;
3042 } else if (parsed != 1) {
3043 fprintf(stderr, "failed the parsing test for %s",
3044 urip_testURLs[urip_current]);
3045 failures++;
3046 }
3047 nb_tests++;
3048 }
3049
3050 xmlPopInputCallbacks();
3051 return(failures);
3052 }
3053
3054 #ifdef LIBXML_SCHEMAS_ENABLED
3055 /************************************************************************
3056 * *
3057 * Schemas tests *
3058 * *
3059 ************************************************************************/
3060 static int
schemasOneTest(const char * sch,const char * filename,const char * result,const char * err,int options,xmlSchemaPtr schemas)3061 schemasOneTest(const char *sch,
3062 const char *filename,
3063 const char *result,
3064 const char *err,
3065 int options,
3066 xmlSchemaPtr schemas) {
3067 xmlDocPtr doc;
3068 xmlSchemaValidCtxtPtr ctxt;
3069 int ret = 0;
3070 int validResult = 0;
3071 char *temp;
3072 FILE *schemasOutput;
3073
3074 doc = xmlReadFile(filename, NULL, options);
3075 if (doc == NULL) {
3076 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3077 return(-1);
3078 }
3079
3080 temp = resultFilename(result, temp_directory, ".res");
3081 if (temp == NULL) {
3082 fprintf(stderr, "Out of memory\n");
3083 fatalError();
3084 }
3085 schemasOutput = fopen(temp, "wb");
3086 if (schemasOutput == NULL) {
3087 fprintf(stderr, "failed to open output file %s\n", temp);
3088 xmlFreeDoc(doc);
3089 free(temp);
3090 return(-1);
3091 }
3092
3093 ctxt = xmlSchemaNewValidCtxt(schemas);
3094 xmlSchemaSetValidErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
3095 validResult = xmlSchemaValidateDoc(ctxt, doc);
3096 if (validResult == 0) {
3097 fprintf(schemasOutput, "%s validates\n", filename);
3098 } else if (validResult > 0) {
3099 fprintf(schemasOutput, "%s fails to validate\n", filename);
3100 } else {
3101 fprintf(schemasOutput, "%s validation generated an internal error\n",
3102 filename);
3103 }
3104 fclose(schemasOutput);
3105 if (result) {
3106 if (compareFiles(temp, result)) {
3107 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3108 ret = 1;
3109 }
3110 }
3111 if (temp != NULL) {
3112 unlink(temp);
3113 free(temp);
3114 }
3115
3116 if ((validResult != 0) && (err != NULL)) {
3117 if (compareFileMem(err, testErrors, testErrorsSize)) {
3118 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3119 ret = 1;
3120 }
3121 }
3122
3123 xmlSchemaFreeValidCtxt(ctxt);
3124 xmlFreeDoc(doc);
3125 return(ret);
3126 }
3127 /**
3128 * schemasTest:
3129 * @filename: the schemas file
3130 * @result: the file with expected result
3131 * @err: the file with error messages
3132 *
3133 * Parse a file containing URI, compose them against a fixed base and
3134 * check for errors
3135 *
3136 * Returns 0 in case of success, an error code otherwise
3137 */
3138 static int
schemasTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * errr ATTRIBUTE_UNUSED,int options)3139 schemasTest(const char *filename,
3140 const char *resul ATTRIBUTE_UNUSED,
3141 const char *errr ATTRIBUTE_UNUSED,
3142 int options) {
3143 const char *base = baseFilename(filename);
3144 const char *base2;
3145 const char *instance;
3146 xmlSchemaParserCtxtPtr ctxt;
3147 xmlSchemaPtr schemas;
3148 int res = 0, len, ret;
3149 char pattern[500];
3150 char prefix[500];
3151 char result[500];
3152 char err[500];
3153 glob_t globbuf;
3154 size_t i;
3155 char count = 0;
3156
3157 /* first compile the schemas if possible */
3158 ctxt = xmlSchemaNewParserCtxt(filename);
3159 xmlSchemaSetParserErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
3160 schemas = xmlSchemaParse(ctxt);
3161 xmlSchemaFreeParserCtxt(ctxt);
3162
3163 /*
3164 * most of the mess is about the output filenames generated by the Makefile
3165 */
3166 len = strlen(base);
3167 if ((len > 499) || (len < 5)) {
3168 xmlSchemaFree(schemas);
3169 return(-1);
3170 }
3171 len -= 4; /* remove trailing .xsd */
3172 if (base[len - 2] == '_') {
3173 len -= 2; /* remove subtest number */
3174 }
3175 if (base[len - 2] == '_') {
3176 len -= 2; /* remove subtest number */
3177 }
3178 memcpy(prefix, base, len);
3179 prefix[len] = 0;
3180
3181 if (snprintf(pattern, 499, "./test/schemas/%s_?.xml", prefix) >= 499)
3182 pattern[499] = 0;
3183
3184 if (base[len] == '_') {
3185 len += 2;
3186 memcpy(prefix, base, len);
3187 prefix[len] = 0;
3188 }
3189
3190 globbuf.gl_offs = 0;
3191 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3192 for (i = 0;i < globbuf.gl_pathc;i++) {
3193 testErrorsSize = 0;
3194 testErrors[0] = 0;
3195 instance = globbuf.gl_pathv[i];
3196 base2 = baseFilename(instance);
3197 len = strlen(base2);
3198 if ((len > 6) && (base2[len - 6] == '_')) {
3199 count = base2[len - 5];
3200 ret = snprintf(result, 499, "result/schemas/%s_%c",
3201 prefix, count);
3202 if (ret >= 499)
3203 result[499] = 0;
3204 ret = snprintf(err, 499, "result/schemas/%s_%c.err",
3205 prefix, count);
3206 if (ret >= 499)
3207 err[499] = 0;
3208 } else {
3209 fprintf(stderr, "don't know how to process %s\n", instance);
3210 continue;
3211 }
3212 if (schemas == NULL) {
3213 } else {
3214 nb_tests++;
3215 ret = schemasOneTest(filename, instance, result, err,
3216 options, schemas);
3217 if (ret != 0)
3218 res = ret;
3219 }
3220 }
3221 globfree(&globbuf);
3222 xmlSchemaFree(schemas);
3223
3224 return(res);
3225 }
3226
3227 /************************************************************************
3228 * *
3229 * Schemas tests *
3230 * *
3231 ************************************************************************/
3232 static int
rngOneTest(const char * sch,const char * filename,const char * result,const char * err,int options,xmlRelaxNGPtr schemas)3233 rngOneTest(const char *sch,
3234 const char *filename,
3235 const char *result,
3236 const char *err,
3237 int options,
3238 xmlRelaxNGPtr schemas) {
3239 xmlDocPtr doc;
3240 xmlRelaxNGValidCtxtPtr ctxt;
3241 int ret = 0;
3242 char *temp;
3243 FILE *schemasOutput;
3244
3245 doc = xmlReadFile(filename, NULL, options);
3246 if (doc == NULL) {
3247 fprintf(stderr, "failed to parse instance %s for %s\n", filename, sch);
3248 return(-1);
3249 }
3250
3251 temp = resultFilename(result, temp_directory, ".res");
3252 if (temp == NULL) {
3253 fprintf(stderr, "Out of memory\n");
3254 fatalError();
3255 }
3256 schemasOutput = fopen(temp, "wb");
3257 if (schemasOutput == NULL) {
3258 fprintf(stderr, "failed to open output file %s\n", temp);
3259 xmlFreeDoc(doc);
3260 free(temp);
3261 return(-1);
3262 }
3263
3264 ctxt = xmlRelaxNGNewValidCtxt(schemas);
3265 xmlRelaxNGSetValidErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
3266 ret = xmlRelaxNGValidateDoc(ctxt, doc);
3267 if (ret == 0) {
3268 testErrorHandler(NULL, "%s validates\n", filename);
3269 } else if (ret > 0) {
3270 testErrorHandler(NULL, "%s fails to validate\n", filename);
3271 } else {
3272 testErrorHandler(NULL, "%s validation generated an internal error\n",
3273 filename);
3274 }
3275 fclose(schemasOutput);
3276 ret = 0;
3277 if (result) {
3278 if (compareFiles(temp, result)) {
3279 fprintf(stderr, "Result for %s on %s failed\n", filename, sch);
3280 ret = 1;
3281 }
3282 }
3283 if (temp != NULL) {
3284 unlink(temp);
3285 free(temp);
3286 }
3287
3288 if (err != NULL) {
3289 if (compareFileMem(err, testErrors, testErrorsSize)) {
3290 fprintf(stderr, "Error for %s on %s failed\n", filename, sch);
3291 ret = 1;
3292 printf("%s", testErrors);
3293 }
3294 }
3295
3296
3297 xmlRelaxNGFreeValidCtxt(ctxt);
3298 xmlFreeDoc(doc);
3299 return(ret);
3300 }
3301 /**
3302 * rngTest:
3303 * @filename: the schemas file
3304 * @result: the file with expected result
3305 * @err: the file with error messages
3306 *
3307 * Parse an RNG schemas and then apply it to the related .xml
3308 *
3309 * Returns 0 in case of success, an error code otherwise
3310 */
3311 static int
rngTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * errr ATTRIBUTE_UNUSED,int options)3312 rngTest(const char *filename,
3313 const char *resul ATTRIBUTE_UNUSED,
3314 const char *errr ATTRIBUTE_UNUSED,
3315 int options) {
3316 const char *base = baseFilename(filename);
3317 const char *base2;
3318 const char *instance;
3319 xmlRelaxNGParserCtxtPtr ctxt;
3320 xmlRelaxNGPtr schemas;
3321 int res = 0, len, ret = 0;
3322 char pattern[500];
3323 char prefix[500];
3324 char result[500];
3325 char err[500];
3326 glob_t globbuf;
3327 size_t i;
3328 char count = 0;
3329
3330 /* first compile the schemas if possible */
3331 ctxt = xmlRelaxNGNewParserCtxt(filename);
3332 xmlRelaxNGSetParserErrors(ctxt, testErrorHandler, testErrorHandler, ctxt);
3333 schemas = xmlRelaxNGParse(ctxt);
3334 xmlRelaxNGFreeParserCtxt(ctxt);
3335
3336 /*
3337 * most of the mess is about the output filenames generated by the Makefile
3338 */
3339 len = strlen(base);
3340 if ((len > 499) || (len < 5)) {
3341 xmlRelaxNGFree(schemas);
3342 return(-1);
3343 }
3344 len -= 4; /* remove trailing .rng */
3345 memcpy(prefix, base, len);
3346 prefix[len] = 0;
3347
3348 if (snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix) >= 499)
3349 pattern[499] = 0;
3350
3351 globbuf.gl_offs = 0;
3352 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3353 for (i = 0;i < globbuf.gl_pathc;i++) {
3354 testErrorsSize = 0;
3355 testErrors[0] = 0;
3356 instance = globbuf.gl_pathv[i];
3357 base2 = baseFilename(instance);
3358 len = strlen(base2);
3359 if ((len > 6) && (base2[len - 6] == '_')) {
3360 count = base2[len - 5];
3361 res = snprintf(result, 499, "result/relaxng/%s_%c",
3362 prefix, count);
3363 if (res >= 499)
3364 result[499] = 0;
3365 res = snprintf(err, 499, "result/relaxng/%s_%c.err",
3366 prefix, count);
3367 if (res >= 499)
3368 err[499] = 0;
3369 } else {
3370 fprintf(stderr, "don't know how to process %s\n", instance);
3371 continue;
3372 }
3373 if (schemas == NULL) {
3374 } else {
3375 nb_tests++;
3376 res = rngOneTest(filename, instance, result, err,
3377 options, schemas);
3378 if (res != 0)
3379 ret = res;
3380 }
3381 }
3382 globfree(&globbuf);
3383 xmlRelaxNGFree(schemas);
3384
3385 return(ret);
3386 }
3387
3388 #ifdef LIBXML_READER_ENABLED
3389 /**
3390 * rngStreamTest:
3391 * @filename: the schemas file
3392 * @result: the file with expected result
3393 * @err: the file with error messages
3394 *
3395 * Parse a set of files with streaming, applying an RNG schemas
3396 *
3397 * Returns 0 in case of success, an error code otherwise
3398 */
3399 static int
rngStreamTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * errr ATTRIBUTE_UNUSED,int options)3400 rngStreamTest(const char *filename,
3401 const char *resul ATTRIBUTE_UNUSED,
3402 const char *errr ATTRIBUTE_UNUSED,
3403 int options) {
3404 const char *base = baseFilename(filename);
3405 const char *base2;
3406 const char *instance;
3407 int res = 0, len, ret;
3408 char pattern[500];
3409 char prefix[500];
3410 char result[500];
3411 char err[500];
3412 glob_t globbuf;
3413 size_t i;
3414 char count = 0;
3415 xmlTextReaderPtr reader;
3416 int disable_err = 0;
3417
3418 /*
3419 * most of the mess is about the output filenames generated by the Makefile
3420 */
3421 len = strlen(base);
3422 if ((len > 499) || (len < 5)) {
3423 fprintf(stderr, "len(base) == %d !\n", len);
3424 return(-1);
3425 }
3426 len -= 4; /* remove trailing .rng */
3427 memcpy(prefix, base, len);
3428 prefix[len] = 0;
3429
3430 /*
3431 * strictly unifying the error messages is nearly impossible this
3432 * hack is also done in the Makefile
3433 */
3434 if ((!strcmp(prefix, "tutor10_1")) || (!strcmp(prefix, "tutor10_2")) ||
3435 (!strcmp(prefix, "tutor3_2")) || (!strcmp(prefix, "307377")) ||
3436 (!strcmp(prefix, "tutor8_2")))
3437 disable_err = 1;
3438
3439 if (snprintf(pattern, 499, "./test/relaxng/%s_?.xml", prefix) >= 499)
3440 pattern[499] = 0;
3441
3442 globbuf.gl_offs = 0;
3443 glob(pattern, GLOB_DOOFFS, NULL, &globbuf);
3444 for (i = 0;i < globbuf.gl_pathc;i++) {
3445 testErrorsSize = 0;
3446 testErrors[0] = 0;
3447 instance = globbuf.gl_pathv[i];
3448 base2 = baseFilename(instance);
3449 len = strlen(base2);
3450 if ((len > 6) && (base2[len - 6] == '_')) {
3451 count = base2[len - 5];
3452 ret = snprintf(result, 499, "result/relaxng/%s_%c",
3453 prefix, count);
3454 if (ret >= 499)
3455 result[499] = 0;
3456 ret = snprintf(err, 499, "result/relaxng/%s_%c.err",
3457 prefix, count);
3458 if (ret >= 499)
3459 err[499] = 0;
3460 } else {
3461 fprintf(stderr, "don't know how to process %s\n", instance);
3462 continue;
3463 }
3464 reader = xmlReaderForFile(instance, NULL, options);
3465 if (reader == NULL) {
3466 fprintf(stderr, "Failed to build reader for %s\n", instance);
3467 }
3468 if (disable_err == 1)
3469 ret = streamProcessTest(instance, result, NULL, reader, filename,
3470 options);
3471 else
3472 ret = streamProcessTest(instance, result, err, reader, filename,
3473 options);
3474 xmlFreeTextReader(reader);
3475 if (ret != 0) {
3476 fprintf(stderr, "instance %s failed\n", instance);
3477 res = ret;
3478 }
3479 }
3480 globfree(&globbuf);
3481
3482 return(res);
3483 }
3484 #endif /* READER */
3485
3486 #endif
3487
3488 #ifdef LIBXML_PATTERN_ENABLED
3489 #ifdef LIBXML_READER_ENABLED
3490 /************************************************************************
3491 * *
3492 * Patterns tests *
3493 * *
3494 ************************************************************************/
patternNode(FILE * out,xmlTextReaderPtr reader,const char * pattern,xmlPatternPtr patternc,xmlStreamCtxtPtr patstream)3495 static void patternNode(FILE *out, xmlTextReaderPtr reader,
3496 const char *pattern, xmlPatternPtr patternc,
3497 xmlStreamCtxtPtr patstream) {
3498 xmlChar *path = NULL;
3499 int match = -1;
3500 int type, empty;
3501
3502 type = xmlTextReaderNodeType(reader);
3503 empty = xmlTextReaderIsEmptyElement(reader);
3504
3505 if (type == XML_READER_TYPE_ELEMENT) {
3506 /* do the check only on element start */
3507 match = xmlPatternMatch(patternc, xmlTextReaderCurrentNode(reader));
3508
3509 if (match) {
3510 path = xmlGetNodePath(xmlTextReaderCurrentNode(reader));
3511 fprintf(out, "Node %s matches pattern %s\n", path, pattern);
3512 }
3513 }
3514 if (patstream != NULL) {
3515 int ret;
3516
3517 if (type == XML_READER_TYPE_ELEMENT) {
3518 ret = xmlStreamPush(patstream,
3519 xmlTextReaderConstLocalName(reader),
3520 xmlTextReaderConstNamespaceUri(reader));
3521 if (ret < 0) {
3522 fprintf(out, "xmlStreamPush() failure\n");
3523 xmlFreeStreamCtxt(patstream);
3524 patstream = NULL;
3525 } else if (ret != match) {
3526 if (path == NULL) {
3527 path = xmlGetNodePath(
3528 xmlTextReaderCurrentNode(reader));
3529 }
3530 fprintf(out,
3531 "xmlPatternMatch and xmlStreamPush disagree\n");
3532 fprintf(out,
3533 " pattern %s node %s\n",
3534 pattern, path);
3535 }
3536
3537
3538 }
3539 if ((type == XML_READER_TYPE_END_ELEMENT) ||
3540 ((type == XML_READER_TYPE_ELEMENT) && (empty))) {
3541 ret = xmlStreamPop(patstream);
3542 if (ret < 0) {
3543 fprintf(out, "xmlStreamPop() failure\n");
3544 xmlFreeStreamCtxt(patstream);
3545 patstream = NULL;
3546 }
3547 }
3548 }
3549 if (path != NULL)
3550 xmlFree(path);
3551 }
3552
3553 /**
3554 * patternTest:
3555 * @filename: the schemas file
3556 * @result: the file with expected result
3557 * @err: the file with error messages
3558 *
3559 * Parse a set of files with streaming, applying an RNG schemas
3560 *
3561 * Returns 0 in case of success, an error code otherwise
3562 */
3563 static int
patternTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options)3564 patternTest(const char *filename,
3565 const char *resul ATTRIBUTE_UNUSED,
3566 const char *err ATTRIBUTE_UNUSED,
3567 int options) {
3568 xmlPatternPtr patternc = NULL;
3569 xmlStreamCtxtPtr patstream = NULL;
3570 FILE *o, *f;
3571 char str[1024];
3572 char xml[500];
3573 char result[500];
3574 int len, i;
3575 int ret = 0, res;
3576 char *temp;
3577 xmlTextReaderPtr reader;
3578 xmlDocPtr doc;
3579
3580 len = strlen(filename);
3581 len -= 4;
3582 memcpy(xml, filename, len);
3583 xml[len] = 0;
3584 if (snprintf(result, 499, "result/pattern/%s", baseFilename(xml)) >= 499)
3585 result[499] = 0;
3586 memcpy(xml + len, ".xml", 5);
3587
3588 if (!checkTestFile(xml) && !update_results) {
3589 fprintf(stderr, "Missing xml file %s\n", xml);
3590 return(-1);
3591 }
3592 if (!checkTestFile(result) && !update_results) {
3593 fprintf(stderr, "Missing result file %s\n", result);
3594 return(-1);
3595 }
3596 f = fopen(filename, "rb");
3597 if (f == NULL) {
3598 fprintf(stderr, "Failed to open %s\n", filename);
3599 return(-1);
3600 }
3601 temp = resultFilename(filename, temp_directory, ".res");
3602 if (temp == NULL) {
3603 fprintf(stderr, "Out of memory\n");
3604 fatalError();
3605 }
3606 o = fopen(temp, "wb");
3607 if (o == NULL) {
3608 fprintf(stderr, "failed to open output file %s\n", temp);
3609 fclose(f);
3610 free(temp);
3611 return(-1);
3612 }
3613 while (1) {
3614 /*
3615 * read one line in string buffer.
3616 */
3617 if (fgets (&str[0], sizeof (str) - 1, f) == NULL)
3618 break;
3619
3620 /*
3621 * remove the ending spaces
3622 */
3623 i = strlen(str);
3624 while ((i > 0) &&
3625 ((str[i - 1] == '\n') || (str[i - 1] == '\r') ||
3626 (str[i - 1] == ' ') || (str[i - 1] == '\t'))) {
3627 i--;
3628 str[i] = 0;
3629 }
3630 doc = xmlReadFile(xml, NULL, options);
3631 if (doc == NULL) {
3632 fprintf(stderr, "Failed to parse %s\n", xml);
3633 ret = 1;
3634 } else {
3635 xmlNodePtr root;
3636 const xmlChar *namespaces[22];
3637 int j;
3638 xmlNsPtr ns;
3639
3640 root = xmlDocGetRootElement(doc);
3641 for (ns = root->nsDef, j = 0;ns != NULL && j < 20;ns=ns->next) {
3642 namespaces[j++] = ns->href;
3643 namespaces[j++] = ns->prefix;
3644 }
3645 namespaces[j++] = NULL;
3646 namespaces[j] = NULL;
3647
3648 patternc = xmlPatterncompile((const xmlChar *) str, doc->dict,
3649 0, &namespaces[0]);
3650 if (patternc == NULL) {
3651 testErrorHandler(NULL,
3652 "Pattern %s failed to compile\n", str);
3653 xmlFreeDoc(doc);
3654 ret = 1;
3655 continue;
3656 }
3657 patstream = xmlPatternGetStreamCtxt(patternc);
3658 if (patstream != NULL) {
3659 ret = xmlStreamPush(patstream, NULL, NULL);
3660 if (ret < 0) {
3661 fprintf(stderr, "xmlStreamPush() failure\n");
3662 xmlFreeStreamCtxt(patstream);
3663 patstream = NULL;
3664 }
3665 }
3666 nb_tests++;
3667
3668 reader = xmlReaderWalker(doc);
3669 res = xmlTextReaderRead(reader);
3670 while (res == 1) {
3671 patternNode(o, reader, str, patternc, patstream);
3672 res = xmlTextReaderRead(reader);
3673 }
3674 if (res != 0) {
3675 fprintf(o, "%s : failed to parse\n", filename);
3676 }
3677 xmlFreeTextReader(reader);
3678 xmlFreeDoc(doc);
3679 xmlFreeStreamCtxt(patstream);
3680 patstream = NULL;
3681 xmlFreePattern(patternc);
3682
3683 }
3684 }
3685
3686 fclose(f);
3687 fclose(o);
3688
3689 ret = compareFiles(temp, result);
3690 if (ret) {
3691 fprintf(stderr, "Result for %s failed in %s\n", filename, result);
3692 ret = 1;
3693 }
3694 if (temp != NULL) {
3695 unlink(temp);
3696 free(temp);
3697 }
3698 return(ret);
3699 }
3700 #endif /* READER */
3701 #endif /* PATTERN */
3702 #ifdef LIBXML_C14N_ENABLED
3703 /************************************************************************
3704 * *
3705 * Canonicalization tests *
3706 * *
3707 ************************************************************************/
3708 static xmlXPathObjectPtr
load_xpath_expr(xmlDocPtr parent_doc,const char * filename)3709 load_xpath_expr (xmlDocPtr parent_doc, const char* filename) {
3710 xmlXPathObjectPtr xpath;
3711 xmlDocPtr doc;
3712 xmlChar *expr;
3713 xmlXPathContextPtr ctx;
3714 xmlNodePtr node;
3715 xmlNsPtr ns;
3716
3717 /*
3718 * load XPath expr as a file
3719 */
3720 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3721 xmlSubstituteEntitiesDefault(1);
3722
3723 doc = xmlReadFile(filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
3724 if (doc == NULL) {
3725 fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
3726 return(NULL);
3727 }
3728
3729 /*
3730 * Check the document is of the right kind
3731 */
3732 if(xmlDocGetRootElement(doc) == NULL) {
3733 fprintf(stderr,"Error: empty document for file \"%s\"\n", filename);
3734 xmlFreeDoc(doc);
3735 return(NULL);
3736 }
3737
3738 node = doc->children;
3739 while(node != NULL && !xmlStrEqual(node->name, (const xmlChar *)"XPath")) {
3740 node = node->next;
3741 }
3742
3743 if(node == NULL) {
3744 fprintf(stderr,"Error: XPath element expected in the file \"%s\"\n", filename);
3745 xmlFreeDoc(doc);
3746 return(NULL);
3747 }
3748
3749 expr = xmlNodeGetContent(node);
3750 if(expr == NULL) {
3751 fprintf(stderr,"Error: XPath content element is NULL \"%s\"\n", filename);
3752 xmlFreeDoc(doc);
3753 return(NULL);
3754 }
3755
3756 ctx = xmlXPathNewContext(parent_doc);
3757 if(ctx == NULL) {
3758 fprintf(stderr,"Error: unable to create new context\n");
3759 xmlFree(expr);
3760 xmlFreeDoc(doc);
3761 return(NULL);
3762 }
3763
3764 /*
3765 * Register namespaces
3766 */
3767 ns = node->nsDef;
3768 while(ns != NULL) {
3769 if(xmlXPathRegisterNs(ctx, ns->prefix, ns->href) != 0) {
3770 fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", ns->prefix, ns->href);
3771 xmlFree(expr);
3772 xmlXPathFreeContext(ctx);
3773 xmlFreeDoc(doc);
3774 return(NULL);
3775 }
3776 ns = ns->next;
3777 }
3778
3779 /*
3780 * Evaluate xpath
3781 */
3782 xpath = xmlXPathEvalExpression(expr, ctx);
3783 if(xpath == NULL) {
3784 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3785 xmlFree(expr);
3786 xmlXPathFreeContext(ctx);
3787 xmlFreeDoc(doc);
3788 return(NULL);
3789 }
3790
3791 /* print_xpath_nodes(xpath->nodesetval); */
3792
3793 xmlFree(expr);
3794 xmlXPathFreeContext(ctx);
3795 xmlFreeDoc(doc);
3796 return(xpath);
3797 }
3798
3799 /*
3800 * Macro used to grow the current buffer.
3801 */
3802 #define xxx_growBufferReentrant() { \
3803 buffer_size *= 2; \
3804 buffer = (xmlChar **) \
3805 xmlRealloc(buffer, buffer_size * sizeof(xmlChar*)); \
3806 if (buffer == NULL) { \
3807 perror("realloc failed"); \
3808 return(NULL); \
3809 } \
3810 }
3811
3812 static xmlChar **
parse_list(xmlChar * str)3813 parse_list(xmlChar *str) {
3814 xmlChar **buffer;
3815 xmlChar **out = NULL;
3816 int buffer_size = 0;
3817 int len;
3818
3819 if(str == NULL) {
3820 return(NULL);
3821 }
3822
3823 len = xmlStrlen(str);
3824 if((str[0] == '\'') && (str[len - 1] == '\'')) {
3825 str[len - 1] = '\0';
3826 str++;
3827 }
3828 /*
3829 * allocate an translation buffer.
3830 */
3831 buffer_size = 1000;
3832 buffer = (xmlChar **) xmlMalloc(buffer_size * sizeof(xmlChar*));
3833 if (buffer == NULL) {
3834 perror("malloc failed");
3835 return(NULL);
3836 }
3837 out = buffer;
3838
3839 while(*str != '\0') {
3840 if (out - buffer > buffer_size - 10) {
3841 int indx = out - buffer;
3842
3843 xxx_growBufferReentrant();
3844 out = &buffer[indx];
3845 }
3846 (*out++) = str;
3847 while(*str != ',' && *str != '\0') ++str;
3848 if(*str == ',') *(str++) = '\0';
3849 }
3850 (*out) = NULL;
3851 return buffer;
3852 }
3853
3854 static int
c14nRunTest(const char * xml_filename,int with_comments,int mode,const char * xpath_filename,const char * ns_filename,const char * result_file)3855 c14nRunTest(const char* xml_filename, int with_comments, int mode,
3856 const char* xpath_filename, const char *ns_filename,
3857 const char* result_file) {
3858 xmlDocPtr doc;
3859 xmlXPathObjectPtr xpath = NULL;
3860 xmlChar *result = NULL;
3861 int ret;
3862 xmlChar **inclusive_namespaces = NULL;
3863 const char *nslist = NULL;
3864 int nssize;
3865
3866
3867 /*
3868 * build an XML tree from a the file; we need to add default
3869 * attributes and resolve all character and entities references
3870 */
3871 xmlLoadExtDtdDefaultValue = XML_DETECT_IDS | XML_COMPLETE_ATTRS;
3872 xmlSubstituteEntitiesDefault(1);
3873
3874 doc = xmlReadFile(xml_filename, NULL, XML_PARSE_DTDATTR | XML_PARSE_NOENT);
3875 if (doc == NULL) {
3876 fprintf(stderr, "Error: unable to parse file \"%s\"\n", xml_filename);
3877 return(-1);
3878 }
3879
3880 /*
3881 * Check the document is of the right kind
3882 */
3883 if(xmlDocGetRootElement(doc) == NULL) {
3884 fprintf(stderr,"Error: empty document for file \"%s\"\n", xml_filename);
3885 xmlFreeDoc(doc);
3886 return(-1);
3887 }
3888
3889 /*
3890 * load xpath file if specified
3891 */
3892 if(xpath_filename) {
3893 xpath = load_xpath_expr(doc, xpath_filename);
3894 if(xpath == NULL) {
3895 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3896 xmlFreeDoc(doc);
3897 return(-1);
3898 }
3899 }
3900
3901 if (ns_filename != NULL) {
3902 if (loadMem(ns_filename, &nslist, &nssize)) {
3903 fprintf(stderr,"Error: unable to evaluate xpath expression\n");
3904 if(xpath != NULL) xmlXPathFreeObject(xpath);
3905 xmlFreeDoc(doc);
3906 return(-1);
3907 }
3908 inclusive_namespaces = parse_list((xmlChar *) nslist);
3909 }
3910
3911 /*
3912 * Canonical form
3913 */
3914 /* fprintf(stderr,"File \"%s\" loaded: start canonization\n", xml_filename); */
3915 ret = xmlC14NDocDumpMemory(doc,
3916 (xpath) ? xpath->nodesetval : NULL,
3917 mode, inclusive_namespaces,
3918 with_comments, &result);
3919 if (ret >= 0) {
3920 if(result != NULL) {
3921 if (compareFileMem(result_file, (const char *) result, ret)) {
3922 fprintf(stderr, "Result mismatch for %s\n", xml_filename);
3923 fprintf(stderr, "RESULT:\n%s\n", (const char*)result);
3924 ret = -1;
3925 }
3926 }
3927 } else {
3928 fprintf(stderr,"Error: failed to canonicalize XML file \"%s\" (ret=%d)\n", xml_filename, ret);
3929 ret = -1;
3930 }
3931
3932 /*
3933 * Cleanup
3934 */
3935 if (result != NULL) xmlFree(result);
3936 if(xpath != NULL) xmlXPathFreeObject(xpath);
3937 if (inclusive_namespaces != NULL) xmlFree(inclusive_namespaces);
3938 if (nslist != NULL) free((char *) nslist);
3939 xmlFreeDoc(doc);
3940
3941 return(ret);
3942 }
3943
3944 static int
c14nCommonTest(const char * filename,int with_comments,int mode,const char * subdir)3945 c14nCommonTest(const char *filename, int with_comments, int mode,
3946 const char *subdir) {
3947 char buf[500];
3948 char prefix[500];
3949 const char *base;
3950 int len;
3951 char *result = NULL;
3952 char *xpath = NULL;
3953 char *ns = NULL;
3954 int ret = 0;
3955
3956 base = baseFilename(filename);
3957 len = strlen(base);
3958 len -= 4;
3959 memcpy(prefix, base, len);
3960 prefix[len] = 0;
3961
3962 if (snprintf(buf, 499, "result/c14n/%s/%s", subdir, prefix) >= 499)
3963 buf[499] = 0;
3964 if (!checkTestFile(buf) && !update_results) {
3965 fprintf(stderr, "Missing result file %s", buf);
3966 return(-1);
3967 }
3968 result = strdup(buf);
3969 if (snprintf(buf, 499, "test/c14n/%s/%s.xpath", subdir, prefix) >= 499)
3970 buf[499] = 0;
3971 if (checkTestFile(buf)) {
3972 xpath = strdup(buf);
3973 }
3974 if (snprintf(buf, 499, "test/c14n/%s/%s.ns", subdir, prefix) >= 499)
3975 buf[499] = 0;
3976 if (checkTestFile(buf)) {
3977 ns = strdup(buf);
3978 }
3979
3980 nb_tests++;
3981 if (c14nRunTest(filename, with_comments, mode,
3982 xpath, ns, result) < 0)
3983 ret = 1;
3984
3985 if (result != NULL) free(result);
3986 if (xpath != NULL) free(xpath);
3987 if (ns != NULL) free(ns);
3988 return(ret);
3989 }
3990
3991 static int
c14nWithCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)3992 c14nWithCommentTest(const char *filename,
3993 const char *resul ATTRIBUTE_UNUSED,
3994 const char *err ATTRIBUTE_UNUSED,
3995 int options ATTRIBUTE_UNUSED) {
3996 return(c14nCommonTest(filename, 1, XML_C14N_1_0, "with-comments"));
3997 }
3998 static int
c14nWithoutCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)3999 c14nWithoutCommentTest(const char *filename,
4000 const char *resul ATTRIBUTE_UNUSED,
4001 const char *err ATTRIBUTE_UNUSED,
4002 int options ATTRIBUTE_UNUSED) {
4003 return(c14nCommonTest(filename, 0, XML_C14N_1_0, "without-comments"));
4004 }
4005 static int
c14nExcWithoutCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)4006 c14nExcWithoutCommentTest(const char *filename,
4007 const char *resul ATTRIBUTE_UNUSED,
4008 const char *err ATTRIBUTE_UNUSED,
4009 int options ATTRIBUTE_UNUSED) {
4010 return(c14nCommonTest(filename, 0, XML_C14N_EXCLUSIVE_1_0, "exc-without-comments"));
4011 }
4012 static int
c14n11WithoutCommentTest(const char * filename,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)4013 c14n11WithoutCommentTest(const char *filename,
4014 const char *resul ATTRIBUTE_UNUSED,
4015 const char *err ATTRIBUTE_UNUSED,
4016 int options ATTRIBUTE_UNUSED) {
4017 return(c14nCommonTest(filename, 0, XML_C14N_1_1, "1-1-without-comments"));
4018 }
4019 #endif
4020 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
4021 /************************************************************************
4022 * *
4023 * Catalog and threads test *
4024 * *
4025 ************************************************************************/
4026
4027 /*
4028 * mostly a cut and paste from testThreads.c
4029 */
4030 #define MAX_ARGC 20
4031
4032 typedef struct {
4033 const char *filename;
4034 int okay;
4035 } xmlThreadParams;
4036
4037 static const char *catalog = "test/threads/complex.xml";
4038 static xmlThreadParams threadParams[] = {
4039 { "test/threads/abc.xml", 0 },
4040 { "test/threads/acb.xml", 0 },
4041 { "test/threads/bac.xml", 0 },
4042 { "test/threads/bca.xml", 0 },
4043 { "test/threads/cab.xml", 0 },
4044 { "test/threads/cba.xml", 0 },
4045 { "test/threads/invalid.xml", 0 }
4046 };
4047 static const unsigned int num_threads = sizeof(threadParams) /
4048 sizeof(threadParams[0]);
4049
4050 #ifndef xmlDoValidityCheckingDefaultValue
4051 #error xmlDoValidityCheckingDefaultValue is not a macro
4052 #endif
4053 #ifndef xmlGenericErrorContext
4054 #error xmlGenericErrorContext is not a macro
4055 #endif
4056
4057 static void *
thread_specific_data(void * private_data)4058 thread_specific_data(void *private_data)
4059 {
4060 xmlDocPtr myDoc;
4061 xmlThreadParams *params = (xmlThreadParams *) private_data;
4062 const char *filename = params->filename;
4063 int okay = 1;
4064
4065 if (!strcmp(filename, "test/threads/invalid.xml")) {
4066 xmlDoValidityCheckingDefaultValue = 0;
4067 xmlGenericErrorContext = stdout;
4068 } else {
4069 xmlDoValidityCheckingDefaultValue = 1;
4070 xmlGenericErrorContext = stderr;
4071 }
4072 #ifdef LIBXML_SAX1_ENABLED
4073 myDoc = xmlParseFile(filename);
4074 #else
4075 myDoc = xmlReadFile(filename, NULL, XML_WITH_CATALOG);
4076 #endif
4077 if (myDoc) {
4078 xmlFreeDoc(myDoc);
4079 } else {
4080 printf("parse failed\n");
4081 okay = 0;
4082 }
4083 if (!strcmp(filename, "test/threads/invalid.xml")) {
4084 if (xmlDoValidityCheckingDefaultValue != 0) {
4085 printf("ValidityCheckingDefaultValue override failed\n");
4086 okay = 0;
4087 }
4088 if (xmlGenericErrorContext != stdout) {
4089 printf("xmlGenericErrorContext override failed\n");
4090 okay = 0;
4091 }
4092 } else {
4093 if (xmlDoValidityCheckingDefaultValue != 1) {
4094 printf("ValidityCheckingDefaultValue override failed\n");
4095 okay = 0;
4096 }
4097 if (xmlGenericErrorContext != stderr) {
4098 printf("xmlGenericErrorContext override failed\n");
4099 okay = 0;
4100 }
4101 }
4102 params->okay = okay;
4103 return(NULL);
4104 }
4105
4106 #if defined(_WIN32) && !defined(__CYGWIN__)
4107 #include <windows.h>
4108 #include <string.h>
4109
4110 #define TEST_REPEAT_COUNT 500
4111
4112 static HANDLE tid[MAX_ARGC];
4113
4114 static DWORD WINAPI
win32_thread_specific_data(void * private_data)4115 win32_thread_specific_data(void *private_data)
4116 {
4117 thread_specific_data(private_data);
4118 return(0);
4119 }
4120
4121 static int
testThread(void)4122 testThread(void)
4123 {
4124 unsigned int i, repeat;
4125 BOOL ret;
4126 int res = 0;
4127
4128 xmlInitParser();
4129 for (repeat = 0; repeat < TEST_REPEAT_COUNT; repeat++) {
4130 xmlLoadCatalog(catalog);
4131 nb_tests++;
4132
4133 for (i = 0; i < num_threads; i++) {
4134 tid[i] = (HANDLE) - 1;
4135 }
4136
4137 for (i = 0; i < num_threads; i++) {
4138 DWORD useless;
4139
4140 tid[i] = CreateThread(NULL, 0,
4141 win32_thread_specific_data,
4142 (void *) &threadParams[i], 0,
4143 &useless);
4144 if (tid[i] == NULL) {
4145 fprintf(stderr, "CreateThread failed\n");
4146 return(1);
4147 }
4148 }
4149
4150 if (WaitForMultipleObjects(num_threads, tid, TRUE, INFINITE) ==
4151 WAIT_FAILED) {
4152 fprintf(stderr, "WaitForMultipleObjects failed\n");
4153 return(1);
4154 }
4155
4156 for (i = 0; i < num_threads; i++) {
4157 DWORD exitCode;
4158 ret = GetExitCodeThread(tid[i], &exitCode);
4159 if (ret == 0) {
4160 fprintf(stderr, "GetExitCodeThread failed\n");
4161 return(1);
4162 }
4163 CloseHandle(tid[i]);
4164 }
4165
4166 xmlCatalogCleanup();
4167 for (i = 0; i < num_threads; i++) {
4168 if (threadParams[i].okay == 0) {
4169 fprintf(stderr, "Thread %d handling %s failed\n",
4170 i, threadParams[i].filename);
4171 res = 1;
4172 }
4173 }
4174 }
4175
4176 return (res);
4177 }
4178
4179 #elif defined __BEOS__
4180 #include <OS.h>
4181
4182 static thread_id tid[MAX_ARGC];
4183
4184 static int
testThread(void)4185 testThread(void)
4186 {
4187 unsigned int i, repeat;
4188 status_t ret;
4189 int res = 0;
4190
4191 xmlInitParser();
4192 for (repeat = 0; repeat < 500; repeat++) {
4193 xmlLoadCatalog(catalog);
4194 for (i = 0; i < num_threads; i++) {
4195 tid[i] = (thread_id) - 1;
4196 }
4197 for (i = 0; i < num_threads; i++) {
4198 tid[i] =
4199 spawn_thread(thread_specific_data, "xmlTestThread",
4200 B_NORMAL_PRIORITY, (void *) &threadParams[i]);
4201 if (tid[i] < B_OK) {
4202 fprintf(stderr, "beos_thread_create failed\n");
4203 return (1);
4204 }
4205 printf("beos_thread_create %d -> %d\n", i, tid[i]);
4206 }
4207 for (i = 0; i < num_threads; i++) {
4208 void *result;
4209 ret = wait_for_thread(tid[i], &result);
4210 printf("beos_thread_wait %d -> %d\n", i, ret);
4211 if (ret != B_OK) {
4212 fprintf(stderr, "beos_thread_wait failed\n");
4213 return (1);
4214 }
4215 }
4216
4217 xmlCatalogCleanup();
4218 ret = B_OK;
4219 for (i = 0; i < num_threads; i++)
4220 if (threadParams[i].okay == 0) {
4221 printf("Thread %d handling %s failed\n", i,
4222 threadParams[i].filename);
4223 ret = B_ERROR;
4224 }
4225 }
4226 if (ret != B_OK)
4227 return(1);
4228 return (0);
4229 }
4230
4231 #elif defined HAVE_PTHREAD_H
4232 #include <pthread.h>
4233
4234 static pthread_t tid[MAX_ARGC];
4235
4236 static int
testThread(void)4237 testThread(void)
4238 {
4239 unsigned int i, repeat;
4240 int ret;
4241 int res = 0;
4242
4243 xmlInitParser();
4244
4245 for (repeat = 0; repeat < 500; repeat++) {
4246 xmlLoadCatalog(catalog);
4247 nb_tests++;
4248
4249 for (i = 0; i < num_threads; i++) {
4250 tid[i] = (pthread_t) - 1;
4251 }
4252
4253 for (i = 0; i < num_threads; i++) {
4254 ret = pthread_create(&tid[i], 0, thread_specific_data,
4255 (void *) &threadParams[i]);
4256 if (ret != 0) {
4257 fprintf(stderr, "pthread_create failed\n");
4258 return (1);
4259 }
4260 }
4261 for (i = 0; i < num_threads; i++) {
4262 void *result;
4263 ret = pthread_join(tid[i], &result);
4264 if (ret != 0) {
4265 fprintf(stderr, "pthread_join failed\n");
4266 return (1);
4267 }
4268 }
4269
4270 xmlCatalogCleanup();
4271 for (i = 0; i < num_threads; i++)
4272 if (threadParams[i].okay == 0) {
4273 fprintf(stderr, "Thread %d handling %s failed\n",
4274 i, threadParams[i].filename);
4275 res = 1;
4276 }
4277 }
4278 return (res);
4279 }
4280
4281 #else
4282 static int
testThread(void)4283 testThread(void)
4284 {
4285 fprintf(stderr,
4286 "Specific platform thread support not detected\n");
4287 return (-1);
4288 }
4289 #endif
4290 static int
threadsTest(const char * filename ATTRIBUTE_UNUSED,const char * resul ATTRIBUTE_UNUSED,const char * err ATTRIBUTE_UNUSED,int options ATTRIBUTE_UNUSED)4291 threadsTest(const char *filename ATTRIBUTE_UNUSED,
4292 const char *resul ATTRIBUTE_UNUSED,
4293 const char *err ATTRIBUTE_UNUSED,
4294 int options ATTRIBUTE_UNUSED) {
4295 return(testThread());
4296 }
4297 #endif
4298 /************************************************************************
4299 * *
4300 * Tests Descriptions *
4301 * *
4302 ************************************************************************/
4303
4304 static
4305 testDesc testDescriptions[] = {
4306 { "XML regression tests" ,
4307 oldParseTest, "./test/*", "result/", "", NULL,
4308 0 },
4309 { "XML regression tests on memory" ,
4310 memParseTest, "./test/*", "result/", "", NULL,
4311 0 },
4312 { "XML entity subst regression tests" ,
4313 noentParseTest, "./test/*", "result/noent/", "", NULL,
4314 XML_PARSE_NOENT },
4315 { "XML Namespaces regression tests",
4316 errParseTest, "./test/namespaces/*", "result/namespaces/", "", ".err",
4317 0 },
4318 { "Error cases regression tests",
4319 errParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4320 0 },
4321 { "Error cases regression tests from file descriptor",
4322 fdParseTest, "./test/errors/*.xml", "result/errors/", "", ".err",
4323 0 },
4324 { "Error cases regression tests with entity substitution",
4325 errParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".ent",
4326 XML_PARSE_NOENT },
4327 { "Error cases regression tests (old 1.0)",
4328 errParseTest, "./test/errors10/*.xml", "result/errors10/", "", ".err",
4329 XML_PARSE_OLD10 },
4330 #ifdef LIBXML_READER_ENABLED
4331 { "Error cases stream regression tests",
4332 streamParseTest, "./test/errors/*.xml", "result/errors/", NULL, ".str",
4333 0 },
4334 { "Reader regression tests",
4335 streamParseTest, "./test/*", "result/", ".rdr", NULL,
4336 0 },
4337 { "Reader entities substitution regression tests",
4338 streamParseTest, "./test/*", "result/", ".rde", NULL,
4339 XML_PARSE_NOENT },
4340 { "Reader on memory regression tests",
4341 streamMemParseTest, "./test/*", "result/", ".rdr", NULL,
4342 0 },
4343 { "Walker regression tests",
4344 walkerParseTest, "./test/*", "result/", ".rdr", NULL,
4345 0 },
4346 #endif
4347 #ifdef LIBXML_SAX1_ENABLED
4348 { "SAX1 callbacks regression tests" ,
4349 saxParseTest, "./test/*", "result/", ".sax", NULL,
4350 XML_PARSE_SAX1 },
4351 #endif
4352 { "SAX2 callbacks regression tests" ,
4353 saxParseTest, "./test/*", "result/", ".sax2", NULL,
4354 0 },
4355 { "SAX2 callbacks regression tests with entity substitution" ,
4356 saxParseTest, "./test/*", "result/noent/", ".sax2", NULL,
4357 XML_PARSE_NOENT },
4358 #ifdef LIBXML_PUSH_ENABLED
4359 { "XML push regression tests" ,
4360 pushParseTest, "./test/*", "result/", "", NULL,
4361 0 },
4362 #endif
4363 #ifdef LIBXML_HTML_ENABLED
4364 { "HTML regression tests" ,
4365 errParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4366 XML_PARSE_HTML },
4367 { "HTML regression tests from file descriptor",
4368 fdParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4369 XML_PARSE_HTML },
4370 #ifdef LIBXML_PUSH_ENABLED
4371 { "Push HTML regression tests" ,
4372 pushParseTest, "./test/HTML/*", "result/HTML/", "", ".err",
4373 XML_PARSE_HTML },
4374 #endif
4375 { "HTML SAX regression tests" ,
4376 saxParseTest, "./test/HTML/*", "result/HTML/", ".sax", NULL,
4377 XML_PARSE_HTML },
4378 #endif
4379 #ifdef LIBXML_VALID_ENABLED
4380 { "Valid documents regression tests" ,
4381 errParseTest, "./test/VCM/*", NULL, NULL, NULL,
4382 XML_PARSE_DTDVALID },
4383 { "Validity checking regression tests" ,
4384 errParseTest, "./test/VC/*", "result/VC/", NULL, "",
4385 XML_PARSE_DTDVALID },
4386 #ifdef LIBXML_READER_ENABLED
4387 { "Streaming validity checking regression tests" ,
4388 streamParseTest, "./test/valid/*.xml", "result/valid/", NULL, ".err.rdr",
4389 XML_PARSE_DTDVALID },
4390 { "Streaming validity error checking regression tests" ,
4391 streamParseTest, "./test/VC/*", "result/VC/", NULL, ".rdr",
4392 XML_PARSE_DTDVALID },
4393 #endif
4394 { "General documents valid regression tests" ,
4395 errParseTest, "./test/valid/*", "result/valid/", "", ".err",
4396 XML_PARSE_DTDVALID },
4397 #endif
4398 #ifdef LIBXML_XINCLUDE_ENABLED
4399 { "XInclude regression tests" ,
4400 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4401 /* Ignore errors at this point ".err", */
4402 XML_PARSE_XINCLUDE },
4403 #ifdef LIBXML_READER_ENABLED
4404 { "XInclude xmlReader regression tests",
4405 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4406 /* Ignore errors at this point ".err", */
4407 NULL, XML_PARSE_XINCLUDE },
4408 #endif
4409 { "XInclude regression tests stripping include nodes" ,
4410 errParseTest, "./test/XInclude/docs/*", "result/XInclude/", "", NULL,
4411 /* Ignore errors at this point ".err", */
4412 XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4413 #ifdef LIBXML_READER_ENABLED
4414 { "XInclude xmlReader regression tests stripping include nodes",
4415 streamParseTest, "./test/XInclude/docs/*", "result/XInclude/", ".rdr",
4416 /* Ignore errors at this point ".err", */
4417 NULL, XML_PARSE_XINCLUDE | XML_PARSE_NOXINCNODE },
4418 #endif
4419 #endif
4420 #ifdef LIBXML_XPATH_ENABLED
4421 #ifdef LIBXML_DEBUG_ENABLED
4422 { "XPath expressions regression tests" ,
4423 xpathExprTest, "./test/XPath/expr/*", "result/XPath/expr/", "", NULL,
4424 0 },
4425 { "XPath document queries regression tests" ,
4426 xpathDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4427 0 },
4428 #ifdef LIBXML_XPTR_ENABLED
4429 { "XPointer document queries regression tests" ,
4430 xptrDocTest, "./test/XPath/docs/*", NULL, NULL, NULL,
4431 0 },
4432 #endif
4433 { "xml:id regression tests" ,
4434 xmlidDocTest, "./test/xmlid/*", "result/xmlid/", "", ".err",
4435 0 },
4436 #endif
4437 #endif
4438 { "URI parsing tests" ,
4439 uriParseTest, "./test/URI/*.uri", "result/URI/", "", NULL,
4440 0 },
4441 { "URI base composition tests" ,
4442 uriBaseTest, "./test/URI/*.data", "result/URI/", "", NULL,
4443 0 },
4444 { "Path URI conversion tests" ,
4445 uriPathTest, NULL, NULL, NULL, NULL,
4446 0 },
4447 #ifdef LIBXML_SCHEMAS_ENABLED
4448 { "Schemas regression tests" ,
4449 schemasTest, "./test/schemas/*_*.xsd", NULL, NULL, NULL,
4450 0 },
4451 { "Relax-NG regression tests" ,
4452 rngTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4453 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4454 #ifdef LIBXML_READER_ENABLED
4455 { "Relax-NG streaming regression tests" ,
4456 rngStreamTest, "./test/relaxng/*.rng", NULL, NULL, NULL,
4457 XML_PARSE_DTDATTR | XML_PARSE_NOENT },
4458 #endif
4459 #endif
4460 #ifdef LIBXML_PATTERN_ENABLED
4461 #ifdef LIBXML_READER_ENABLED
4462 { "Pattern regression tests" ,
4463 patternTest, "./test/pattern/*.pat", "result/pattern/", NULL, NULL,
4464 0 },
4465 #endif
4466 #endif
4467 #ifdef LIBXML_C14N_ENABLED
4468 { "C14N with comments regression tests" ,
4469 c14nWithCommentTest, "./test/c14n/with-comments/*.xml", NULL, NULL, NULL,
4470 0 },
4471 { "C14N without comments regression tests" ,
4472 c14nWithoutCommentTest, "./test/c14n/without-comments/*.xml", NULL, NULL, NULL,
4473 0 },
4474 { "C14N exclusive without comments regression tests" ,
4475 c14nExcWithoutCommentTest, "./test/c14n/exc-without-comments/*.xml", NULL, NULL, NULL,
4476 0 },
4477 { "C14N 1.1 without comments regression tests" ,
4478 c14n11WithoutCommentTest, "./test/c14n/1-1-without-comments/*.xml", NULL, NULL, NULL,
4479 0 },
4480 #endif
4481 #if defined(LIBXML_THREAD_ENABLED) && defined(LIBXML_CATALOG_ENABLED)
4482 { "Catalog and Threads regression tests" ,
4483 threadsTest, NULL, NULL, NULL, NULL,
4484 0 },
4485 #endif
4486 {NULL, NULL, NULL, NULL, NULL, NULL, 0}
4487 };
4488
4489 /************************************************************************
4490 * *
4491 * The main code driving the tests *
4492 * *
4493 ************************************************************************/
4494
4495 static int
launchTests(testDescPtr tst)4496 launchTests(testDescPtr tst) {
4497 int res = 0, err = 0;
4498 size_t i;
4499 char *result;
4500 char *error;
4501 int mem;
4502 xmlCharEncodingHandlerPtr ebcdicHandler, eucJpHandler;
4503
4504 ebcdicHandler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EBCDIC);
4505 eucJpHandler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_EUC_JP);
4506
4507 if (tst == NULL) return(-1);
4508 if (tst->in != NULL) {
4509 glob_t globbuf;
4510
4511 globbuf.gl_offs = 0;
4512 glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
4513 for (i = 0;i < globbuf.gl_pathc;i++) {
4514 if (!checkTestFile(globbuf.gl_pathv[i]))
4515 continue;
4516 if (((ebcdicHandler == NULL) &&
4517 (strstr(globbuf.gl_pathv[i], "ebcdic") != NULL)) ||
4518 ((eucJpHandler == NULL) &&
4519 (strstr(globbuf.gl_pathv[i], "icu_parse_test") != NULL)))
4520 continue;
4521 if (tst->suffix != NULL) {
4522 result = resultFilename(globbuf.gl_pathv[i], tst->out,
4523 tst->suffix);
4524 if (result == NULL) {
4525 fprintf(stderr, "Out of memory !\n");
4526 fatalError();
4527 }
4528 } else {
4529 result = NULL;
4530 }
4531 if (tst->err != NULL) {
4532 error = resultFilename(globbuf.gl_pathv[i], tst->out,
4533 tst->err);
4534 if (error == NULL) {
4535 fprintf(stderr, "Out of memory !\n");
4536 fatalError();
4537 }
4538 } else {
4539 error = NULL;
4540 }
4541 if ((result) &&(!checkTestFile(result)) && !update_results) {
4542 fprintf(stderr, "Missing result file %s\n", result);
4543 } else if ((error) &&(!checkTestFile(error)) && !update_results) {
4544 fprintf(stderr, "Missing error file %s\n", error);
4545 } else {
4546 mem = xmlMemUsed();
4547 extraMemoryFromResolver = 0;
4548 testErrorsSize = 0;
4549 testErrors[0] = 0;
4550 res = tst->func(globbuf.gl_pathv[i], result, error,
4551 tst->options | XML_PARSE_COMPACT);
4552 xmlResetLastError();
4553 if (res != 0) {
4554 fprintf(stderr, "File %s generated an error\n",
4555 globbuf.gl_pathv[i]);
4556 nb_errors++;
4557 err++;
4558 }
4559 else if (xmlMemUsed() != mem) {
4560 if ((xmlMemUsed() != mem) &&
4561 (extraMemoryFromResolver == 0)) {
4562 fprintf(stderr, "File %s leaked %d bytes\n",
4563 globbuf.gl_pathv[i], xmlMemUsed() - mem);
4564 nb_leaks++;
4565 err++;
4566 }
4567 }
4568 testErrorsSize = 0;
4569 }
4570 if (result)
4571 free(result);
4572 if (error)
4573 free(error);
4574 }
4575 globfree(&globbuf);
4576 } else {
4577 testErrorsSize = 0;
4578 testErrors[0] = 0;
4579 extraMemoryFromResolver = 0;
4580 res = tst->func(NULL, NULL, NULL, tst->options);
4581 if (res != 0) {
4582 nb_errors++;
4583 err++;
4584 }
4585 }
4586
4587 xmlCharEncCloseFunc(ebcdicHandler);
4588 xmlCharEncCloseFunc(eucJpHandler);
4589
4590 return(err);
4591 }
4592
4593 static int verbose = 0;
4594 static int tests_quiet = 0;
4595
4596 static int
runtest(int i)4597 runtest(int i) {
4598 int ret = 0, res;
4599 int old_errors, old_tests, old_leaks;
4600
4601 old_errors = nb_errors;
4602 old_tests = nb_tests;
4603 old_leaks = nb_leaks;
4604 if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
4605 printf("## %s\n", testDescriptions[i].desc);
4606 res = launchTests(&testDescriptions[i]);
4607 if (res != 0)
4608 ret++;
4609 if (verbose) {
4610 if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
4611 printf("Ran %d tests, no errors\n", nb_tests - old_tests);
4612 else
4613 printf("Ran %d tests, %d errors, %d leaks\n",
4614 nb_tests - old_tests,
4615 nb_errors - old_errors,
4616 nb_leaks - old_leaks);
4617 }
4618 return(ret);
4619 }
4620
4621 int
main(int argc ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)4622 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4623 int i, a, ret = 0;
4624 int subset = 0;
4625
4626 #if defined(_WIN32) && !defined(__CYGWIN__)
4627 setvbuf(stdout, NULL, _IONBF, 0);
4628 setvbuf(stderr, NULL, _IONBF, 0);
4629 #endif
4630
4631 #if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1900
4632 _set_output_format(_TWO_DIGIT_EXPONENT);
4633 #endif
4634
4635 initializeLibxml2();
4636
4637 for (a = 1; a < argc;a++) {
4638 if (!strcmp(argv[a], "-v"))
4639 verbose = 1;
4640 else if (!strcmp(argv[a], "-u"))
4641 update_results = 1;
4642 else if (!strcmp(argv[a], "-quiet"))
4643 tests_quiet = 1;
4644 else if (!strcmp(argv[a], "--out"))
4645 temp_directory = argv[++a];
4646 else {
4647 for (i = 0; testDescriptions[i].func != NULL; i++) {
4648 if (strstr(testDescriptions[i].desc, argv[a])) {
4649 ret += runtest(i);
4650 subset++;
4651 }
4652 }
4653 }
4654 }
4655 if (subset == 0) {
4656 for (i = 0; testDescriptions[i].func != NULL; i++) {
4657 ret += runtest(i);
4658 }
4659 }
4660 if ((nb_errors == 0) && (nb_leaks == 0)) {
4661 ret = 0;
4662 printf("Total %d tests, no errors\n",
4663 nb_tests);
4664 } else {
4665 ret = 1;
4666 printf("Total %d tests, %d errors, %d leaks\n",
4667 nb_tests, nb_errors, nb_leaks);
4668 }
4669 xmlCleanupParser();
4670 xmlMemoryDump();
4671
4672 return(ret);
4673 }
4674
4675 #else /* ! LIBXML_OUTPUT_ENABLED */
4676 int
main(int argc ATTRIBUTE_UNUSED,char ** argv ATTRIBUTE_UNUSED)4677 main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
4678 fprintf(stderr, "runtest requires output to be enabled in libxml2\n");
4679 return(1);
4680 }
4681 #endif
4682