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