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