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>