Annotation of embedaddon/libxml2/testrecurse.c, revision 1.1.1.3

1.1       misho       1: /*
                      2:  * testrecurse.c: C program to run libxml2 regression tests checking entities
                      3:  *            recursions
                      4:  *
                      5:  * To compile on Unixes:
                      6:  * cc -o testrecurse `xml2-config --cflags` testrecurse.c `xml2-config --libs` -lpthread
                      7:  *
                      8:  * See Copyright for the status of this software.
                      9:  *
                     10:  * daniel@veillard.com
                     11:  */
                     12: 
                     13: #include "libxml.h"
                     14: #include <stdio.h>
                     15: 
                     16: #if !defined(_WIN32) || defined(__CYGWIN__)
                     17: #include <unistd.h>
                     18: #endif
                     19: #include <string.h>
                     20: #include <sys/types.h>
                     21: #include <sys/stat.h>
                     22: #include <fcntl.h>
                     23: 
                     24: #include <libxml/parser.h>
                     25: #include <libxml/tree.h>
                     26: #include <libxml/uri.h>
                     27: #ifdef LIBXML_READER_ENABLED
                     28: #include <libxml/xmlreader.h>
                     29: #endif
                     30: 
                     31: /*
                     32:  * O_BINARY is just for Windows compatibility - if it isn't defined
                     33:  * on this system, avoid any compilation error
                     34:  */
                     35: #ifdef O_BINARY
                     36: #define RD_FLAGS       O_RDONLY | O_BINARY
                     37: #else
                     38: #define        RD_FLAGS        O_RDONLY
                     39: #endif
                     40: 
                     41: typedef int (*functest) (const char *filename, const char *result,
                     42:                          const char *error, int options);
                     43: 
                     44: typedef struct testDesc testDesc;
                     45: typedef testDesc *testDescPtr;
                     46: struct testDesc {
                     47:     const char *desc; /* descripton of the test */
                     48:     functest    func; /* function implementing the test */
                     49:     const char *in;   /* glob to path for input files */
                     50:     const char *out;  /* output directory */
                     51:     const char *suffix;/* suffix for output files */
                     52:     const char *err;  /* suffix for error output files */
                     53:     int     options;  /* parser options for the test */
                     54: };
                     55: 
                     56: static int checkTestFile(const char *filename);
                     57: 
                     58: 
                     59: #if defined(_WIN32) && !defined(__CYGWIN__)
                     60: 
                     61: #include <windows.h>
                     62: #include <io.h>
                     63: 
                     64: typedef struct
                     65: {
                     66:       size_t gl_pathc;    /* Count of paths matched so far  */
                     67:       char **gl_pathv;    /* List of matched pathnames.  */
                     68:       size_t gl_offs;     /* Slots to reserve in 'gl_pathv'.  */
                     69: } glob_t;
                     70: 
                     71: #define GLOB_DOOFFS 0
                     72: static int glob(const char *pattern, int flags,
                     73:                 int errfunc(const char *epath, int eerrno),
                     74:                 glob_t *pglob) {
                     75:     glob_t *ret;
                     76:     WIN32_FIND_DATA FindFileData;
                     77:     HANDLE hFind;
                     78:     unsigned int nb_paths = 0;
                     79:     char directory[500];
                     80:     int len;
                     81: 
                     82:     if ((pattern == NULL) || (pglob == NULL)) return(-1);
                     83: 
                     84:     strncpy(directory, pattern, 499);
                     85:     for (len = strlen(directory);len >= 0;len--) {
                     86:         if (directory[len] == '/') {
                     87:            len++;
                     88:            directory[len] = 0;
                     89:            break;
                     90:        }
                     91:     }
                     92:     if (len <= 0)
                     93:         len = 0;
                     94: 
                     95: 
                     96:     ret = pglob;
                     97:     memset(ret, 0, sizeof(glob_t));
                     98: 
                     99:     hFind = FindFirstFileA(pattern, &FindFileData);
                    100:     if (hFind == INVALID_HANDLE_VALUE)
                    101:         return(0);
                    102:     nb_paths = 20;
                    103:     ret->gl_pathv = (char **) malloc(nb_paths * sizeof(char *));
                    104:     if (ret->gl_pathv == NULL) {
                    105:        FindClose(hFind);
                    106:         return(-1);
                    107:     }
                    108:     strncpy(directory + len, FindFileData.cFileName, 499 - len);
                    109:     ret->gl_pathv[ret->gl_pathc] = strdup(directory);
                    110:     if (ret->gl_pathv[ret->gl_pathc] == NULL)
                    111:         goto done;
                    112:     ret->gl_pathc++;
                    113:     while(FindNextFileA(hFind, &FindFileData)) {
                    114:         if (FindFileData.cFileName[0] == '.')
                    115:            continue;
                    116:         if (ret->gl_pathc + 2 > nb_paths) {
                    117:             char **tmp = realloc(ret->gl_pathv, nb_paths * 2 * sizeof(char *));
                    118:             if (tmp == NULL)
                    119:                 break;
                    120:             ret->gl_pathv = tmp;
                    121:             nb_paths *= 2;
                    122:        }
                    123:        strncpy(directory + len, FindFileData.cFileName, 499 - len);
                    124:        ret->gl_pathv[ret->gl_pathc] = strdup(directory);
                    125:         if (ret->gl_pathv[ret->gl_pathc] == NULL)
                    126:             break;
                    127:         ret->gl_pathc++;
                    128:     }
                    129:     ret->gl_pathv[ret->gl_pathc] = NULL;
                    130: 
                    131: done:
                    132:     FindClose(hFind);
                    133:     return(0);
                    134: }
                    135: 
                    136: 
                    137: 
                    138: static void globfree(glob_t *pglob) {
                    139:     unsigned int i;
                    140:     if (pglob == NULL)
                    141:         return;
                    142: 
                    143:     for (i = 0;i < pglob->gl_pathc;i++) {
                    144:          if (pglob->gl_pathv[i] != NULL)
                    145:              free(pglob->gl_pathv[i]);
                    146:     }
                    147: }
1.1.1.2   misho     148: 
1.1       misho     149: #else
                    150: #include <glob.h>
                    151: #endif
                    152: 
                    153: /************************************************************************
                    154:  *                                                                     *
                    155:  *             Huge document generator                                 *
                    156:  *                                                                     *
                    157:  ************************************************************************/
                    158: 
                    159: #include <libxml/xmlIO.h>
                    160: 
                    161: 
                    162: static const char *start = "<!DOCTYPE foo [\
                    163: <!ENTITY f 'some internal data'> \
                    164: <!ENTITY e '&f;&f;'> \
                    165: <!ENTITY d '&e;&e;'> \
                    166: ]> \
                    167: <foo>";
                    168: 
                    169: static const char *segment = "  <bar>&e; &f; &d;</bar>\n";
                    170: static const char *finish = "</foo>";
                    171: 
                    172: static int curseg = 0;
                    173: static const char *current;
                    174: static int rlen;
                    175: 
                    176: /**
                    177:  * hugeMatch:
                    178:  * @URI: an URI to test
                    179:  *
                    180:  * Check for an huge: query
                    181:  *
                    182:  * Returns 1 if yes and 0 if another Input module should be used
                    183:  */
                    184: static int
                    185: hugeMatch(const char * URI) {
                    186:     if ((URI != NULL) && (!strncmp(URI, "huge:", 4)))
                    187:         return(1);
                    188:     return(0);
                    189: }
                    190: 
                    191: /**
                    192:  * hugeOpen:
                    193:  * @URI: an URI to test
                    194:  *
                    195:  * Return a pointer to the huge: query handler, in this example simply
                    196:  * the current pointer...
                    197:  *
                    198:  * Returns an Input context or NULL in case or error
                    199:  */
                    200: static void *
                    201: hugeOpen(const char * URI) {
                    202:     if ((URI == NULL) || (strncmp(URI, "huge:", 4)))
                    203:         return(NULL);
                    204:     rlen = strlen(start);
                    205:     current = start;
                    206:     return((void *) current);
                    207: }
                    208: 
                    209: /**
                    210:  * hugeClose:
                    211:  * @context: the read context
                    212:  *
                    213:  * Close the huge: query handler
                    214:  *
                    215:  * Returns 0 or -1 in case of error
                    216:  */
                    217: static int
                    218: hugeClose(void * context) {
                    219:     if (context == NULL) return(-1);
                    220:     return(0);
                    221: }
                    222: 
                    223: #define MAX_NODES 1000000
                    224: 
                    225: /**
                    226:  * hugeRead:
                    227:  * @context: the read context
                    228:  * @buffer: where to store data
                    229:  * @len: number of bytes to read
                    230:  *
                    231:  * Implement an huge: query read.
                    232:  *
                    233:  * Returns the number of bytes read or -1 in case of error
                    234:  */
                    235: static int
                    236: hugeRead(void *context, char *buffer, int len)
                    237: {
                    238:     if ((context == NULL) || (buffer == NULL) || (len < 0))
                    239:         return (-1);
                    240: 
                    241:     if (len >= rlen) {
                    242:         if (curseg >= MAX_NODES + 1) {
                    243:             rlen = 0;
                    244:             return(0);
                    245:         }
                    246:         len = rlen;
                    247:         rlen = 0;
                    248:        memcpy(buffer, current, len);
                    249:         curseg ++;
                    250:         if (curseg == MAX_NODES) {
                    251:            fprintf(stderr, "\n");
                    252:             rlen = strlen(finish);
                    253:             current = finish;
                    254:        } else {
                    255:            if (curseg % (MAX_NODES / 10) == 0)
                    256:                fprintf(stderr, ".");
                    257:             rlen = strlen(segment);
                    258:             current = segment;
                    259:        }
                    260:     } else {
                    261:        memcpy(buffer, current, len);
                    262:        rlen -= len;
                    263:         current += len;
                    264:     }
                    265:     return (len);
                    266: }
                    267: 
                    268: /************************************************************************
                    269:  *                                                                     *
                    270:  *             Libxml2 specific routines                               *
                    271:  *                                                                     *
                    272:  ************************************************************************/
                    273: 
                    274: static int nb_tests = 0;
                    275: static int nb_errors = 0;
                    276: static int nb_leaks = 0;
                    277: static int extraMemoryFromResolver = 0;
                    278: 
                    279: static int
                    280: fatalError(void) {
                    281:     fprintf(stderr, "Exitting tests on fatal error\n");
                    282:     exit(1);
                    283: }
                    284: 
                    285: /*
                    286:  * We need to trap calls to the resolver to not account memory for the catalog
                    287:  * which is shared to the current running test. We also don't want to have
                    288:  * network downloads modifying tests.
                    289:  */
                    290: static xmlParserInputPtr
                    291: testExternalEntityLoader(const char *URL, const char *ID,
                    292:                         xmlParserCtxtPtr ctxt) {
                    293:     xmlParserInputPtr ret;
                    294: 
                    295:     if (checkTestFile(URL)) {
                    296:        ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
                    297:     } else {
                    298:        int memused = xmlMemUsed();
                    299:        ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
                    300:        extraMemoryFromResolver += xmlMemUsed() - memused;
                    301:     }
                    302: 
                    303:     return(ret);
                    304: }
                    305: 
                    306: /*
                    307:  * Trapping the error messages at the generic level to grab the equivalent of
                    308:  * stderr messages on CLI tools.
                    309:  */
                    310: static char testErrors[32769];
                    311: static int testErrorsSize = 0;
                    312: 
                    313: static void XMLCDECL
                    314: channel(void *ctx  ATTRIBUTE_UNUSED, const char *msg, ...) {
                    315:     va_list args;
                    316:     int res;
                    317: 
                    318:     if (testErrorsSize >= 32768)
                    319:         return;
                    320:     va_start(args, msg);
                    321:     res = vsnprintf(&testErrors[testErrorsSize],
                    322:                     32768 - testErrorsSize,
                    323:                    msg, args);
                    324:     va_end(args);
                    325:     if (testErrorsSize + res >= 32768) {
                    326:         /* buffer is full */
                    327:        testErrorsSize = 32768;
                    328:        testErrors[testErrorsSize] = 0;
                    329:     } else {
                    330:         testErrorsSize += res;
                    331:     }
                    332:     testErrors[testErrorsSize] = 0;
                    333: }
                    334: 
                    335: /**
                    336:  * xmlParserPrintFileContext:
                    337:  * @input:  an xmlParserInputPtr input
                    338:  *
                    339:  * Displays current context within the input content for error tracking
                    340:  */
                    341: 
                    342: static void
                    343: xmlParserPrintFileContextInternal(xmlParserInputPtr input ,
                    344:                xmlGenericErrorFunc chanl, void *data ) {
                    345:     const xmlChar *cur, *base;
                    346:     unsigned int n, col;       /* GCC warns if signed, because compared with sizeof() */
                    347:     xmlChar  content[81]; /* space for 80 chars + line terminator */
                    348:     xmlChar *ctnt;
                    349: 
                    350:     if (input == NULL) return;
                    351:     cur = input->cur;
                    352:     base = input->base;
                    353:     /* skip backwards over any end-of-lines */
                    354:     while ((cur > base) && ((*(cur) == '\n') || (*(cur) == '\r'))) {
                    355:        cur--;
                    356:     }
                    357:     n = 0;
                    358:     /* search backwards for beginning-of-line (to max buff size) */
                    359:     while ((n++ < (sizeof(content)-1)) && (cur > base) &&
                    360:    (*(cur) != '\n') && (*(cur) != '\r'))
                    361:         cur--;
                    362:     if ((*(cur) == '\n') || (*(cur) == '\r')) cur++;
                    363:     /* calculate the error position in terms of the current position */
                    364:     col = input->cur - cur;
                    365:     /* search forward for end-of-line (to max buff size) */
                    366:     n = 0;
                    367:     ctnt = content;
                    368:     /* copy selected text to our buffer */
                    369:     while ((*cur != 0) && (*(cur) != '\n') &&
                    370:    (*(cur) != '\r') && (n < sizeof(content)-1)) {
                    371:                *ctnt++ = *cur++;
                    372:        n++;
                    373:     }
                    374:     *ctnt = 0;
                    375:     /* print out the selected text */
                    376:     chanl(data ,"%s\n", content);
                    377:     /* create blank line with problem pointer */
                    378:     n = 0;
                    379:     ctnt = content;
                    380:     /* (leave buffer space for pointer + line terminator) */
                    381:     while ((n<col) && (n++ < sizeof(content)-2) && (*ctnt != 0)) {
                    382:        if (*(ctnt) != '\t')
                    383:            *(ctnt) = ' ';
                    384:        ctnt++;
                    385:     }
                    386:     *ctnt++ = '^';
                    387:     *ctnt = 0;
                    388:     chanl(data ,"%s\n", content);
                    389: }
                    390: 
                    391: static void
                    392: testStructuredErrorHandler(void *ctx  ATTRIBUTE_UNUSED, xmlErrorPtr err) {
                    393:     char *file = NULL;
                    394:     int line = 0;
                    395:     int code = -1;
                    396:     int domain;
                    397:     void *data = NULL;
                    398:     const char *str;
                    399:     const xmlChar *name = NULL;
                    400:     xmlNodePtr node;
                    401:     xmlErrorLevel level;
                    402:     xmlParserInputPtr input = NULL;
                    403:     xmlParserInputPtr cur = NULL;
                    404:     xmlParserCtxtPtr ctxt = NULL;
                    405: 
                    406:     if (err == NULL)
                    407:         return;
                    408: 
                    409:     file = err->file;
                    410:     line = err->line;
                    411:     code = err->code;
                    412:     domain = err->domain;
                    413:     level = err->level;
                    414:     node = err->node;
                    415:     if ((domain == XML_FROM_PARSER) || (domain == XML_FROM_HTML) ||
                    416:         (domain == XML_FROM_DTD) || (domain == XML_FROM_NAMESPACE) ||
                    417:        (domain == XML_FROM_IO) || (domain == XML_FROM_VALID)) {
                    418:        ctxt = err->ctxt;
                    419:     }
                    420:     str = err->message;
                    421: 
                    422:     if (code == XML_ERR_OK)
                    423:         return;
                    424: 
                    425:     if ((node != NULL) && (node->type == XML_ELEMENT_NODE))
                    426:         name = node->name;
                    427: 
                    428:     /*
                    429:      * Maintain the compatibility with the legacy error handling
                    430:      */
                    431:     if (ctxt != NULL) {
                    432:         input = ctxt->input;
                    433:         if ((input != NULL) && (input->filename == NULL) &&
                    434:             (ctxt->inputNr > 1)) {
                    435:             cur = input;
                    436:             input = ctxt->inputTab[ctxt->inputNr - 2];
                    437:         }
                    438:         if (input != NULL) {
                    439:             if (input->filename)
                    440:                 channel(data, "%s:%d: ", input->filename, input->line);
                    441:             else if ((line != 0) && (domain == XML_FROM_PARSER))
                    442:                 channel(data, "Entity: line %d: ", input->line);
                    443:         }
                    444:     } else {
                    445:         if (file != NULL)
                    446:             channel(data, "%s:%d: ", file, line);
                    447:         else if ((line != 0) && (domain == XML_FROM_PARSER))
                    448:             channel(data, "Entity: line %d: ", line);
                    449:     }
                    450:     if (name != NULL) {
                    451:         channel(data, "element %s: ", name);
                    452:     }
                    453:     if (code == XML_ERR_OK)
                    454:         return;
                    455:     switch (domain) {
                    456:         case XML_FROM_PARSER:
                    457:             channel(data, "parser ");
                    458:             break;
                    459:         case XML_FROM_NAMESPACE:
                    460:             channel(data, "namespace ");
                    461:             break;
                    462:         case XML_FROM_DTD:
                    463:         case XML_FROM_VALID:
                    464:             channel(data, "validity ");
                    465:             break;
                    466:         case XML_FROM_HTML:
                    467:             channel(data, "HTML parser ");
                    468:             break;
                    469:         case XML_FROM_MEMORY:
                    470:             channel(data, "memory ");
                    471:             break;
                    472:         case XML_FROM_OUTPUT:
                    473:             channel(data, "output ");
                    474:             break;
                    475:         case XML_FROM_IO:
                    476:             channel(data, "I/O ");
                    477:             break;
                    478:         case XML_FROM_XINCLUDE:
                    479:             channel(data, "XInclude ");
                    480:             break;
                    481:         case XML_FROM_XPATH:
                    482:             channel(data, "XPath ");
                    483:             break;
                    484:         case XML_FROM_XPOINTER:
                    485:             channel(data, "parser ");
                    486:             break;
                    487:         case XML_FROM_REGEXP:
                    488:             channel(data, "regexp ");
                    489:             break;
                    490:         case XML_FROM_MODULE:
                    491:             channel(data, "module ");
                    492:             break;
                    493:         case XML_FROM_SCHEMASV:
                    494:             channel(data, "Schemas validity ");
                    495:             break;
                    496:         case XML_FROM_SCHEMASP:
                    497:             channel(data, "Schemas parser ");
                    498:             break;
                    499:         case XML_FROM_RELAXNGP:
                    500:             channel(data, "Relax-NG parser ");
                    501:             break;
                    502:         case XML_FROM_RELAXNGV:
                    503:             channel(data, "Relax-NG validity ");
                    504:             break;
                    505:         case XML_FROM_CATALOG:
                    506:             channel(data, "Catalog ");
                    507:             break;
                    508:         case XML_FROM_C14N:
                    509:             channel(data, "C14N ");
                    510:             break;
                    511:         case XML_FROM_XSLT:
                    512:             channel(data, "XSLT ");
                    513:             break;
                    514:         default:
                    515:             break;
                    516:     }
                    517:     if (code == XML_ERR_OK)
                    518:         return;
                    519:     switch (level) {
                    520:         case XML_ERR_NONE:
                    521:             channel(data, ": ");
                    522:             break;
                    523:         case XML_ERR_WARNING:
                    524:             channel(data, "warning : ");
                    525:             break;
                    526:         case XML_ERR_ERROR:
                    527:             channel(data, "error : ");
                    528:             break;
                    529:         case XML_ERR_FATAL:
                    530:             channel(data, "error : ");
                    531:             break;
                    532:     }
                    533:     if (code == XML_ERR_OK)
                    534:         return;
                    535:     if (str != NULL) {
                    536:         int len;
                    537:        len = xmlStrlen((const xmlChar *)str);
                    538:        if ((len > 0) && (str[len - 1] != '\n'))
                    539:            channel(data, "%s\n", str);
                    540:        else
                    541:            channel(data, "%s", str);
                    542:     } else {
                    543:         channel(data, "%s\n", "out of memory error");
                    544:     }
                    545:     if (code == XML_ERR_OK)
                    546:         return;
                    547: 
                    548:     if (ctxt != NULL) {
                    549:         xmlParserPrintFileContextInternal(input, channel, data);
                    550:         if (cur != NULL) {
                    551:             if (cur->filename)
                    552:                 channel(data, "%s:%d: \n", cur->filename, cur->line);
                    553:             else if ((line != 0) && (domain == XML_FROM_PARSER))
                    554:                 channel(data, "Entity: line %d: \n", cur->line);
                    555:             xmlParserPrintFileContextInternal(cur, channel, data);
                    556:         }
                    557:     }
                    558:     if ((domain == XML_FROM_XPATH) && (err->str1 != NULL) &&
                    559:         (err->int1 < 100) &&
                    560:        (err->int1 < xmlStrlen((const xmlChar *)err->str1))) {
                    561:        xmlChar buf[150];
                    562:        int i;
                    563: 
                    564:        channel(data, "%s\n", err->str1);
                    565:        for (i=0;i < err->int1;i++)
                    566:             buf[i] = ' ';
                    567:        buf[i++] = '^';
                    568:        buf[i] = 0;
                    569:        channel(data, "%s\n", buf);
                    570:     }
                    571: }
                    572: 
                    573: static void
                    574: initializeLibxml2(void) {
                    575:     xmlGetWarningsDefaultValue = 0;
                    576:     xmlPedanticParserDefault(0);
                    577: 
                    578:     xmlMemSetup(xmlMemFree, xmlMemMalloc, xmlMemRealloc, xmlMemoryStrdup);
                    579:     xmlInitParser();
                    580:     xmlSetExternalEntityLoader(testExternalEntityLoader);
                    581:     xmlSetStructuredErrorFunc(NULL, testStructuredErrorHandler);
                    582:     /*
                    583:      * register the new I/O handlers
                    584:      */
                    585:     if (xmlRegisterInputCallbacks(hugeMatch, hugeOpen,
                    586:                                   hugeRead, hugeClose) < 0) {
                    587:         fprintf(stderr, "failed to register Huge handler\n");
                    588:        exit(1);
                    589:     }
                    590: }
                    591: 
                    592: /************************************************************************
                    593:  *                                                                     *
                    594:  *             File name and path utilities                            *
                    595:  *                                                                     *
                    596:  ************************************************************************/
                    597: 
                    598: static const char *baseFilename(const char *filename) {
                    599:     const char *cur;
                    600:     if (filename == NULL)
                    601:         return(NULL);
                    602:     cur = &filename[strlen(filename)];
                    603:     while ((cur > filename) && (*cur != '/'))
                    604:         cur--;
                    605:     if (*cur == '/')
                    606:         return(cur + 1);
                    607:     return(cur);
                    608: }
                    609: 
                    610: static char *resultFilename(const char *filename, const char *out,
                    611:                             const char *suffix) {
                    612:     const char *base;
                    613:     char res[500];
                    614:     char suffixbuff[500];
                    615: 
                    616: /*************
                    617:     if ((filename[0] == 't') && (filename[1] == 'e') &&
                    618:         (filename[2] == 's') && (filename[3] == 't') &&
                    619:        (filename[4] == '/'))
                    620:        filename = &filename[5];
                    621:  *************/
                    622: 
                    623:     base = baseFilename(filename);
                    624:     if (suffix == NULL)
                    625:         suffix = ".tmp";
                    626:     if (out == NULL)
                    627:         out = "";
                    628: 
                    629:     strncpy(suffixbuff,suffix,499);
                    630: #ifdef VMS
                    631:     if(strstr(base,".") && suffixbuff[0]=='.')
                    632:       suffixbuff[0]='_';
                    633: #endif
                    634: 
                    635:     snprintf(res, 499, "%s%s%s", out, base, suffixbuff);
                    636:     res[499] = 0;
                    637:     return(strdup(res));
                    638: }
                    639: 
                    640: static int checkTestFile(const char *filename) {
                    641:     struct stat buf;
                    642: 
                    643:     if (stat(filename, &buf) == -1)
                    644:         return(0);
                    645: 
                    646: #if defined(_WIN32) && !defined(__CYGWIN__)
                    647:     if (!(buf.st_mode & _S_IFREG))
                    648:         return(0);
                    649: #else
                    650:     if (!S_ISREG(buf.st_mode))
                    651:         return(0);
                    652: #endif
                    653: 
                    654:     return(1);
                    655: }
                    656: 
                    657: 
                    658: 
                    659: /************************************************************************
                    660:  *                                                                     *
                    661:  *             Test to detect or not recursive entities                *
                    662:  *                                                                     *
                    663:  ************************************************************************/
                    664: /**
                    665:  * recursiveDetectTest:
                    666:  * @filename: the file to parse
                    667:  * @result: the file with expected result
                    668:  * @err: the file with error messages: unused
                    669:  *
                    670:  * Parse a file loading DTD and replacing entities check it fails for
                    671:  * lol cases
                    672:  *
                    673:  * Returns 0 in case of success, an error code otherwise
                    674:  */
                    675: static int
                    676: recursiveDetectTest(const char *filename,
                    677:              const char *result ATTRIBUTE_UNUSED,
                    678:              const char *err ATTRIBUTE_UNUSED,
                    679:             int options ATTRIBUTE_UNUSED) {
                    680:     xmlDocPtr doc;
                    681:     xmlParserCtxtPtr ctxt;
                    682:     int res = 0;
                    683: 
                    684:     nb_tests++;
                    685: 
                    686:     ctxt = xmlNewParserCtxt();
                    687:     /*
                    688:      * base of the test, parse with the old API
                    689:      */
                    690:     doc = xmlCtxtReadFile(ctxt, filename, NULL,
                    691:                           XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
                    692:     if ((doc != NULL) || (ctxt->lastError.code != XML_ERR_ENTITY_LOOP)) {
                    693:         fprintf(stderr, "Failed to detect recursion in %s\n", filename);
                    694:        xmlFreeParserCtxt(ctxt);
                    695:        xmlFreeDoc(doc);
                    696:         return(1);
                    697:     }
                    698:     xmlFreeParserCtxt(ctxt);
                    699: 
                    700:     return(res);
                    701: }
                    702: 
                    703: /**
                    704:  * notRecursiveDetectTest:
                    705:  * @filename: the file to parse
                    706:  * @result: the file with expected result
                    707:  * @err: the file with error messages: unused
                    708:  *
                    709:  * Parse a file loading DTD and replacing entities check it works for
                    710:  * good cases
                    711:  *
                    712:  * Returns 0 in case of success, an error code otherwise
                    713:  */
                    714: static int
                    715: notRecursiveDetectTest(const char *filename,
                    716:              const char *result ATTRIBUTE_UNUSED,
                    717:              const char *err ATTRIBUTE_UNUSED,
                    718:             int options ATTRIBUTE_UNUSED) {
                    719:     xmlDocPtr doc;
                    720:     xmlParserCtxtPtr ctxt;
                    721:     int res = 0;
                    722: 
                    723:     nb_tests++;
                    724: 
                    725:     ctxt = xmlNewParserCtxt();
                    726:     /*
                    727:      * base of the test, parse with the old API
                    728:      */
                    729:     doc = xmlCtxtReadFile(ctxt, filename, NULL,
                    730:                           XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
                    731:     if (doc == NULL) {
                    732:         fprintf(stderr, "Failed to parse correct file %s\n", filename);
                    733:        xmlFreeParserCtxt(ctxt);
                    734:         return(1);
                    735:     }
                    736:     xmlFreeDoc(doc);
                    737:     xmlFreeParserCtxt(ctxt);
                    738: 
                    739:     return(res);
                    740: }
                    741: 
                    742: #ifdef LIBXML_READER_ENABLED
                    743: /**
                    744:  * notRecursiveHugeTest:
                    745:  * @filename: the file to parse
                    746:  * @result: the file with expected result
                    747:  * @err: the file with error messages: unused
                    748:  *
                    749:  * Parse a memory generated file
                    750:  * good cases
                    751:  *
                    752:  * Returns 0 in case of success, an error code otherwise
                    753:  */
                    754: static int
                    755: notRecursiveHugeTest(const char *filename ATTRIBUTE_UNUSED,
                    756:              const char *result ATTRIBUTE_UNUSED,
                    757:              const char *err ATTRIBUTE_UNUSED,
                    758:             int options ATTRIBUTE_UNUSED) {
                    759:     xmlTextReaderPtr reader;
                    760:     int res = 0;
                    761:     int ret;
                    762: 
                    763:     nb_tests++;
                    764: 
                    765:     reader = xmlReaderForFile("huge:test" , NULL,
                    766:                               XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
                    767:     if (reader == NULL) {
                    768:         fprintf(stderr, "Failed to open huge:test\n");
                    769:        return(1);
                    770:     }
                    771:     ret = xmlTextReaderRead(reader);
                    772:     while (ret == 1) {
                    773:         ret = xmlTextReaderRead(reader);
                    774:     }
                    775:     if (ret != 0) {
                    776:         fprintf(stderr, "Failed to parser huge:test with entities\n");
                    777:        res = 1;
                    778:     }
                    779:     xmlFreeTextReader(reader);
                    780: 
                    781:     return(res);
                    782: }
                    783: #endif
                    784: 
                    785: /************************************************************************
                    786:  *                                                                     *
                    787:  *                     Tests Descriptions                              *
                    788:  *                                                                     *
                    789:  ************************************************************************/
                    790: 
                    791: static
                    792: testDesc testDescriptions[] = {
                    793:     { "Parsing recursive test cases" ,
                    794:       recursiveDetectTest, "./test/recurse/lol*.xml", NULL, NULL, NULL,
                    795:       0 },
                    796:     { "Parsing non-recursive test cases" ,
                    797:       notRecursiveDetectTest, "./test/recurse/good*.xml", NULL, NULL, NULL,
                    798:       0 },
                    799: #ifdef LIBXML_READER_ENABLED
                    800:     { "Parsing non-recursive huge case" ,
                    801:       notRecursiveHugeTest, NULL, NULL, NULL, NULL,
                    802:       0 },
                    803: #endif
                    804:     {NULL, NULL, NULL, NULL, NULL, NULL, 0}
                    805: };
                    806: 
                    807: /************************************************************************
                    808:  *                                                                     *
                    809:  *             The main code driving the tests                         *
                    810:  *                                                                     *
                    811:  ************************************************************************/
                    812: 
                    813: static int
                    814: launchTests(testDescPtr tst) {
                    815:     int res = 0, err = 0;
                    816:     size_t i;
                    817:     char *result;
                    818:     char *error;
                    819:     int mem;
                    820: 
                    821:     if (tst == NULL) return(-1);
                    822:     if (tst->in != NULL) {
                    823:        glob_t globbuf;
                    824: 
                    825:        globbuf.gl_offs = 0;
                    826:        glob(tst->in, GLOB_DOOFFS, NULL, &globbuf);
                    827:        for (i = 0;i < globbuf.gl_pathc;i++) {
                    828:            if (!checkTestFile(globbuf.gl_pathv[i]))
                    829:                continue;
                    830:            if (tst->suffix != NULL) {
                    831:                result = resultFilename(globbuf.gl_pathv[i], tst->out,
                    832:                                        tst->suffix);
                    833:                if (result == NULL) {
                    834:                    fprintf(stderr, "Out of memory !\n");
                    835:                    fatalError();
                    836:                }
                    837:            } else {
                    838:                result = NULL;
                    839:            }
                    840:            if (tst->err != NULL) {
                    841:                error = resultFilename(globbuf.gl_pathv[i], tst->out,
                    842:                                        tst->err);
                    843:                if (error == NULL) {
                    844:                    fprintf(stderr, "Out of memory !\n");
                    845:                    fatalError();
                    846:                }
                    847:            } else {
                    848:                error = NULL;
                    849:            }
                    850:            if ((result) &&(!checkTestFile(result))) {
                    851:                fprintf(stderr, "Missing result file %s\n", result);
                    852:            } else if ((error) &&(!checkTestFile(error))) {
                    853:                fprintf(stderr, "Missing error file %s\n", error);
                    854:            } else {
                    855:                mem = xmlMemUsed();
                    856:                extraMemoryFromResolver = 0;
                    857:                testErrorsSize = 0;
                    858:                testErrors[0] = 0;
                    859:                res = tst->func(globbuf.gl_pathv[i], result, error,
                    860:                                tst->options | XML_PARSE_COMPACT);
                    861:                xmlResetLastError();
                    862:                if (res != 0) {
                    863:                    fprintf(stderr, "File %s generated an error\n",
                    864:                            globbuf.gl_pathv[i]);
                    865:                    nb_errors++;
                    866:                    err++;
                    867:                }
                    868:                else if (xmlMemUsed() != mem) {
                    869:                    if ((xmlMemUsed() != mem) &&
                    870:                        (extraMemoryFromResolver == 0)) {
                    871:                        fprintf(stderr, "File %s leaked %d bytes\n",
                    872:                                globbuf.gl_pathv[i], xmlMemUsed() - mem);
                    873:                        nb_leaks++;
                    874:                        err++;
                    875:                    }
                    876:                }
                    877:                testErrorsSize = 0;
                    878:            }
                    879:            if (result)
                    880:                free(result);
                    881:            if (error)
                    882:                free(error);
                    883:        }
                    884:        globfree(&globbuf);
                    885:     } else {
                    886:         testErrorsSize = 0;
                    887:        testErrors[0] = 0;
                    888:        extraMemoryFromResolver = 0;
                    889:         res = tst->func(NULL, NULL, NULL, tst->options);
                    890:        if (res != 0) {
                    891:            nb_errors++;
                    892:            err++;
                    893:        }
                    894:     }
                    895:     return(err);
                    896: }
                    897: 
                    898: static int verbose = 0;
                    899: static int tests_quiet = 0;
                    900: 
                    901: static int
                    902: runtest(int i) {
                    903:     int ret = 0, res;
                    904:     int old_errors, old_tests, old_leaks;
                    905: 
                    906:     old_errors = nb_errors;
                    907:     old_tests = nb_tests;
                    908:     old_leaks = nb_leaks;
                    909:     if ((tests_quiet == 0) && (testDescriptions[i].desc != NULL))
                    910:        printf("## %s\n", testDescriptions[i].desc);
                    911:     res = launchTests(&testDescriptions[i]);
                    912:     if (res != 0)
                    913:        ret++;
                    914:     if (verbose) {
                    915:        if ((nb_errors == old_errors) && (nb_leaks == old_leaks))
                    916:            printf("Ran %d tests, no errors\n", nb_tests - old_tests);
                    917:        else
                    918:            printf("Ran %d tests, %d errors, %d leaks\n",
                    919:                   nb_tests - old_tests,
                    920:                   nb_errors - old_errors,
                    921:                   nb_leaks - old_leaks);
                    922:     }
                    923:     return(ret);
                    924: }
                    925: 
                    926: int
                    927: main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) {
                    928:     int i, a, ret = 0;
                    929:     int subset = 0;
                    930: 
                    931:     initializeLibxml2();
                    932: 
                    933:     for (a = 1; a < argc;a++) {
                    934:         if (!strcmp(argv[a], "-v"))
                    935:            verbose = 1;
                    936:         else if (!strcmp(argv[a], "-quiet"))
                    937:            tests_quiet = 1;
                    938:        else {
                    939:            for (i = 0; testDescriptions[i].func != NULL; i++) {
                    940:                if (strstr(testDescriptions[i].desc, argv[a])) {
                    941:                    ret += runtest(i);
                    942:                    subset++;
                    943:                }
                    944:            }
                    945:        }
                    946:     }
                    947:     if (subset == 0) {
                    948:        for (i = 0; testDescriptions[i].func != NULL; i++) {
                    949:            ret += runtest(i);
                    950:        }
                    951:     }
                    952:     if ((nb_errors == 0) && (nb_leaks == 0)) {
                    953:         ret = 0;
                    954:        printf("Total %d tests, no errors\n",
                    955:               nb_tests);
                    956:     } else {
                    957:         ret = 1;
                    958:        printf("Total %d tests, %d errors, %d leaks\n",
                    959:               nb_tests, nb_errors, nb_leaks);
                    960:     }
                    961:     xmlCleanupParser();
                    962:     xmlMemoryDump();
                    963: 
                    964:     return(ret);
                    965: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>