File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / testlimits.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:28 2014 UTC (9 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

    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>