Annotation of embedaddon/libxml2/testlimits.c, revision 1.1.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>