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