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