Annotation of XML/xmlIO.c, revision 1.26

1.1       daniel      1: /*
                      2:  * xmlIO.c : implementation of the I/O interfaces used by the parser
                      3:  *
                      4:  * See Copyright for the status of this software.
                      5:  *
                      6:  * Daniel.Veillard@w3.org
                      7:  */
                      8: 
1.10      daniel      9: #ifdef WIN32
1.16      daniel     10: #include "win32config.h"
1.10      daniel     11: #else
1.12      daniel     12: #include "config.h"
1.10      daniel     13: #endif
                     14: 
                     15: #include <stdio.h>
                     16: #include <string.h>
1.1       daniel     17: 
1.10      daniel     18: #ifdef HAVE_SYS_TYPES_H
1.1       daniel     19: #include <sys/types.h>
1.10      daniel     20: #endif
                     21: #ifdef HAVE_SYS_STAT_H
1.1       daniel     22: #include <sys/stat.h>
1.10      daniel     23: #endif
                     24: #ifdef HAVE_FCNTL_H
1.1       daniel     25: #include <fcntl.h>
1.10      daniel     26: #endif
1.1       daniel     27: #ifdef HAVE_UNISTD_H
                     28: #include <unistd.h>
                     29: #endif
1.10      daniel     30: #ifdef HAVE_STDLIB_H
                     31: #include <stdlib.h>
                     32: #endif
1.1       daniel     33: #ifdef HAVE_ZLIB_H
                     34: #include <zlib.h>
                     35: #endif
                     36: 
1.21      daniel     37: #include <libxml/xmlmemory.h>
                     38: #include <libxml/parser.h>
                     39: #include <libxml/parserInternals.h>
                     40: #include <libxml/xmlIO.h>
                     41: #include <libxml/nanohttp.h>
                     42: #include <libxml/nanoftp.h>
1.1       daniel     43: 
                     44: /* #define DEBUG_INPUT */
1.2       daniel     45: /* #define VERBOSE_FAILURE */
1.5       daniel     46: /* #define DEBUG_EXTERNAL_ENTITIES */
1.1       daniel     47: 
                     48: #ifdef DEBUG_INPUT
                     49: #define MINLEN 40
                     50: #else
                     51: #define MINLEN 4000
                     52: #endif
                     53: 
1.22      daniel     54: /*
                     55:  * Input I/O callback sets
                     56:  */
                     57: typedef struct _xmlInputCallback {
                     58:     xmlInputMatchCallback matchcallback;
                     59:     xmlInputOpenCallback opencallback;
                     60:     xmlInputReadCallback readcallback;
                     61:     xmlInputCloseCallback closecallback;
                     62: } xmlInputCallback;
                     63: 
1.23      daniel     64: #define MAX_INPUT_CALLBACK 15
1.22      daniel     65: 
1.23      daniel     66: xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
                     67: int xmlInputCallbackNr = 0;
                     68: int xmlInputCallbackInitialized = 0;
                     69: 
                     70: /************************************************************************
                     71:  *                                                                     *
                     72:  *             Standard I/O for file accesses                          *
                     73:  *                                                                     *
                     74:  ************************************************************************/
1.22      daniel     75: 
                     76: /**
1.23      daniel     77:  * xmlFdMatch:
1.22      daniel     78:  * @filename:  the URI for matching
                     79:  *
                     80:  * input from file descriptor
                     81:  *
                     82:  * Returns 1 if matches, 0 otherwise
                     83:  */
1.23      daniel     84: int
                     85: xmlFdMatch (const char *filename) {
                     86:     return(1);
                     87: }
                     88: 
                     89: /**
                     90:  * xmlFdOpen:
                     91:  * @filename:  the URI for matching
                     92:  *
                     93:  * input from file descriptor, supports compressed input
                     94:  * if @filename is " " then the standard input is used
                     95:  *
                     96:  * Returns an I/O context or NULL in case of error
                     97:  */
                     98: void *
                     99: xmlFdOpen (const char *filename) {
                    100:     const char *path = NULL;
                    101:     int fd;
                    102: 
                    103:     if (!strcmp(filename, "-")) {
                    104:        fd = 0;
                    105:        return((void *) fd);
                    106:     }
                    107: 
1.22      daniel    108:     if (!strncmp(filename, "file://localhost", 16))
1.23      daniel    109:        path = &filename[16];
                    110:     else if (!strncmp(filename, "file:///", 8))
                    111:        path = &filename[8];
                    112:     else if (filename[0] == '/')
                    113:        path = filename;
                    114:     if (path == NULL)
                    115:        return(NULL);
                    116: 
                    117: #ifdef WIN32
                    118:     fd = _open (filename, O_RDONLY | _O_BINARY);
                    119: #else
                    120:     fd = open (filename, O_RDONLY);
                    121: #endif
                    122: 
                    123:     return((void *) fd);
                    124: }
                    125: 
                    126: /**
                    127:  * xmlFdRead:
                    128:  * @context:  the I/O context
                    129:  * @buffer:  where to drop data
                    130:  * @len:  number of bytes to write
                    131:  *
                    132:  * Read @len bytes to @buffer from the I/O channel.
                    133:  *
                    134:  * Returns the number of bytes written
                    135:  */
                    136: int
                    137: xmlFdRead (void * context, char * buffer, int len) {
                    138:     return(read((int) context, &buffer[0], len));
                    139: }
                    140: 
                    141: /**
                    142:  * xmlFdClose:
                    143:  * @context:  the I/O context
                    144:  *
                    145:  * Close an I/O channel
                    146:  */
                    147: void
                    148: xmlFdClose (void * context) {
                    149:     close((int) context);
1.22      daniel    150: }
1.23      daniel    151: 
1.22      daniel    152: /**
1.23      daniel    153:  * xmlFileMatch:
1.22      daniel    154:  * @filename:  the URI for matching
                    155:  *
1.23      daniel    156:  * input from FILE *
1.22      daniel    157:  *
                    158:  * Returns 1 if matches, 0 otherwise
                    159:  */
1.23      daniel    160: int
                    161: xmlFileMatch (const char *filename) {
                    162:     return(1);
                    163: }
                    164: 
                    165: /**
                    166:  * xmlFileOpen:
                    167:  * @filename:  the URI for matching
                    168:  *
                    169:  * input from FILE *, supports compressed input
                    170:  * if @filename is " " then the standard input is used
                    171:  *
                    172:  * Returns an I/O context or NULL in case of error
                    173:  */
                    174: void *
                    175: xmlFileOpen (const char *filename) {
1.22      daniel    176:     const char *path = NULL;
1.23      daniel    177:     FILE *fd;
                    178: 
                    179:     if (!strcmp(filename, "-")) {
                    180:        fd = stdin;
                    181:        return((void *) fd);
                    182:     }
1.22      daniel    183: 
                    184:     if (!strncmp(filename, "file://localhost", 16))
                    185:        path = &filename[16];
                    186:     else if (!strncmp(filename, "file:///", 8))
1.23      daniel    187:        path = &filename[8];
                    188:     else 
1.22      daniel    189:        path = filename;
                    190:     if (path == NULL)
1.23      daniel    191:        return(NULL);
                    192: 
1.22      daniel    193: #ifdef WIN32
1.23      daniel    194:     fd = fopen(path, "rb");
1.22      daniel    195: #else
1.23      daniel    196:     fd = fopen(path, "r");
                    197: #endif /* WIN32 */
                    198:     return((void *) fd);
                    199: }
                    200: 
                    201: /**
                    202:  * xmlFileRead:
                    203:  * @context:  the I/O context
                    204:  * @buffer:  where to drop data
                    205:  * @len:  number of bytes to write
                    206:  *
                    207:  * Read @len bytes to @buffer from the I/O channel.
                    208:  *
                    209:  * Returns the number of bytes written
                    210:  */
                    211: int
                    212: xmlFileRead (void * context, char * buffer, int len) {
                    213:     return(fread(&buffer[0], 1,  len, (FILE *) context));
                    214: }
                    215: 
                    216: /**
                    217:  * xmlFileClose:
                    218:  * @context:  the I/O context
                    219:  *
                    220:  * Close an I/O channel
                    221:  */
                    222: void
                    223: xmlFileClose (void * context) {
                    224:     fclose((FILE *) context);
                    225: }
                    226: 
                    227: #ifdef HAVE_ZLIB_H
                    228: /************************************************************************
                    229:  *                                                                     *
                    230:  *             I/O for compressed file accesses                        *
                    231:  *                                                                     *
                    232:  ************************************************************************/
                    233: /**
                    234:  * xmlGzfileMatch:
                    235:  * @filename:  the URI for matching
                    236:  *
                    237:  * input from compressed file test
                    238:  *
                    239:  * Returns 1 if matches, 0 otherwise
                    240:  */
                    241: int
                    242: xmlGzfileMatch (const char *filename) {
                    243:     return(1);
                    244: }
                    245: 
                    246: /**
                    247:  * xmlGzfileOpen:
                    248:  * @filename:  the URI for matching
                    249:  *
                    250:  * input from compressed file open
                    251:  * if @filename is " " then the standard input is used
                    252:  *
                    253:  * Returns an I/O context or NULL in case of error
                    254:  */
                    255: void *
                    256: xmlGzfileOpen (const char *filename) {
                    257:     const char *path = NULL;
                    258:     gzFile fd;
                    259: 
                    260:     if (!strcmp(filename, "-")) {
                    261:         fd = gzdopen (fileno(stdin), "r");
                    262:        return((void *) fd);
                    263:     }
                    264: 
                    265:     if (!strncmp(filename, "file://localhost", 16))
                    266:        path = &filename[16];
                    267:     else if (!strncmp(filename, "file:///", 8))
                    268:        path = &filename[8];
                    269:     else 
                    270:        path = filename;
                    271: 
                    272:     fd = gzopen(filename, "r");
                    273:     return((void *) fd);
                    274: }
                    275: 
                    276: /**
                    277:  * xmlGzfileRead:
                    278:  * @context:  the I/O context
                    279:  * @buffer:  where to drop data
                    280:  * @len:  number of bytes to write
                    281:  *
                    282:  * Read @len bytes to @buffer from the compressed I/O channel.
                    283:  *
                    284:  * Returns the number of bytes written
                    285:  */
                    286: int
                    287: xmlGzfileRead (void * context, char * buffer, int len) {
                    288:     return(gzread((gzFile) context, &buffer[0], len));
                    289: }
                    290: 
                    291: /**
                    292:  * xmlGzfileClose:
                    293:  * @context:  the I/O context
                    294:  *
                    295:  * Close a compressed I/O channel
                    296:  */
                    297: void
                    298: xmlGzfileClose (void * context) {
                    299:     gzclose((gzFile) context);
                    300: }
                    301: #endif /* HAVE_ZLIB_H */
                    302: 
                    303: #ifdef LIBXML_HTTP_ENABLED
                    304: /************************************************************************
                    305:  *                                                                     *
                    306:  *                     I/O for HTTP file accesses                      *
                    307:  *                                                                     *
                    308:  ************************************************************************/
                    309: /**
                    310:  * xmlIOHTTPMatch:
                    311:  * @filename:  the URI for matching
                    312:  *
                    313:  * check if the URI matches an HTTP one
                    314:  *
                    315:  * Returns 1 if matches, 0 otherwise
                    316:  */
                    317: int
                    318: xmlIOHTTPMatch (const char *filename) {
                    319:     if (!strncmp(filename, "http://", 7))
                    320:        return(1);
                    321:     return(0);
                    322: }
                    323: 
                    324: /**
                    325:  * xmlIOHTTPOpen:
                    326:  * @filename:  the URI for matching
                    327:  *
                    328:  * open an HTTP I/O channel
                    329:  *
                    330:  * Returns an I/O context or NULL in case of error
                    331:  */
                    332: void *
                    333: xmlIOHTTPOpen (const char *filename) {
                    334:     return(xmlNanoHTTPOpen(filename, NULL));
                    335: }
                    336: 
                    337: /**
                    338:  * xmlIOHTTPRead:
                    339:  * @context:  the I/O context
                    340:  * @buffer:  where to drop data
                    341:  * @len:  number of bytes to write
                    342:  *
                    343:  * Read @len bytes to @buffer from the I/O channel.
                    344:  *
                    345:  * Returns the number of bytes written
                    346:  */
                    347: int 
                    348: xmlIOHTTPRead(void * context, char * buffer, int len) {
                    349:     return(xmlNanoHTTPRead(context, &buffer[0], len));
1.22      daniel    350: }
                    351: 
1.23      daniel    352: /**
                    353:  * xmlIOHTTPClose:
                    354:  * @context:  the I/O context
                    355:  *
                    356:  * Close an HTTP I/O channel
                    357:  */
                    358: void
                    359: xmlIOHTTPClose (void * context) {
                    360:     xmlNanoHTTPClose(context);
1.22      daniel    361: }
1.23      daniel    362: #endif /* LIBXML_HTTP_ENABLED */
                    363: 
                    364: #ifdef LIBXML_FTP_ENABLED
                    365: /************************************************************************
                    366:  *                                                                     *
                    367:  *                     I/O for FTP file accesses                       *
                    368:  *                                                                     *
                    369:  ************************************************************************/
                    370: /**
                    371:  * xmlIOFTPMatch:
                    372:  * @filename:  the URI for matching
                    373:  *
                    374:  * check if the URI matches an FTP one
                    375:  *
                    376:  * Returns 1 if matches, 0 otherwise
                    377:  */
                    378: int
                    379: xmlIOFTPMatch (const char *filename) {
                    380:     if (!strncmp(filename, "ftp://", 6))
                    381:        return(1);
                    382:     return(0);
1.22      daniel    383: }
                    384: 
1.23      daniel    385: /**
                    386:  * xmlIOFTPOpen:
                    387:  * @filename:  the URI for matching
                    388:  *
                    389:  * open an FTP I/O channel
                    390:  *
                    391:  * Returns an I/O context or NULL in case of error
                    392:  */
                    393: void *
                    394: xmlIOFTPOpen (const char *filename) {
                    395:     return(xmlNanoFTPOpen(filename));
1.22      daniel    396: }
1.23      daniel    397: 
                    398: /**
                    399:  * xmlIOFTPRead:
                    400:  * @context:  the I/O context
                    401:  * @buffer:  where to drop data
                    402:  * @len:  number of bytes to write
                    403:  *
                    404:  * Read @len bytes to @buffer from the I/O channel.
                    405:  *
                    406:  * Returns the number of bytes written
                    407:  */
                    408: int 
                    409: xmlIOFTPRead(void * context, char * buffer, int len) {
                    410:     return(xmlNanoFTPRead(context, &buffer[0], len));
1.22      daniel    411: }
1.23      daniel    412: 
                    413: /**
                    414:  * xmlIOFTPClose:
                    415:  * @context:  the I/O context
                    416:  *
                    417:  * Close an FTP I/O channel
                    418:  */
                    419: void
                    420: xmlIOFTPClose (void * context) {
                    421:     xmlNanoFTPClose(context);
1.22      daniel    422: }
1.23      daniel    423: #endif /* LIBXML_FTP_ENABLED */
                    424: 
                    425: 
                    426: /**
                    427:  * xmlRegisterInputCallbacks:
                    428:  * @match:  the xmlInputMatchCallback
                    429:  * @open:  the xmlInputOpenCallback
                    430:  * @read:  the xmlInputReadCallback
                    431:  * @close:  the xmlInputCloseCallback
                    432:  *
                    433:  * Register a new set of I/O callback for handling parser input.
                    434:  *
                    435:  * Returns the registered handler number or -1 in case of error
                    436:  */
                    437: int
                    438: xmlRegisterInputCallbacks(xmlInputMatchCallback match,
                    439:        xmlInputOpenCallback open, xmlInputReadCallback read,
                    440:        xmlInputCloseCallback close) {
                    441:     if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
                    442:        return(-1);
                    443:     }
                    444:     xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = match;
                    445:     xmlInputCallbackTable[xmlInputCallbackNr].opencallback = open;
                    446:     xmlInputCallbackTable[xmlInputCallbackNr].readcallback = read;
                    447:     xmlInputCallbackTable[xmlInputCallbackNr].closecallback = close;
                    448:     return(xmlInputCallbackNr++);
1.22      daniel    449: }
                    450: 
1.23      daniel    451: /**
                    452:  * xmlRegisterDefaultInputCallbacks:
                    453:  *
                    454:  * Registers the default compiled-in I/O handlers.
                    455:  */
                    456: void
                    457: xmlRegisterDefaultInputCallbacks(void) {
                    458:     xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
                    459:                              xmlFileRead, xmlFileClose);
                    460: #ifdef HAVE_ZLIB_H
                    461:     xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
                    462:                              xmlGzfileRead, xmlGzfileClose);
                    463: #endif /* HAVE_ZLIB_H */
                    464: 
                    465: #ifdef LIBXML_HTTP_ENABLED
                    466:     xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
                    467:                              xmlIOHTTPRead, xmlIOHTTPClose);
                    468: #endif /* LIBXML_HTTP_ENABLED */
                    469: 
                    470: #ifdef LIBXML_FTP_ENABLED
                    471:     xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
                    472:                              xmlIOFTPRead, xmlIOFTPClose);
                    473: #endif /* LIBXML_FTP_ENABLED */
                    474: }
1.22      daniel    475: 
1.1       daniel    476: /**
                    477:  * xmlAllocParserInputBuffer:
                    478:  * @enc:  the charset encoding if known
                    479:  *
                    480:  * Create a buffered parser input for progressive parsing
                    481:  *
                    482:  * Returns the new parser input or NULL
                    483:  */
                    484: xmlParserInputBufferPtr
                    485: xmlAllocParserInputBuffer(xmlCharEncoding enc) {
                    486:     xmlParserInputBufferPtr ret;
                    487: 
1.8       daniel    488:     ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1.1       daniel    489:     if (ret == NULL) {
                    490:         fprintf(stderr, "xmlAllocParserInputBuffer : out of memory!\n");
                    491:        return(NULL);
                    492:     }
1.3       veillard  493:     memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1.1       daniel    494:     ret->buffer = xmlBufferCreate();
1.17      daniel    495:     if (ret->buffer == NULL) {
                    496:         xmlFree(ret);
                    497:        return(NULL);
                    498:     }
                    499:     ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
1.1       daniel    500:     ret->encoder = xmlGetCharEncodingHandler(enc);
1.26    ! daniel    501:     if (ret->encoder != NULL)
        !           502:         ret->raw = xmlBufferCreate();
        !           503:     else
        !           504:         ret->raw = NULL;
1.23      daniel    505:     ret->readcallback = NULL;
                    506:     ret->closecallback = NULL;
                    507:     ret->context = NULL;
1.1       daniel    508: 
                    509:     return(ret);
                    510: }
                    511: 
                    512: /**
                    513:  * xmlFreeParserInputBuffer:
                    514:  * @in:  a buffered parser input
                    515:  *
                    516:  * Free up the memory used by a buffered parser input
                    517:  */
                    518: void
                    519: xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
1.26    ! daniel    520:     if (in->raw) {
        !           521:         xmlBufferFree(in->raw);
        !           522:        in->raw = NULL;
        !           523:     }
1.25      daniel    524:     if (in->encoder != NULL) {
                    525:         xmlCharEncCloseFunc(in->encoder);
                    526:     }
                    527:     if (in->closecallback != NULL) {
                    528:        in->closecallback(in->context);
                    529:     }
1.1       daniel    530:     if (in->buffer != NULL) {
                    531:         xmlBufferFree(in->buffer);
                    532:        in->buffer = NULL;
                    533:     }
1.23      daniel    534: 
1.3       veillard  535:     memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
1.8       daniel    536:     xmlFree(in);
1.1       daniel    537: }
                    538: 
                    539: /**
                    540:  * xmlParserInputBufferCreateFilename:
1.23      daniel    541:  * @URI:  a C string containing the URI or filename
1.1       daniel    542:  * @enc:  the charset encoding if known
                    543:  *
                    544:  * Create a buffered parser input for the progressive parsing of a file
                    545:  * If filename is "-' then we use stdin as the input.
                    546:  * Automatic support for ZLIB/Compress compressed document is provided
                    547:  * by default if found at compile-time.
1.20      daniel    548:  * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
1.1       daniel    549:  *
                    550:  * Returns the new parser input or NULL
                    551:  */
                    552: xmlParserInputBufferPtr
1.23      daniel    553: xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
1.1       daniel    554:     xmlParserInputBufferPtr ret;
1.23      daniel    555:     int i;
                    556:     void *context = NULL;
                    557: 
                    558:     if (xmlInputCallbackInitialized == 0)
                    559:        xmlRegisterDefaultInputCallbacks();
1.1       daniel    560: 
1.23      daniel    561:     if (URI == NULL) return(NULL);
1.1       daniel    562: 
1.23      daniel    563:     /*
                    564:      * Try to find one of the input accept method accepting taht scheme
                    565:      * Go in reverse to give precedence to user defined handlers.
                    566:      */
                    567:     for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
                    568:        if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
                    569:            (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
                    570:            context = xmlInputCallbackTable[i].opencallback(URI);
                    571:            if (context != NULL)
                    572:                break;
1.1       daniel    573:        }
1.23      daniel    574:     }
                    575:     if (context == NULL) {
                    576: #ifdef DEBUG_INPUT
                    577:        fprintf(stderr, "No input filter matching \"%s\"\n", URI);
1.1       daniel    578: #endif
1.23      daniel    579:        return(NULL);
1.1       daniel    580:     }
1.20      daniel    581: 
                    582:     /*
                    583:      * Allocate the Input buffer front-end.
1.1       daniel    584:      */
                    585:     ret = xmlAllocParserInputBuffer(enc);
                    586:     if (ret != NULL) {
1.23      daniel    587:        ret->context = context;
                    588:        ret->readcallback = xmlInputCallbackTable[i].readcallback;
                    589:        ret->closecallback = xmlInputCallbackTable[i].closecallback;
1.1       daniel    590:     }
                    591:     return(ret);
                    592: }
                    593: 
                    594: /**
                    595:  * xmlParserInputBufferCreateFile:
                    596:  * @file:  a FILE* 
                    597:  * @enc:  the charset encoding if known
                    598:  *
                    599:  * Create a buffered parser input for the progressive parsing of a FILE *
                    600:  * buffered C I/O
                    601:  *
                    602:  * Returns the new parser input or NULL
                    603:  */
                    604: xmlParserInputBufferPtr
                    605: xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
                    606:     xmlParserInputBufferPtr ret;
                    607: 
1.23      daniel    608:     if (xmlInputCallbackInitialized == 0)
                    609:        xmlRegisterDefaultInputCallbacks();
                    610: 
1.1       daniel    611:     if (file == NULL) return(NULL);
                    612: 
                    613:     ret = xmlAllocParserInputBuffer(enc);
1.23      daniel    614:     if (ret != NULL) {
                    615:         ret->context = file;
                    616:        ret->readcallback = xmlFileRead;
                    617:        ret->closecallback = xmlFileClose;
                    618:     }
1.1       daniel    619: 
                    620:     return(ret);
                    621: }
                    622: 
                    623: /**
                    624:  * xmlParserInputBufferCreateFd:
                    625:  * @fd:  a file descriptor number
                    626:  * @enc:  the charset encoding if known
                    627:  *
                    628:  * Create a buffered parser input for the progressive parsing for the input
                    629:  * from a file descriptor
                    630:  *
                    631:  * Returns the new parser input or NULL
                    632:  */
                    633: xmlParserInputBufferPtr
                    634: xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
                    635:     xmlParserInputBufferPtr ret;
                    636: 
                    637:     if (fd < 0) return(NULL);
                    638: 
                    639:     ret = xmlAllocParserInputBuffer(enc);
1.23      daniel    640:     if (ret != NULL) {
                    641:         ret->context = (void *) fd;
                    642:        ret->readcallback = xmlFdRead;
                    643:        ret->closecallback = xmlFdClose;
                    644:     }
1.1       daniel    645: 
                    646:     return(ret);
                    647: }
                    648: 
                    649: /**
1.24      daniel    650:  * xmlParserInputBufferCreateIO:
                    651:  * @ioread:  an I/O read function
                    652:  * @ioclose:  an I/O close function
                    653:  * @ioctx:  an I/O handler
                    654:  * @enc:  the charset encoding if known
                    655:  *
                    656:  * Create a buffered parser input for the progressive parsing for the input
                    657:  * from a file descriptor
                    658:  *
                    659:  * Returns the new parser input or NULL
                    660:  */
                    661: xmlParserInputBufferPtr
                    662: xmlParserInputBufferCreateIO(xmlInputReadCallback   ioread,
                    663:         xmlInputCloseCallback  ioclose, void *ioctx, xmlCharEncoding enc) {
                    664:     xmlParserInputBufferPtr ret;
                    665: 
                    666:     if (ioread == NULL) return(NULL);
                    667: 
                    668:     ret = xmlAllocParserInputBuffer(enc);
                    669:     if (ret != NULL) {
                    670:         ret->context = (void *) ioctx;
                    671:        ret->readcallback = ioread;
                    672:        ret->closecallback = ioclose;
                    673:     }
                    674: 
                    675:     return(ret);
                    676: }
                    677: 
                    678: /**
1.14      daniel    679:  * xmlParserInputBufferPush:
                    680:  * @in:  a buffered parser input
                    681:  * @buf:  an char array
                    682:  * @len:  the size in bytes of the array.
                    683:  *
                    684:  * Push the content of the arry in the input buffer
                    685:  * This routine handle the I18N transcoding to internal UTF-8
                    686:  * This is used when operating the parser in progressive (push) mode.
                    687:  *
                    688:  * Returns the number of chars read and stored in the buffer, or -1
                    689:  *         in case of error.
                    690:  */
                    691: int
1.15      daniel    692: xmlParserInputBufferPush(xmlParserInputBufferPtr in, int len, const char *buf) {
1.14      daniel    693:     int nbchars = 0;
                    694: 
                    695:     if (len < 0) return(0);
                    696:     if (in->encoder != NULL) {
1.26    ! daniel    697:         /*
        !           698:         * Store the data in the incoming raw buffer
        !           699:         */
        !           700:         if (in->raw == NULL) {
        !           701:            in->raw = xmlBufferCreate();
        !           702:        }
        !           703:        xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
1.14      daniel    704: 
                    705:        /*
1.26    ! daniel    706:         * convert as much as possible to the parser reading buffer.
1.14      daniel    707:         */
1.26    ! daniel    708:        nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
1.20      daniel    709:        if (nbchars < 0) {
                    710:            fprintf(stderr, "xmlParserInputBufferPush: encoder error\n");
                    711:            return(-1);
                    712:        }
1.14      daniel    713:     } else {
                    714:        nbchars = len;
1.17      daniel    715:         xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
1.14      daniel    716:     }
                    717: #ifdef DEBUG_INPUT
                    718:     fprintf(stderr, "I/O: pushed %d chars, buffer %d/%d\n",
                    719:             nbchars, in->buffer->use, in->buffer->size);
                    720: #endif
                    721:     return(nbchars);
                    722: }
                    723: 
                    724: /**
1.1       daniel    725:  * xmlParserInputBufferGrow:
                    726:  * @in:  a buffered parser input
                    727:  * @len:  indicative value of the amount of chars to read
                    728:  *
                    729:  * Grow up the content of the input buffer, the old data are preserved
                    730:  * This routine handle the I18N transcoding to internal UTF-8
1.14      daniel    731:  * This routine is used when operating the parser in normal (pull) mode
1.26    ! daniel    732:  *
        !           733:  * TODO: one should be able to remove one extra copy by copying directy
        !           734:  *       onto in->buffer or in->raw
1.1       daniel    735:  *
                    736:  * Returns the number of chars read and stored in the buffer, or -1
                    737:  *         in case of error.
                    738:  */
                    739: int
                    740: xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
                    741:     char *buffer = NULL;
                    742:     int res = 0;
                    743:     int nbchars = 0;
                    744:     int buffree;
                    745: 
                    746:     if ((len <= MINLEN) && (len != 4)) 
                    747:         len = MINLEN;
                    748:     buffree = in->buffer->size - in->buffer->use;
                    749:     if (buffree <= 0) {
                    750:         fprintf(stderr, "xmlParserInputBufferGrow : buffer full !\n");
                    751:        return(0);
                    752:     }
                    753:     if (len > buffree) 
                    754:         len = buffree;
                    755: 
1.8       daniel    756:     buffer = xmlMalloc((len + 1) * sizeof(char));
1.1       daniel    757:     if (buffer == NULL) {
                    758:         fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
                    759:        return(-1);
                    760:     }
1.23      daniel    761: 
                    762:     /*
                    763:      * Call the read method for this I/O type.
                    764:      */
                    765:     if (in->readcallback != NULL) {
                    766:        res = in->readcallback(in->context, &buffer[0], len);
1.1       daniel    767:     } else {
                    768:         fprintf(stderr, "xmlParserInputBufferGrow : no input !\n");
1.8       daniel    769:        xmlFree(buffer);
1.1       daniel    770:        return(-1);
                    771:     }
1.23      daniel    772: 
1.1       daniel    773:     if (res == 0) {
1.8       daniel    774:        xmlFree(buffer);
1.1       daniel    775:         return(0);
                    776:     }
                    777:     if (res < 0) {
                    778:        perror ("read error");
1.8       daniel    779:        xmlFree(buffer);
1.1       daniel    780:        return(-1);
                    781:     }
                    782:     if (in->encoder != NULL) {
1.26    ! daniel    783:         /*
        !           784:         * Store the data in the incoming raw buffer
        !           785:         */
        !           786:         if (in->raw == NULL) {
        !           787:            in->raw = xmlBufferCreate();
1.1       daniel    788:        }
1.26    ! daniel    789:        xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
1.20      daniel    790: 
                    791:        /*
1.26    ! daniel    792:         * convert as much as possible to the parser reading buffer.
1.20      daniel    793:         */
1.26    ! daniel    794:        nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
        !           795:        if (nbchars < 0) {
        !           796:            fprintf(stderr, "xmlParserInputBufferGrow: encoder error\n");
        !           797:            return(-1);
1.20      daniel    798:        }
1.1       daniel    799:     } else {
                    800:        nbchars = res;
1.3       veillard  801:         buffer[nbchars] = 0;
1.13      daniel    802:         xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
1.1       daniel    803:     }
                    804: #ifdef DEBUG_INPUT
                    805:     fprintf(stderr, "I/O: read %d chars, buffer %d/%d\n",
                    806:             nbchars, in->buffer->use, in->buffer->size);
                    807: #endif
1.8       daniel    808:     xmlFree(buffer);
1.1       daniel    809:     return(nbchars);
                    810: }
                    811: 
                    812: /**
                    813:  * xmlParserInputBufferRead:
                    814:  * @in:  a buffered parser input
                    815:  * @len:  indicative value of the amount of chars to read
                    816:  *
                    817:  * Refresh the content of the input buffer, the old data are considered
                    818:  * consumed
                    819:  * This routine handle the I18N transcoding to internal UTF-8
                    820:  *
                    821:  * Returns the number of chars read and stored in the buffer, or -1
                    822:  *         in case of error.
                    823:  */
                    824: int
                    825: xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
                    826:     /* xmlBufferEmpty(in->buffer); */
1.23      daniel    827:     if (in->readcallback != NULL)
1.17      daniel    828:        return(xmlParserInputBufferGrow(in, len));
                    829:     else
                    830:         return(0);
1.4       daniel    831: }
                    832: 
                    833: /*
                    834:  * xmlParserGetDirectory:
                    835:  * @filename:  the path to a file
                    836:  *
                    837:  * lookup the directory for that file
                    838:  *
                    839:  * Returns a new allocated string containing the directory, or NULL.
                    840:  */
                    841: char *
                    842: xmlParserGetDirectory(const char *filename) {
                    843:     char *ret = NULL;
                    844:     char dir[1024];
                    845:     char *cur;
                    846:     char sep = '/';
1.23      daniel    847: 
                    848:     if (xmlInputCallbackInitialized == 0)
                    849:        xmlRegisterDefaultInputCallbacks();
1.4       daniel    850: 
                    851:     if (filename == NULL) return(NULL);
                    852: #ifdef WIN32
                    853:     sep = '\\';
                    854: #endif
                    855: 
                    856:     strncpy(dir, filename, 1023);
                    857:     dir[1023] = 0;
                    858:     cur = &dir[strlen(dir)];
                    859:     while (cur > dir) {
                    860:          if (*cur == sep) break;
                    861:         cur --;
                    862:     }
                    863:     if (*cur == sep) {
                    864:         if (cur == dir) dir[1] = 0;
                    865:        else *cur = 0;
1.8       daniel    866:        ret = xmlMemStrdup(dir);
1.4       daniel    867:     } else {
                    868:         if (getcwd(dir, 1024) != NULL) {
                    869:            dir[1023] = 0;
1.8       daniel    870:            ret = xmlMemStrdup(dir);
1.4       daniel    871:        }
                    872:     }
                    873:     return(ret);
1.5       daniel    874: }
                    875: 
                    876: /****************************************************************
                    877:  *                                                             *
                    878:  *             External entities loading                       *
                    879:  *                                                             *
                    880:  ****************************************************************/
                    881: 
                    882: /*
                    883:  * xmlDefaultExternalEntityLoader:
                    884:  * @URL:  the URL for the entity to load
                    885:  * @ID:  the System ID for the entity to load
1.18      daniel    886:  * @ctxt:  the context in which the entity is called or NULL
1.5       daniel    887:  *
                    888:  * By default we don't load external entitites, yet.
                    889:  *
                    890:  * Returns a new allocated xmlParserInputPtr, or NULL.
                    891:  */
                    892: static
                    893: xmlParserInputPtr
                    894: xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
1.18      daniel    895:                                xmlParserCtxtPtr ctxt) {
                    896:     xmlParserInputPtr ret = NULL;
1.5       daniel    897: #ifdef DEBUG_EXTERNAL_ENTITIES
                    898:     fprintf(stderr, "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
                    899: #endif
1.18      daniel    900:     if (URL == NULL) {
                    901:         if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
                    902:            ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n",
                    903:                               ID);
                    904:         return(NULL);
                    905:     }
                    906:     ret = xmlNewInputFromFile(ctxt, URL);
                    907:     if (ret == NULL) {
                    908:         if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
                    909:            ctxt->sax->warning(ctxt, "failed to load external entity \"%s\"\n",
                    910:                               URL);
                    911:     }
                    912:     return(ret);
1.5       daniel    913: }
                    914: 
                    915: static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
                    916:        xmlDefaultExternalEntityLoader;
                    917: 
                    918: /*
                    919:  * xmlSetExternalEntityLoader:
                    920:  * @f:  the new entity resolver function
                    921:  *
                    922:  * Changes the defaultexternal entity resolver function for the application
                    923:  */
                    924: void
                    925: xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
                    926:     xmlCurrentExternalEntityLoader = f;
                    927: }
                    928: 
                    929: /*
                    930:  * xmlGetExternalEntityLoader:
                    931:  *
                    932:  * Get the default external entity resolver function for the application
                    933:  *
                    934:  * Returns the xmlExternalEntityLoader function pointer
                    935:  */
                    936: xmlExternalEntityLoader
                    937: xmlGetExternalEntityLoader(void) {
                    938:     return(xmlCurrentExternalEntityLoader);
                    939: }
                    940: 
                    941: /*
                    942:  * xmlLoadExternalEntity:
                    943:  * @URL:  the URL for the entity to load
                    944:  * @ID:  the System ID for the entity to load
1.18      daniel    945:  * @ctxt:  the context in which the entity is called or NULL
1.5       daniel    946:  *
                    947:  * Load an external entity, note that the use of this function for
                    948:  * unparsed entities may generate problems
1.6       daniel    949:  * TODO: a more generic External entitiy API must be designed
1.5       daniel    950:  *
                    951:  * Returns the xmlParserInputPtr or NULL
                    952:  */
                    953: xmlParserInputPtr
                    954: xmlLoadExternalEntity(const char *URL, const char *ID,
1.18      daniel    955:                       xmlParserCtxtPtr ctxt) {
                    956:     return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
1.1       daniel    957: }
                    958: 

Webmaster