Annotation of embedaddon/libxml2/testlimits.c, revision 1.1
1.1 ! misho 1: /*
! 2: * testlimits.c: C program to run libxml2 regression tests checking various
! 3: * limits in document size. Will consume a lot of RAM and CPU cycles
! 4: *
! 5: * To compile on Unixes:
! 6: * cc -o testlimits `xml2-config --cflags` testlimits.c `xml2-config --libs` -lpthread
! 7: *
! 8: * See Copyright for the status of this software.
! 9: *
! 10: * daniel@veillard.com
! 11: */
! 12:
! 13: #ifdef HAVE_CONFIG_H
! 14: #include "libxml.h"
! 15: #else
! 16: #include <stdio.h>
! 17: #endif
! 18:
! 19: #if !defined(_WIN32) || defined(__CYGWIN__)
! 20: #include <unistd.h>
! 21: #endif
! 22: #include <string.h>
! 23: #include <sys/types.h>
! 24: #include <sys/stat.h>
! 25: #include <fcntl.h>
! 26: #include <time.h>
! 27:
! 28: #include <libxml/parser.h>
! 29: #include <libxml/parserInternals.h>
! 30: #include <libxml/tree.h>
! 31: #include <libxml/uri.h>
! 32: #ifdef LIBXML_READER_ENABLED
! 33: #include <libxml/xmlreader.h>
! 34: #endif
! 35:
! 36: static int verbose = 0;
! 37: static int tests_quiet = 0;
! 38:
! 39: /************************************************************************
! 40: * *
! 41: * time handling *
! 42: * *
! 43: ************************************************************************/
! 44:
! 45: /* maximum time for one parsing before declaring a timeout */
! 46: #define MAX_TIME 2 /* seconds */
! 47:
! 48: static clock_t t0;
! 49: int timeout = 0;
! 50:
! 51: static void reset_timout(void) {
! 52: timeout = 0;
! 53: t0 = clock();
! 54: }
! 55:
! 56: static int check_time(void) {
! 57: clock_t tnow = clock();
! 58: if (((tnow - t0) / CLOCKS_PER_SEC) > MAX_TIME) {
! 59: timeout = 1;
! 60: return(0);
! 61: }
! 62: return(1);
! 63: }
! 64:
! 65: /************************************************************************
! 66: * *
! 67: * Huge document generator *
! 68: * *
! 69: ************************************************************************/
! 70:
! 71: #include <libxml/xmlIO.h>
! 72:
! 73: /*
! 74: * Huge documents are built using fixed start and end chunks
! 75: * and filling between the two an unconventional amount of char data
! 76: */
! 77: typedef struct hugeTest hugeTest;
! 78: typedef hugeTest *hugeTestPtr;
! 79: struct hugeTest {
! 80: const char *description;
! 81: const char *name;
! 82: const char *start;
! 83: const char *end;
! 84: };
! 85:
! 86: static struct hugeTest hugeTests[] = {
! 87: { "Huge text node", "huge:textNode", "<foo>", "</foo>" },
! 88: { "Huge attribute node", "huge:attrNode", "<foo bar='", "'/>" },
! 89: { "Huge comment node", "huge:commentNode", "<foo><!--", "--></foo>" },
! 90: { "Huge PI node", "huge:piNode", "<foo><?bar ", "?></foo>" },
! 91: };
! 92:
! 93: static const char *current;
! 94: static int rlen;
! 95: static unsigned int currentTest = 0;
! 96: static int instate = 0;
! 97:
! 98: /**
! 99: * hugeMatch:
! 100: * @URI: an URI to test
! 101: *
! 102: * Check for an huge: query
! 103: *
! 104: * Returns 1 if yes and 0 if another Input module should be used
! 105: */
! 106: static int
! 107: hugeMatch(const char * URI) {
! 108: if ((URI != NULL) && (!strncmp(URI, "huge:", 5)))
! 109: return(1);
! 110: return(0);
! 111: }
! 112:
! 113: /**
! 114: * hugeOpen:
! 115: * @URI: an URI to test
! 116: *
! 117: * Return a pointer to the huge: query handler, in this example simply
! 118: * the current pointer...
! 119: *
! 120: * Returns an Input context or NULL in case or error
! 121: */
! 122: static void *
! 123: hugeOpen(const char * URI) {
! 124: if ((URI == NULL) || (strncmp(URI, "huge:", 5)))
! 125: return(NULL);
! 126:
! 127: for (currentTest = 0;currentTest < sizeof(hugeTests)/sizeof(hugeTests[0]);
! 128: currentTest++)
! 129: if (!strcmp(hugeTests[currentTest].name, URI))
! 130: goto found;
! 131:
! 132: return(NULL);
! 133:
! 134: found:
! 135: rlen = strlen(hugeTests[currentTest].start);
! 136: current = hugeTests[currentTest].start;
! 137: instate = 0;
! 138: return((void *) current);
! 139: }
! 140:
! 141: /**
! 142: * hugeClose:
! 143: * @context: the read context
! 144: *
! 145: * Close the huge: query handler
! 146: *
! 147: * Returns 0 or -1 in case of error
! 148: */
! 149: static int
! 150: hugeClose(void * context) {
! 151: if (context == NULL) return(-1);
! 152: fprintf(stderr, "\n");
! 153: return(0);
! 154: }
! 155:
! 156: #define CHUNK 4096
! 157:
! 158: char filling[CHUNK + 1];
! 159:
! 160: static void fillFilling(void) {
! 161: int i;
! 162:
! 163: for (i = 0;i < CHUNK;i++) {
! 164: filling[i] = 'a';
! 165: }
! 166: filling[CHUNK] = 0;
! 167: }
! 168:
! 169: size_t maxlen = 64 * 1024 * 1024;
! 170: size_t curlen = 0;
! 171: size_t dotlen;
! 172:
! 173: /**
! 174: * hugeRead:
! 175: * @context: the read context
! 176: * @buffer: where to store data
! 177: * @len: number of bytes to read
! 178: *
! 179: * Implement an huge: query read.
! 180: *
! 181: * Returns the number of bytes read or -1 in case of error
! 182: */
! 183: static int
! 184: hugeRead(void *context, char *buffer, int len)
! 185: {
! 186: if ((context == NULL) || (buffer == NULL) || (len < 0))
! 187: return (-1);
! 188:
! 189: if (instate == 0) {
! 190: if (len >= rlen) {
! 191: len = rlen;
! 192: rlen = 0;
! 193: memcpy(buffer, current, len);
! 194: instate = 1;
! 195: curlen = 0;
! 196: dotlen = maxlen / 10;
! 197: } else {
! 198: memcpy(buffer, current, len);
! 199: rlen -= len;
! 200: current += len;
! 201: }
! 202: } else if (instate == 2) {
! 203: if (len >= rlen) {
! 204: len = rlen;
! 205: rlen = 0;
! 206: memcpy(buffer, current, len);
! 207: instate = 3;
! 208: curlen = 0;
! 209: } else {
! 210: memcpy(buffer, current, len);
! 211: rlen -= len;
! 212: current += len;
! 213: }
! 214: } else if (instate == 1) {
! 215: if (len > CHUNK) len = CHUNK;
! 216: memcpy(buffer, &filling[0], len);
! 217: curlen += len;
! 218: if (curlen >= maxlen) {
! 219: rlen = strlen(hugeTests[currentTest].end);
! 220: current = hugeTests[currentTest].end;
! 221: instate = 2;
! 222: } else {
! 223: if (curlen > dotlen) {
! 224: fprintf(stderr, ".");
! 225: dotlen += maxlen / 10;
! 226: }
! 227: }
! 228: } else
! 229: len = 0;
! 230: return (len);
! 231: }
! 232:
! 233: /************************************************************************
! 234: * *
! 235: * Crazy document generator *
! 236: * *
! 237: ************************************************************************/
! 238:
! 239: unsigned int crazy_indx = 0;
! 240:
! 241: const char *crazy = "<?xml version='1.0' encoding='UTF-8'?>\
! 242: <?tst ?>\
! 243: <!-- tst -->\
! 244: <!DOCTYPE foo [\
! 245: <?tst ?>\
! 246: <!-- tst -->\
! 247: <!ELEMENT foo (#PCDATA)>\
! 248: <!ELEMENT p (#PCDATA|emph)* >\
! 249: ]>\
! 250: <?tst ?>\
! 251: <!-- tst -->\
! 252: <foo bar='foo'>\
! 253: <?tst ?>\
! 254: <!-- tst -->\
! 255: foo\
! 256: <![CDATA[ ]]>\
! 257: </foo>\
! 258: <?tst ?>\
! 259: <!-- tst -->";
! 260:
! 261: /**
! 262: * crazyMatch:
! 263: * @URI: an URI to test
! 264: *
! 265: * Check for a crazy: query
! 266: *
! 267: * Returns 1 if yes and 0 if another Input module should be used
! 268: */
! 269: static int
! 270: crazyMatch(const char * URI) {
! 271: if ((URI != NULL) && (!strncmp(URI, "crazy:", 6)))
! 272: return(1);
! 273: return(0);
! 274: }
! 275:
! 276: /**
! 277: * crazyOpen:
! 278: * @URI: an URI to test
! 279: *
! 280: * Return a pointer to the crazy: query handler, in this example simply
! 281: * the current pointer...
! 282: *
! 283: * Returns an Input context or NULL in case or error
! 284: */
! 285: static void *
! 286: crazyOpen(const char * URI) {
! 287: if ((URI == NULL) || (strncmp(URI, "crazy:", 6)))
! 288: return(NULL);
! 289:
! 290: if (crazy_indx > strlen(crazy))
! 291: return(NULL);
! 292: reset_timout();
! 293: rlen = crazy_indx;
! 294: current = &crazy[0];
! 295: instate = 0;
! 296: return((void *) current);
! 297: }
! 298:
! 299: /**
! 300: * crazyClose:
! 301: * @context: the read context
! 302: *
! 303: * Close the crazy: query handler
! 304: *
! 305: * Returns 0 or -1 in case of error
! 306: */
! 307: static int
! 308: crazyClose(void * context) {
! 309: if (context == NULL) return(-1);
! 310: return(0);
! 311: }
! 312:
! 313:
! 314: /**
! 315: * crazyRead:
! 316: * @context: the read context
! 317: * @buffer: where to store data
! 318: * @len: number of bytes to read
! 319: *
! 320: * Implement an crazy: query read.
! 321: *
! 322: * Returns the number of bytes read or -1 in case of error
! 323: */
! 324: static int
! 325: crazyRead(void *context, char *buffer, int len)
! 326: {
! 327: if ((context == NULL) || (buffer == NULL) || (len < 0))
! 328: return (-1);
! 329:
! 330: if ((check_time() <= 0) && (instate == 1)) {
! 331: fprintf(stderr, "\ntimeout in crazy(%d)\n", crazy_indx);
! 332: rlen = strlen(crazy) - crazy_indx;
! 333: current = &crazy[crazy_indx];
! 334: instate = 2;
! 335: }
! 336: if (instate == 0) {
! 337: if (len >= rlen) {
! 338: len = rlen;
! 339: rlen = 0;
! 340: memcpy(buffer, current, len);
! 341: instate = 1;
! 342: curlen = 0;
! 343: } else {
! 344: memcpy(buffer, current, len);
! 345: rlen -= len;
! 346: current += len;
! 347: }
! 348: } else if (instate == 2) {
! 349: if (len >= rlen) {
! 350: len = rlen;
! 351: rlen = 0;
! 352: memcpy(buffer, current, len);
! 353: instate = 3;
! 354: curlen = 0;
! 355: } else {
! 356: memcpy(buffer, current, len);
! 357: rlen -= len;
! 358: current += len;
! 359: }
! 360: } else if (instate == 1) {
! 361: if (len > CHUNK) len = CHUNK;
! 362: memcpy(buffer, &filling[0], len);
! 363: curlen += len;
! 364: if (curlen >= maxlen) {
! 365: rlen = strlen(crazy) - crazy_indx;
! 366: current = &crazy[crazy_indx];
! 367: instate = 2;
! 368: }
! 369: } else
! 370: len = 0;
! 371: return (len);
! 372: }
! 373: /************************************************************************
! 374: * *
! 375: * Libxml2 specific routines *
! 376: * *
! 377: ************************************************************************/
! 378:
! 379: static int nb_tests = 0;
! 380: static int nb_errors = 0;
! 381: static int nb_leaks = 0;
! 382: static int extraMemoryFromResolver = 0;
! 383:
! 384: /*
! 385: * We need to trap calls to the resolver to not account memory for the catalog
! 386: * which is shared to the current running test. We also don't want to have
! 387: * network downloads modifying tests.
! 388: */
! 389: static xmlParserInputPtr
! 390: testExternalEntityLoader(const char *URL, const char *ID,
! 391: xmlParserCtxtPtr ctxt) {
! 392: xmlParserInputPtr ret;
! 393: int memused = xmlMemUsed();
! 394:
! 395: ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
! 396: extraMemoryFromResolver += xmlMemUsed() - memused;
! 397:
! 398: return(ret);
! 399: }
! 400:
! 401: /*
! 402: * Trapping the error messages at the generic level to grab the equivalent of
! 403: * stderr messages on CLI tools.
! 404: */
! 405: static char testErrors[32769];
! 406: static int testErrorsSize = 0;
! 407:
! 408: static void XMLCDECL
! 409: channel(void *ctx ATTRIBUTE_UNUSED, const char *msg, ...) {
! 410: va_list args;
! 411: int res;
! 412:
! 413: if (testErrorsSize >= 32768)
! 414: return;
! 415: va_start(args, msg);
! 416: res = vsnprintf(&testErrors[testErrorsSize],
! 417: 32768 - testErrorsSize,
! 418: msg, args);
! 419: va_end(args);
! 420: if (testErrorsSize + res >= 32768) {
! 421: /* buffer is full */
! 422: testErrorsSize = 32768;
! 423: testErrors[testErrorsSize] = 0;
! 424: } else {
! 425: testErrorsSize += res;
! 426: }
! 427: testErrors[testErrorsSize] = 0;
! 428: }
! 429:
! 430: /**
! 431: * xmlParserPrintFileContext:
! 432: * @input: an xmlParserInputPtr input
! 433: *
! 434: * Displays current context within the input content for error tracking
! 435: */
! 436:
! 437: static void
! 438: xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
! 439: xmlGenericErrorFunc chanl, void *data ) {
! 440: const xmlChar *cur, *base;
! 441: unsigned int n, col; /* GCC warns if signed, because compared with sizeof() */
! 442: xmlChar content[81]; /* space for 80 chars + line terminator */
! 443: xmlChar *ctnt;
! 444:
! 445: if (input == NULL) return;
! 446: cur = input->cur;
! 447: base = input->base;
! 448: /* skip backwards over any end-of-lines */
! 449: while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
! 450: cur--;
! 451: }
! 452: n = 0;
! 453: /* search backwards for beginning-of-line (to max buff size) */
! 454: while ((n++ < (sizeof(content)-1)) && (cur > base) &&
! 455: (*(cur) != '\n') && (*(cur) != '\r'))
! 456: cur--;
! 457: if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
! 458: /* calculate the error position in terms of the current position */
! 459: col = input->cur - cur;
! 460: /* search forward for end-of-line (to max buff size) */
! 461: n = 0;
! 462: ctnt = content;
! 463: /* copy selected text to our buffer */
! 464: while ((*cur != 0) && (*(cur) != '\n') &&
! 465: (*(cur) != '\r') && (n < sizeof(content)-1)) {
! 466: *ctnt++ = *cur++;
! 467: n++;
! 468: }
! 469: *ctnt = 0;
! 470: /* print out the selected text */
! 471: chanl(data ,"%s\n", content);
! 472: /* create blank line with problem pointer */
! 473: n = 0;
! 474: ctnt = content;
! 475: /* (leave buffer space for pointer + line terminator) */
! 476: while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
! 477: if (*(ctnt) != '\t')
! 478: *(ctnt) = ' ';
! 479: ctnt++;
! 480: }
! 481: *ctnt++ = '^';
! 482: *ctnt = 0;
! 483: chanl(data ,"%s\n", content);
! 484: }
! 485:
! 486: static void
! 487: testStructuredErrorHandler(void *ctx ATTRIBUTE_UNUSED, xmlErrorPtr err) {
! 488: char *file = NULL;
! 489: int line = 0;
! 490: int code = -1;
! 491: int domain;
! 492: void *data = NULL;
! 493: const char *str;
! 494: const xmlChar *name = NULL;
! 495: xmlNodePtr node;
! 496: xmlErrorLevel level;
! 497: xmlParserInputPtr input = NULL;
! 498: xmlParserInputPtr cur = NULL;
! 499: xmlParserCtxtPtr ctxt = NULL;
! 500:
! 501: if (err == NULL)
! 502: return;
! 503:
! 504: file = err->file;
! 505: line = err->line;
! 506: code = err->code;
! 507: domain = err->domain;
! 508: level = err->level;
! 509: node = err->node;
! 510: if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
! 511: (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
! 512: (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
! 513: ctxt = err->ctxt;
! 514: }
! 515: str = err->message;
! 516:
! 517: if (code == XML_ERR_OK)
! 518: return;
! 519:
! 520: if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
! 521: name = node->name;
! 522:
! 523: /*
! 524: * Maintain the compatibility with the legacy error handling
! 525: */
! 526: if (ctxt != NULL) {
! 527: input = ctxt->input;
! 528: if ((input != NULL) && (input->filename == NULL) &&
! 529: (ctxt->inputNr > 1)) {
! 530: cur = input;
! 531: input = ctxt->inputTab[ctxt->inputNr - 2];
! 532: }
! 533: if (input != NULL) {
! 534: if (input->filename)
! 535: channel(data, "%s:%d: ", input->filename, input->line);
! 536: else if ((line != 0) && (domain == XML_FROM_PARSER))
! 537: channel(data, "Entity: line %d: ", input->line);
! 538: }
! 539: } else {
! 540: if (file != NULL)
! 541: channel(data, "%s:%d: ", file, line);
! 542: else if ((line != 0) && (domain == XML_FROM_PARSER))
! 543: channel(data, "Entity: line %d: ", line);
! 544: }
! 545: if (name != NULL) {
! 546: channel(data, "element %s: ", name);
! 547: }
! 548: if (code == XML_ERR_OK)
! 549: return;
! 550: switch (domain) {
! 551: case XML_FROM_PARSER:
! 552: channel(data, "parser ");
! 553: break;
! 554: case XML_FROM_NAMESPACE:
! 555: channel(data, "namespace ");
! 556: break;
! 557: case XML_FROM_DTD:
! 558: case XML_FROM_VALID:
! 559: channel(data, "validity ");
! 560: break;
! 561: case XML_FROM_HTML:
! 562: channel(data, "HTML parser ");
! 563: break;
! 564: case XML_FROM_MEMORY:
! 565: channel(data, "memory ");
! 566: break;
! 567: case XML_FROM_OUTPUT:
! 568: channel(data, "output ");
! 569: break;
! 570: case XML_FROM_IO:
! 571: channel(data, "I/O ");
! 572: break;
! 573: case XML_FROM_XINCLUDE:
! 574: channel(data, "XInclude ");
! 575: break;
! 576: case XML_FROM_XPATH:
! 577: channel(data, "XPath ");
! 578: break;
! 579: case XML_FROM_XPOINTER:
! 580: channel(data, "parser ");
! 581: break;
! 582: case XML_FROM_REGEXP:
! 583: channel(data, "regexp ");
! 584: break;
! 585: case XML_FROM_MODULE:
! 586: channel(data, "module ");
! 587: break;
! 588: case XML_FROM_SCHEMASV:
! 589: channel(data, "Schemas validity ");
! 590: break;
! 591: case XML_FROM_SCHEMASP:
! 592: channel(data, "Schemas parser ");
! 593: break;
! 594: case XML_FROM_RELAXNGP:
! 595: channel(data, "Relax-NG parser ");
! 596: break;
! 597: case XML_FROM_RELAXNGV:
! 598: channel(data, "Relax-NG validity ");
! 599: break;
! 600: case XML_FROM_CATALOG:
! 601: channel(data, "Catalog ");
! 602: break;
! 603: case XML_FROM_C14N:
! 604: channel(data, "C14N ");
! 605: break;
! 606: case XML_FROM_XSLT:
! 607: channel(data, "XSLT ");
! 608: break;
! 609: default:
! 610: break;
! 611: }
! 612: if (code == XML_ERR_OK)
! 613: return;
! 614: switch (level) {
! 615: case XML_ERR_NONE:
! 616: channel(data, ": ");
! 617: break;
! 618: case XML_ERR_WARNING:
! 619: channel(data, "warning : ");
! 620: break;
! 621: case XML_ERR_ERROR:
! 622: channel(data, "error : ");
! 623: break;
! 624: case XML_ERR_FATAL:
! 625: channel(data, "error : ");
! 626: break;
! 627: }
! 628: if (code == XML_ERR_OK)
! 629: return;
! 630: if (str != NULL) {
! 631: int len;
! 632: len = xmlStrlen((const xmlChar *)str);
! 633: if ((len > 0) && (str[len - 1] != '\n'))
! 634: channel(data, "%s\n", str);
! 635: else
! 636: channel(data, "%s", str);
! 637: } else {
! 638: channel(data, "%s\n", "out of memory error");
! 639: }
! 640: if (code == XML_ERR_OK)
! 641: return;
! 642:
! 643: if (ctxt != NULL) {
! 644: xmlParserPrintFileContextInternal(input, channel, data);
! 645: if (cur != NULL) {
! 646: if (cur->filename)
! 647: channel(data, "%s:%d: \n", cur->filename, cur->line);
! 648: else if ((line != 0) && (domain == XML_FROM_PARSER))
! 649: channel(data, "Entity: line %d: \n", cur->line);
! 650: xmlParserPrintFileContextInternal(cur, channel, data);
! 651: }
! 652: }
! 653: if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
! 654: (err->int1 < 100) &&
! 655: (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
! 656: xmlChar buf[150];
! 657: int i;
! 658:
! 659: channel(data, "%s\n", err->str1);
! 660: for (i=0;i < err->int1;i++)
! 661: buf[i] = ' ';
! 662: buf[i++] = '^';
! 663: buf[i] = 0;
! 664: channel(data, "%s\n", buf);
! 665: }
! 666: }
! 667:
! 668: static void
! 669: initializeLibxml2(void) {
! 670: xmlGetWarningsDefaultValue = 0;
! 671: xmlPedanticParserDefault(0);
! 672:
! 673: xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
! 674: xmlInitParser();
! 675: xmlSetExternalEntityLoader(testExternalEntityLoader);
! 676: xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
! 677: /*
! 678: * register the new I/O handlers
! 679: */
! 680: if (xmlRegisterInputCallbacks(hugeMatch, hugeOpen,
! 681: hugeRead, hugeClose) < 0) {
! 682: fprintf(stderr, "failed to register Huge handlers\n");
! 683: exit(1);
! 684: }
! 685: if (xmlRegisterInputCallbacks(crazyMatch, crazyOpen,
! 686: crazyRead, crazyClose) < 0) {
! 687: fprintf(stderr, "failed to register Crazy handlers\n");
! 688: exit(1);
! 689: }
! 690: }
! 691:
! 692: /************************************************************************
! 693: * *
! 694: * SAX empty callbacks *
! 695: * *
! 696: ************************************************************************/
! 697:
! 698: unsigned long callbacks = 0;
! 699:
! 700: /**
! 701: * isStandaloneCallback:
! 702: * @ctxt: An XML parser context
! 703: *
! 704: * Is this document tagged standalone ?
! 705: *
! 706: * Returns 1 if true
! 707: */
! 708: static int
! 709: isStandaloneCallback(void *ctx ATTRIBUTE_UNUSED)
! 710: {
! 711: callbacks++;
! 712: return (0);
! 713: }
! 714:
! 715: /**
! 716: * hasInternalSubsetCallback:
! 717: * @ctxt: An XML parser context
! 718: *
! 719: * Does this document has an internal subset
! 720: *
! 721: * Returns 1 if true
! 722: */
! 723: static int
! 724: hasInternalSubsetCallback(void *ctx ATTRIBUTE_UNUSED)
! 725: {
! 726: callbacks++;
! 727: return (0);
! 728: }
! 729:
! 730: /**
! 731: * hasExternalSubsetCallback:
! 732: * @ctxt: An XML parser context
! 733: *
! 734: * Does this document has an external subset
! 735: *
! 736: * Returns 1 if true
! 737: */
! 738: static int
! 739: hasExternalSubsetCallback(void *ctx ATTRIBUTE_UNUSED)
! 740: {
! 741: callbacks++;
! 742: return (0);
! 743: }
! 744:
! 745: /**
! 746: * internalSubsetCallback:
! 747: * @ctxt: An XML parser context
! 748: *
! 749: * Does this document has an internal subset
! 750: */
! 751: static void
! 752: internalSubsetCallback(void *ctx ATTRIBUTE_UNUSED,
! 753: const xmlChar * name ATTRIBUTE_UNUSED,
! 754: const xmlChar * ExternalID ATTRIBUTE_UNUSED,
! 755: const xmlChar * SystemID ATTRIBUTE_UNUSED)
! 756: {
! 757: callbacks++;
! 758: return;
! 759: }
! 760:
! 761: /**
! 762: * externalSubsetCallback:
! 763: * @ctxt: An XML parser context
! 764: *
! 765: * Does this document has an external subset
! 766: */
! 767: static void
! 768: externalSubsetCallback(void *ctx ATTRIBUTE_UNUSED,
! 769: const xmlChar * name ATTRIBUTE_UNUSED,
! 770: const xmlChar * ExternalID ATTRIBUTE_UNUSED,
! 771: const xmlChar * SystemID ATTRIBUTE_UNUSED)
! 772: {
! 773: callbacks++;
! 774: return;
! 775: }
! 776:
! 777: /**
! 778: * resolveEntityCallback:
! 779: * @ctxt: An XML parser context
! 780: * @publicId: The public ID of the entity
! 781: * @systemId: The system ID of the entity
! 782: *
! 783: * Special entity resolver, better left to the parser, it has
! 784: * more context than the application layer.
! 785: * The default behaviour is to NOT resolve the entities, in that case
! 786: * the ENTITY_REF nodes are built in the structure (and the parameter
! 787: * values).
! 788: *
! 789: * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
! 790: */
! 791: static xmlParserInputPtr
! 792: resolveEntityCallback(void *ctx ATTRIBUTE_UNUSED,
! 793: const xmlChar * publicId ATTRIBUTE_UNUSED,
! 794: const xmlChar * systemId ATTRIBUTE_UNUSED)
! 795: {
! 796: callbacks++;
! 797: return (NULL);
! 798: }
! 799:
! 800: /**
! 801: * getEntityCallback:
! 802: * @ctxt: An XML parser context
! 803: * @name: The entity name
! 804: *
! 805: * Get an entity by name
! 806: *
! 807: * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
! 808: */
! 809: static xmlEntityPtr
! 810: getEntityCallback(void *ctx ATTRIBUTE_UNUSED,
! 811: const xmlChar * name ATTRIBUTE_UNUSED)
! 812: {
! 813: callbacks++;
! 814: return (NULL);
! 815: }
! 816:
! 817: /**
! 818: * getParameterEntityCallback:
! 819: * @ctxt: An XML parser context
! 820: * @name: The entity name
! 821: *
! 822: * Get a parameter entity by name
! 823: *
! 824: * Returns the xmlParserInputPtr
! 825: */
! 826: static xmlEntityPtr
! 827: getParameterEntityCallback(void *ctx ATTRIBUTE_UNUSED,
! 828: const xmlChar * name ATTRIBUTE_UNUSED)
! 829: {
! 830: callbacks++;
! 831: return (NULL);
! 832: }
! 833:
! 834:
! 835: /**
! 836: * entityDeclCallback:
! 837: * @ctxt: An XML parser context
! 838: * @name: the entity name
! 839: * @type: the entity type
! 840: * @publicId: The public ID of the entity
! 841: * @systemId: The system ID of the entity
! 842: * @content: the entity value (without processing).
! 843: *
! 844: * An entity definition has been parsed
! 845: */
! 846: static void
! 847: entityDeclCallback(void *ctx ATTRIBUTE_UNUSED,
! 848: const xmlChar * name ATTRIBUTE_UNUSED,
! 849: int type ATTRIBUTE_UNUSED,
! 850: const xmlChar * publicId ATTRIBUTE_UNUSED,
! 851: const xmlChar * systemId ATTRIBUTE_UNUSED,
! 852: xmlChar * content ATTRIBUTE_UNUSED)
! 853: {
! 854: callbacks++;
! 855: return;
! 856: }
! 857:
! 858: /**
! 859: * attributeDeclCallback:
! 860: * @ctxt: An XML parser context
! 861: * @name: the attribute name
! 862: * @type: the attribute type
! 863: *
! 864: * An attribute definition has been parsed
! 865: */
! 866: static void
! 867: attributeDeclCallback(void *ctx ATTRIBUTE_UNUSED,
! 868: const xmlChar * elem ATTRIBUTE_UNUSED,
! 869: const xmlChar * name ATTRIBUTE_UNUSED,
! 870: int type ATTRIBUTE_UNUSED, int def ATTRIBUTE_UNUSED,
! 871: const xmlChar * defaultValue ATTRIBUTE_UNUSED,
! 872: xmlEnumerationPtr tree ATTRIBUTE_UNUSED)
! 873: {
! 874: callbacks++;
! 875: return;
! 876: }
! 877:
! 878: /**
! 879: * elementDeclCallback:
! 880: * @ctxt: An XML parser context
! 881: * @name: the element name
! 882: * @type: the element type
! 883: * @content: the element value (without processing).
! 884: *
! 885: * An element definition has been parsed
! 886: */
! 887: static void
! 888: elementDeclCallback(void *ctx ATTRIBUTE_UNUSED,
! 889: const xmlChar * name ATTRIBUTE_UNUSED,
! 890: int type ATTRIBUTE_UNUSED,
! 891: xmlElementContentPtr content ATTRIBUTE_UNUSED)
! 892: {
! 893: callbacks++;
! 894: return;
! 895: }
! 896:
! 897: /**
! 898: * notationDeclCallback:
! 899: * @ctxt: An XML parser context
! 900: * @name: The name of the notation
! 901: * @publicId: The public ID of the entity
! 902: * @systemId: The system ID of the entity
! 903: *
! 904: * What to do when a notation declaration has been parsed.
! 905: */
! 906: static void
! 907: notationDeclCallback(void *ctx ATTRIBUTE_UNUSED,
! 908: const xmlChar * name ATTRIBUTE_UNUSED,
! 909: const xmlChar * publicId ATTRIBUTE_UNUSED,
! 910: const xmlChar * systemId ATTRIBUTE_UNUSED)
! 911: {
! 912: callbacks++;
! 913: return;
! 914: }
! 915:
! 916: /**
! 917: * unparsedEntityDeclCallback:
! 918: * @ctxt: An XML parser context
! 919: * @name: The name of the entity
! 920: * @publicId: The public ID of the entity
! 921: * @systemId: The system ID of the entity
! 922: * @notationName: the name of the notation
! 923: *
! 924: * What to do when an unparsed entity declaration is parsed
! 925: */
! 926: static void
! 927: unparsedEntityDeclCallback(void *ctx ATTRIBUTE_UNUSED,
! 928: const xmlChar * name ATTRIBUTE_UNUSED,
! 929: const xmlChar * publicId ATTRIBUTE_UNUSED,
! 930: const xmlChar * systemId ATTRIBUTE_UNUSED,
! 931: const xmlChar * notationName ATTRIBUTE_UNUSED)
! 932: {
! 933: callbacks++;
! 934: return;
! 935: }
! 936:
! 937: /**
! 938: * setDocumentLocatorCallback:
! 939: * @ctxt: An XML parser context
! 940: * @loc: A SAX Locator
! 941: *
! 942: * Receive the document locator at startup, actually xmlDefaultSAXLocator
! 943: * Everything is available on the context, so this is useless in our case.
! 944: */
! 945: static void
! 946: setDocumentLocatorCallback(void *ctx ATTRIBUTE_UNUSED,
! 947: xmlSAXLocatorPtr loc ATTRIBUTE_UNUSED)
! 948: {
! 949: callbacks++;
! 950: return;
! 951: }
! 952:
! 953: /**
! 954: * startDocumentCallback:
! 955: * @ctxt: An XML parser context
! 956: *
! 957: * called when the document start being processed.
! 958: */
! 959: static void
! 960: startDocumentCallback(void *ctx ATTRIBUTE_UNUSED)
! 961: {
! 962: callbacks++;
! 963: return;
! 964: }
! 965:
! 966: /**
! 967: * endDocumentCallback:
! 968: * @ctxt: An XML parser context
! 969: *
! 970: * called when the document end has been detected.
! 971: */
! 972: static void
! 973: endDocumentCallback(void *ctx ATTRIBUTE_UNUSED)
! 974: {
! 975: callbacks++;
! 976: return;
! 977: }
! 978:
! 979: #if 0
! 980: /**
! 981: * startElementCallback:
! 982: * @ctxt: An XML parser context
! 983: * @name: The element name
! 984: *
! 985: * called when an opening tag has been processed.
! 986: */
! 987: static void
! 988: startElementCallback(void *ctx ATTRIBUTE_UNUSED,
! 989: const xmlChar * name ATTRIBUTE_UNUSED,
! 990: const xmlChar ** atts ATTRIBUTE_UNUSED)
! 991: {
! 992: callbacks++;
! 993: return;
! 994: }
! 995:
! 996: /**
! 997: * endElementCallback:
! 998: * @ctxt: An XML parser context
! 999: * @name: The element name
! 1000: *
! 1001: * called when the end of an element has been detected.
! 1002: */
! 1003: static void
! 1004: endElementCallback(void *ctx ATTRIBUTE_UNUSED,
! 1005: const xmlChar * name ATTRIBUTE_UNUSED)
! 1006: {
! 1007: callbacks++;
! 1008: return;
! 1009: }
! 1010: #endif
! 1011:
! 1012: /**
! 1013: * charactersCallback:
! 1014: * @ctxt: An XML parser context
! 1015: * @ch: a xmlChar string
! 1016: * @len: the number of xmlChar
! 1017: *
! 1018: * receiving some chars from the parser.
! 1019: * Question: how much at a time ???
! 1020: */
! 1021: static void
! 1022: charactersCallback(void *ctx ATTRIBUTE_UNUSED,
! 1023: const xmlChar * ch ATTRIBUTE_UNUSED,
! 1024: int len ATTRIBUTE_UNUSED)
! 1025: {
! 1026: callbacks++;
! 1027: return;
! 1028: }
! 1029:
! 1030: /**
! 1031: * referenceCallback:
! 1032: * @ctxt: An XML parser context
! 1033: * @name: The entity name
! 1034: *
! 1035: * called when an entity reference is detected.
! 1036: */
! 1037: static void
! 1038: referenceCallback(void *ctx ATTRIBUTE_UNUSED,
! 1039: const xmlChar * name ATTRIBUTE_UNUSED)
! 1040: {
! 1041: callbacks++;
! 1042: return;
! 1043: }
! 1044:
! 1045: /**
! 1046: * ignorableWhitespaceCallback:
! 1047: * @ctxt: An XML parser context
! 1048: * @ch: a xmlChar string
! 1049: * @start: the first char in the string
! 1050: * @len: the number of xmlChar
! 1051: *
! 1052: * receiving some ignorable whitespaces from the parser.
! 1053: * Question: how much at a time ???
! 1054: */
! 1055: static void
! 1056: ignorableWhitespaceCallback(void *ctx ATTRIBUTE_UNUSED,
! 1057: const xmlChar * ch ATTRIBUTE_UNUSED,
! 1058: int len ATTRIBUTE_UNUSED)
! 1059: {
! 1060: callbacks++;
! 1061: return;
! 1062: }
! 1063:
! 1064: /**
! 1065: * processingInstructionCallback:
! 1066: * @ctxt: An XML parser context
! 1067: * @target: the target name
! 1068: * @data: the PI data's
! 1069: * @len: the number of xmlChar
! 1070: *
! 1071: * A processing instruction has been parsed.
! 1072: */
! 1073: static void
! 1074: processingInstructionCallback(void *ctx ATTRIBUTE_UNUSED,
! 1075: const xmlChar * target ATTRIBUTE_UNUSED,
! 1076: const xmlChar * data ATTRIBUTE_UNUSED)
! 1077: {
! 1078: callbacks++;
! 1079: return;
! 1080: }
! 1081:
! 1082: /**
! 1083: * cdataBlockCallback:
! 1084: * @ctx: the user data (XML parser context)
! 1085: * @value: The pcdata content
! 1086: * @len: the block length
! 1087: *
! 1088: * called when a pcdata block has been parsed
! 1089: */
! 1090: static void
! 1091: cdataBlockCallback(void *ctx ATTRIBUTE_UNUSED,
! 1092: const xmlChar * value ATTRIBUTE_UNUSED,
! 1093: int len ATTRIBUTE_UNUSED)
! 1094: {
! 1095: callbacks++;
! 1096: return;
! 1097: }
! 1098:
! 1099: /**
! 1100: * commentCallback:
! 1101: * @ctxt: An XML parser context
! 1102: * @value: the comment content
! 1103: *
! 1104: * A comment has been parsed.
! 1105: */
! 1106: static void
! 1107: commentCallback(void *ctx ATTRIBUTE_UNUSED,
! 1108: const xmlChar * value ATTRIBUTE_UNUSED)
! 1109: {
! 1110: callbacks++;
! 1111: return;
! 1112: }
! 1113:
! 1114: /**
! 1115: * warningCallback:
! 1116: * @ctxt: An XML parser context
! 1117: * @msg: the message to display/transmit
! 1118: * @...: extra parameters for the message display
! 1119: *
! 1120: * Display and format a warning messages, gives file, line, position and
! 1121: * extra parameters.
! 1122: */
! 1123: static void XMLCDECL
! 1124: warningCallback(void *ctx ATTRIBUTE_UNUSED,
! 1125: const char *msg ATTRIBUTE_UNUSED, ...)
! 1126: {
! 1127: callbacks++;
! 1128: return;
! 1129: }
! 1130:
! 1131: /**
! 1132: * errorCallback:
! 1133: * @ctxt: An XML parser context
! 1134: * @msg: the message to display/transmit
! 1135: * @...: extra parameters for the message display
! 1136: *
! 1137: * Display and format a error messages, gives file, line, position and
! 1138: * extra parameters.
! 1139: */
! 1140: static void XMLCDECL
! 1141: errorCallback(void *ctx ATTRIBUTE_UNUSED, const char *msg ATTRIBUTE_UNUSED,
! 1142: ...)
! 1143: {
! 1144: callbacks++;
! 1145: return;
! 1146: }
! 1147:
! 1148: /**
! 1149: * fatalErrorCallback:
! 1150: * @ctxt: An XML parser context
! 1151: * @msg: the message to display/transmit
! 1152: * @...: extra parameters for the message display
! 1153: *
! 1154: * Display and format a fatalError messages, gives file, line, position and
! 1155: * extra parameters.
! 1156: */
! 1157: static void XMLCDECL
! 1158: fatalErrorCallback(void *ctx ATTRIBUTE_UNUSED,
! 1159: const char *msg ATTRIBUTE_UNUSED, ...)
! 1160: {
! 1161: return;
! 1162: }
! 1163:
! 1164:
! 1165: /*
! 1166: * SAX2 specific callbacks
! 1167: */
! 1168:
! 1169: /**
! 1170: * startElementNsCallback:
! 1171: * @ctxt: An XML parser context
! 1172: * @name: The element name
! 1173: *
! 1174: * called when an opening tag has been processed.
! 1175: */
! 1176: static void
! 1177: startElementNsCallback(void *ctx ATTRIBUTE_UNUSED,
! 1178: const xmlChar * localname ATTRIBUTE_UNUSED,
! 1179: const xmlChar * prefix ATTRIBUTE_UNUSED,
! 1180: const xmlChar * URI ATTRIBUTE_UNUSED,
! 1181: int nb_namespaces ATTRIBUTE_UNUSED,
! 1182: const xmlChar ** namespaces ATTRIBUTE_UNUSED,
! 1183: int nb_attributes ATTRIBUTE_UNUSED,
! 1184: int nb_defaulted ATTRIBUTE_UNUSED,
! 1185: const xmlChar ** attributes ATTRIBUTE_UNUSED)
! 1186: {
! 1187: callbacks++;
! 1188: return;
! 1189: }
! 1190:
! 1191: /**
! 1192: * endElementCallback:
! 1193: * @ctxt: An XML parser context
! 1194: * @name: The element name
! 1195: *
! 1196: * called when the end of an element has been detected.
! 1197: */
! 1198: static void
! 1199: endElementNsCallback(void *ctx ATTRIBUTE_UNUSED,
! 1200: const xmlChar * localname ATTRIBUTE_UNUSED,
! 1201: const xmlChar * prefix ATTRIBUTE_UNUSED,
! 1202: const xmlChar * URI ATTRIBUTE_UNUSED)
! 1203: {
! 1204: callbacks++;
! 1205: return;
! 1206: }
! 1207:
! 1208: static xmlSAXHandler callbackSAX2HandlerStruct = {
! 1209: internalSubsetCallback,
! 1210: isStandaloneCallback,
! 1211: hasInternalSubsetCallback,
! 1212: hasExternalSubsetCallback,
! 1213: resolveEntityCallback,
! 1214: getEntityCallback,
! 1215: entityDeclCallback,
! 1216: notationDeclCallback,
! 1217: attributeDeclCallback,
! 1218: elementDeclCallback,
! 1219: unparsedEntityDeclCallback,
! 1220: setDocumentLocatorCallback,
! 1221: startDocumentCallback,
! 1222: endDocumentCallback,
! 1223: NULL,
! 1224: NULL,
! 1225: referenceCallback,
! 1226: charactersCallback,
! 1227: ignorableWhitespaceCallback,
! 1228: processingInstructionCallback,
! 1229: commentCallback,
! 1230: warningCallback,
! 1231: errorCallback,
! 1232: fatalErrorCallback,
! 1233: getParameterEntityCallback,
! 1234: cdataBlockCallback,
! 1235: externalSubsetCallback,
! 1236: XML_SAX2_MAGIC,
! 1237: NULL,
! 1238: startElementNsCallback,
! 1239: endElementNsCallback,
! 1240: NULL
! 1241: };
! 1242:
! 1243: static xmlSAXHandlerPtr callbackSAX2Handler = &callbackSAX2HandlerStruct;
! 1244:
! 1245: /************************************************************************
! 1246: * *
! 1247: * The tests front-ends *
! 1248: * *
! 1249: ************************************************************************/
! 1250:
! 1251: /**
! 1252: * readerTest:
! 1253: * @filename: the file to parse
! 1254: * @max_size: size of the limit to test
! 1255: * @options: parsing options
! 1256: * @fail: should a failure be reported
! 1257: *
! 1258: * Parse a memory generated file using SAX
! 1259: *
! 1260: * Returns 0 in case of success, an error code otherwise
! 1261: */
! 1262: static int
! 1263: saxTest(const char *filename, size_t limit, int options, int fail) {
! 1264: int res = 0;
! 1265: xmlParserCtxtPtr ctxt;
! 1266: xmlDocPtr doc;
! 1267: xmlSAXHandlerPtr old_sax;
! 1268:
! 1269: nb_tests++;
! 1270:
! 1271: maxlen = limit;
! 1272: ctxt = xmlNewParserCtxt();
! 1273: if (ctxt == NULL) {
! 1274: fprintf(stderr, "Failed to create parser context\n");
! 1275: return(1);
! 1276: }
! 1277: old_sax = ctxt->sax;
! 1278: ctxt->sax = callbackSAX2Handler;
! 1279: ctxt->userData = NULL;
! 1280: doc = xmlCtxtReadFile(ctxt, filename, NULL, options);
! 1281:
! 1282: if (doc != NULL) {
! 1283: fprintf(stderr, "SAX parsing generated a document !\n");
! 1284: xmlFreeDoc(doc);
! 1285: res = 0;
! 1286: } else if (ctxt->wellFormed == 0) {
! 1287: if (fail)
! 1288: res = 0;
! 1289: else {
! 1290: fprintf(stderr, "Failed to parse '%s' %lu\n", filename, limit);
! 1291: res = 1;
! 1292: }
! 1293: } else {
! 1294: if (fail) {
! 1295: fprintf(stderr, "Failed to get failure for '%s' %lu\n",
! 1296: filename, limit);
! 1297: res = 1;
! 1298: } else
! 1299: res = 0;
! 1300: }
! 1301: ctxt->sax = old_sax;
! 1302: xmlFreeParserCtxt(ctxt);
! 1303:
! 1304: return(res);
! 1305: }
! 1306: #ifdef LIBXML_READER_ENABLED
! 1307: /**
! 1308: * readerTest:
! 1309: * @filename: the file to parse
! 1310: * @max_size: size of the limit to test
! 1311: * @options: parsing options
! 1312: * @fail: should a failure be reported
! 1313: *
! 1314: * Parse a memory generated file using the xmlReader
! 1315: *
! 1316: * Returns 0 in case of success, an error code otherwise
! 1317: */
! 1318: static int
! 1319: readerTest(const char *filename, size_t limit, int options, int fail) {
! 1320: xmlTextReaderPtr reader;
! 1321: int res = 0;
! 1322: int ret;
! 1323:
! 1324: nb_tests++;
! 1325:
! 1326: maxlen = limit;
! 1327: reader = xmlReaderForFile(filename , NULL, options);
! 1328: if (reader == NULL) {
! 1329: fprintf(stderr, "Failed to open '%s' test\n", filename);
! 1330: return(1);
! 1331: }
! 1332: ret = xmlTextReaderRead(reader);
! 1333: while (ret == 1) {
! 1334: ret = xmlTextReaderRead(reader);
! 1335: }
! 1336: if (ret != 0) {
! 1337: if (fail)
! 1338: res = 0;
! 1339: else {
! 1340: if (strncmp(filename, "crazy:", 6) == 0)
! 1341: fprintf(stderr, "Failed to parse '%s' %u\n",
! 1342: filename, crazy_indx);
! 1343: else
! 1344: fprintf(stderr, "Failed to parse '%s' %lu\n",
! 1345: filename, limit);
! 1346: res = 1;
! 1347: }
! 1348: } else {
! 1349: if (fail) {
! 1350: if (strncmp(filename, "crazy:", 6) == 0)
! 1351: fprintf(stderr, "Failed to get failure for '%s' %u\n",
! 1352: filename, crazy_indx);
! 1353: else
! 1354: fprintf(stderr, "Failed to get failure for '%s' %lu\n",
! 1355: filename, limit);
! 1356: res = 1;
! 1357: } else
! 1358: res = 0;
! 1359: }
! 1360: if (timeout)
! 1361: res = 1;
! 1362: xmlFreeTextReader(reader);
! 1363:
! 1364: return(res);
! 1365: }
! 1366: #endif
! 1367:
! 1368: /************************************************************************
! 1369: * *
! 1370: * Tests descriptions *
! 1371: * *
! 1372: ************************************************************************/
! 1373:
! 1374: typedef int (*functest) (const char *filename, size_t limit, int options,
! 1375: int fail);
! 1376:
! 1377: typedef struct limitDesc limitDesc;
! 1378: typedef limitDesc *limitDescPtr;
! 1379: struct limitDesc {
! 1380: const char *name; /* the huge generator name */
! 1381: size_t limit; /* the limit to test */
! 1382: int options; /* extra parser options */
! 1383: int fail; /* whether the test should fail */
! 1384: };
! 1385:
! 1386: static limitDesc limitDescriptions[] = {
! 1387: /* max length of a text node in content */
! 1388: {"huge:textNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
! 1389: {"huge:textNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
! 1390: {"huge:textNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
! 1391: /* max length of a text node in content */
! 1392: {"huge:attrNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
! 1393: {"huge:attrNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
! 1394: {"huge:attrNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
! 1395: /* max length of a comment node */
! 1396: {"huge:commentNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
! 1397: {"huge:commentNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
! 1398: {"huge:commentNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
! 1399: /* max length of a PI node */
! 1400: {"huge:piNode", XML_MAX_TEXT_LENGTH - CHUNK, 0, 0},
! 1401: {"huge:piNode", XML_MAX_TEXT_LENGTH + CHUNK, 0, 1},
! 1402: {"huge:piNode", XML_MAX_TEXT_LENGTH + CHUNK, XML_PARSE_HUGE, 0},
! 1403: };
! 1404:
! 1405: typedef struct testDesc testDesc;
! 1406: typedef testDesc *testDescPtr;
! 1407: struct testDesc {
! 1408: const char *desc; /* descripton of the test */
! 1409: functest func; /* function implementing the test */
! 1410: };
! 1411:
! 1412: static
! 1413: testDesc testDescriptions[] = {
! 1414: { "Parsing of huge files with the sax parser", saxTest},
! 1415: /* { "Parsing of huge files with the tree parser", treeTest}, */
! 1416: #ifdef LIBXML_READER_ENABLED
! 1417: { "Parsing of huge files with the reader", readerTest},
! 1418: #endif
! 1419: {NULL, NULL}
! 1420: };
! 1421:
! 1422: typedef struct testException testException;
! 1423: typedef testException *testExceptionPtr;
! 1424: struct testException {
! 1425: unsigned int test; /* the parser test number */
! 1426: unsigned int limit; /* the limit test number */
! 1427: int fail; /* new fail value or -1*/
! 1428: size_t size; /* new limit value or 0 */
! 1429: };
! 1430:
! 1431: static
! 1432: testException testExceptions[] = {
! 1433: /* the SAX parser doesn't hit a limit of XML_MAX_TEXT_LENGTH text nodes */
! 1434: { 0, 1, 0, 0},
! 1435: };
! 1436:
! 1437: static int
! 1438: launchTests(testDescPtr tst, unsigned int test) {
! 1439: int res = 0, err = 0;
! 1440: unsigned int i, j;
! 1441: size_t limit;
! 1442: int fail;
! 1443:
! 1444: if (tst == NULL) return(-1);
! 1445:
! 1446: for (i = 0;i < sizeof(limitDescriptions)/sizeof(limitDescriptions[0]);i++) {
! 1447: limit = limitDescriptions[i].limit;
! 1448: fail = limitDescriptions[i].fail;
! 1449: /*
! 1450: * Handle exceptions if any
! 1451: */
! 1452: for (j = 0;j < sizeof(testExceptions)/sizeof(testExceptions[0]);j++) {
! 1453: if ((testExceptions[j].test == test) &&
! 1454: (testExceptions[j].limit == i)) {
! 1455: if (testExceptions[j].fail != -1)
! 1456: fail = testExceptions[j].fail;
! 1457: if (testExceptions[j].size != 0)
! 1458: limit = testExceptions[j].size;
! 1459: break;
! 1460: }
! 1461: }
! 1462: res = tst->func(limitDescriptions[i].name, limit,
! 1463: limitDescriptions[i].options, fail);
! 1464: if (res != 0) {
! 1465: nb_errors++;
! 1466: err++;
! 1467: }
! 1468: }
! 1469: return(err);
! 1470: }
! 1471:
! 1472:
! 1473: static int
! 1474: runtest(unsigned int i) {
! 1475: int ret = 0, res;
! 1476: int old_errors, old_tests, old_leaks;
! 1477:
! 1478: old_errors = nb_errors;
! 1479: old_tests = nb_tests;
! 1480: old_leaks = nb_leaks;
! 1481: if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
! 1482: printf("## %s\n", testDescriptions[i].desc);
! 1483: res = launchTests(&testDescriptions[i], i);
! 1484: if (res != 0)
! 1485: ret++;
! 1486: if (verbose) {
! 1487: if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
! 1488: printf("Ran %d tests, no errors\n", nb_tests - old_tests);
! 1489: else
! 1490: printf("Ran %d tests, %d errors, %d leaks\n",
! 1491: nb_tests - old_tests,
! 1492: nb_errors - old_errors,
! 1493: nb_leaks - old_leaks);
! 1494: }
! 1495: return(ret);
! 1496: }
! 1497:
! 1498: static int
! 1499: launchCrazySAX(unsigned int test, int fail) {
! 1500: int res = 0, err = 0;
! 1501:
! 1502: crazy_indx = test;
! 1503:
! 1504: res = saxTest("crazy::test", XML_MAX_LOOKUP_LIMIT - CHUNK, 0, fail);
! 1505: if (res != 0) {
! 1506: nb_errors++;
! 1507: err++;
! 1508: }
! 1509: if (tests_quiet == 0)
! 1510: fprintf(stderr, "%c", crazy[test]);
! 1511:
! 1512: return(err);
! 1513: }
! 1514:
! 1515: static int
! 1516: launchCrazy(unsigned int test, int fail) {
! 1517: int res = 0, err = 0;
! 1518:
! 1519: crazy_indx = test;
! 1520:
! 1521: res = readerTest("crazy::test", XML_MAX_LOOKUP_LIMIT - CHUNK, 0, fail);
! 1522: if (res != 0) {
! 1523: nb_errors++;
! 1524: err++;
! 1525: }
! 1526: if (tests_quiet == 0)
! 1527: fprintf(stderr, "%c", crazy[test]);
! 1528:
! 1529: return(err);
! 1530: }
! 1531:
! 1532: static int get_crazy_fail(int test) {
! 1533: /*
! 1534: * adding 1000000 of character 'a' leads to parser failure mostly
! 1535: * everywhere except in those special spots. Need to be updated
! 1536: * each time crazy is updated
! 1537: */
! 1538: int fail = 1;
! 1539: if ((test == 44) || /* PI in Misc */
! 1540: ((test >= 50) && (test <= 55)) || /* Comment in Misc */
! 1541: (test == 79) || /* PI in DTD */
! 1542: ((test >= 85) && (test <= 90)) || /* Comment in DTD */
! 1543: (test == 154) || /* PI in Misc */
! 1544: ((test >= 160) && (test <= 165)) || /* Comment in Misc */
! 1545: ((test >= 178) && (test <= 181)) || /* attribute value */
! 1546: (test == 183) || /* Text */
! 1547: (test == 189) || /* PI in Content */
! 1548: (test == 191) || /* Text */
! 1549: ((test >= 195) && (test <= 200)) || /* Comment in Content */
! 1550: ((test >= 203) && (test <= 206)) || /* Text */
! 1551: (test == 215) || (test == 216) || /* in CDATA */
! 1552: (test == 219) || /* Text */
! 1553: (test == 231) || /* PI in Misc */
! 1554: ((test >= 237) && (test <= 242))) /* Comment in Misc */
! 1555: fail = 0;
! 1556: return(fail);
! 1557: }
! 1558:
! 1559: static int
! 1560: runcrazy(void) {
! 1561: int ret = 0, res = 0;
! 1562: int old_errors, old_tests, old_leaks;
! 1563: unsigned int i;
! 1564:
! 1565: old_errors = nb_errors;
! 1566: old_tests = nb_tests;
! 1567: old_leaks = nb_leaks;
! 1568: if (tests_quiet == 0) {
! 1569: printf("## Crazy tests on reader\n");
! 1570: }
! 1571: for (i = 0;i < strlen(crazy);i++) {
! 1572: res += launchCrazy(i, get_crazy_fail(i));
! 1573: if (res != 0)
! 1574: ret++;
! 1575: }
! 1576: if (tests_quiet == 0) {
! 1577: printf("\n## Crazy tests on SAX\n");
! 1578: }
! 1579: for (i = 0;i < strlen(crazy);i++) {
! 1580: res += launchCrazySAX(i, get_crazy_fail(i));
! 1581: if (res != 0)
! 1582: ret++;
! 1583: }
! 1584: if (tests_quiet == 0)
! 1585: fprintf(stderr, "\n");
! 1586: if (verbose) {
! 1587: if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
! 1588: printf("Ran %d tests, no errors\n", nb_tests - old_tests);
! 1589: else
! 1590: printf("Ran %d tests, %d errors, %d leaks\n",
! 1591: nb_tests - old_tests,
! 1592: nb_errors - old_errors,
! 1593: nb_leaks - old_leaks);
! 1594: }
! 1595: return(ret);
! 1596: }
! 1597:
! 1598:
! 1599: int
! 1600: main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
! 1601: int i, a, ret = 0;
! 1602: int subset = 0;
! 1603:
! 1604: fillFilling();
! 1605: initializeLibxml2();
! 1606:
! 1607: for (a = 1; a < argc;a++) {
! 1608: if (!strcmp(argv[a], "-v"))
! 1609: verbose = 1;
! 1610: else if (!strcmp(argv[a], "-quiet"))
! 1611: tests_quiet = 1;
! 1612: else if (!strcmp(argv[a], "-crazy"))
! 1613: subset = 1;
! 1614: }
! 1615: if (subset == 0) {
! 1616: for (i = 0; testDescriptions[i].func != NULL; i++) {
! 1617: ret += runtest(i);
! 1618: }
! 1619: }
! 1620: ret += runcrazy();
! 1621: if ((nb_errors == 0) && (nb_leaks == 0)) {
! 1622: ret = 0;
! 1623: printf("Total %d tests, no errors\n",
! 1624: nb_tests);
! 1625: } else {
! 1626: ret = 1;
! 1627: printf("Total %d tests, %d errors, %d leaks\n",
! 1628: nb_tests, nb_errors, nb_leaks);
! 1629: }
! 1630: xmlCleanupParser();
! 1631: xmlMemoryDump();
! 1632:
! 1633: return(ret);
! 1634: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>