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