Annotation of XML/xmlIO.c, revision 1.14

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
                     10: #define HAVE_FCNTL_H
                     11: #include <io.h>
                     12: #else
1.12      daniel     13: #include "config.h"
1.10      daniel     14: #endif
                     15: 
                     16: #include <stdio.h>
                     17: #include <string.h>
1.1       daniel     18: 
1.10      daniel     19: #ifdef HAVE_SYS_TYPES_H
1.1       daniel     20: #include <sys/types.h>
1.10      daniel     21: #endif
                     22: #ifdef HAVE_SYS_STAT_H
1.1       daniel     23: #include <sys/stat.h>
1.10      daniel     24: #endif
                     25: #ifdef HAVE_FCNTL_H
1.1       daniel     26: #include <fcntl.h>
1.10      daniel     27: #endif
1.1       daniel     28: #ifdef HAVE_UNISTD_H
                     29: #include <unistd.h>
                     30: #endif
1.10      daniel     31: #ifdef HAVE_STDLIB_H
                     32: #include <stdlib.h>
                     33: #endif
1.1       daniel     34: #ifdef HAVE_ZLIB_H
                     35: #include <zlib.h>
                     36: #endif
                     37: 
1.8       daniel     38: #include "xmlmemory.h"
1.5       daniel     39: #include "parser.h"
1.1       daniel     40: #include "xmlIO.h"
1.9       daniel     41: #include "nanohttp.h"
1.1       daniel     42: 
                     43: /* #define DEBUG_INPUT */
1.2       daniel     44: /* #define VERBOSE_FAILURE */
1.5       daniel     45: /* #define DEBUG_EXTERNAL_ENTITIES */
1.1       daniel     46: 
                     47: #ifdef DEBUG_INPUT
                     48: #define MINLEN 40
                     49: #else
                     50: #define MINLEN 4000
                     51: #endif
                     52: 
                     53: /**
                     54:  * xmlAllocParserInputBuffer:
                     55:  * @enc:  the charset encoding if known
                     56:  *
                     57:  * Create a buffered parser input for progressive parsing
                     58:  *
                     59:  * Returns the new parser input or NULL
                     60:  */
                     61: xmlParserInputBufferPtr
                     62: xmlAllocParserInputBuffer(xmlCharEncoding enc) {
                     63:     xmlParserInputBufferPtr ret;
                     64: 
1.8       daniel     65:     ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
1.1       daniel     66:     if (ret == NULL) {
                     67:         fprintf(stderr, "xmlAllocParserInputBuffer : out of memory!\n");
                     68:        return(NULL);
                     69:     }
1.3       veillard   70:     memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
1.1       daniel     71:     ret->buffer = xmlBufferCreate();
                     72:     ret->encoder = xmlGetCharEncodingHandler(enc);
                     73:     ret->fd = -1;
1.11      daniel     74:     ret->netIO = NULL;
1.1       daniel     75: 
                     76:     return(ret);
                     77: }
                     78: 
                     79: /**
                     80:  * xmlFreeParserInputBuffer:
                     81:  * @in:  a buffered parser input
                     82:  *
                     83:  * Free up the memory used by a buffered parser input
                     84:  */
                     85: void
                     86: xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
                     87:     if (in->buffer != NULL) {
                     88:         xmlBufferFree(in->buffer);
                     89:        in->buffer = NULL;
                     90:     }
                     91: #ifdef HAVE_ZLIB_H
                     92:     if (in->gzfile != NULL)
                     93:         gzclose(in->gzfile);
                     94: #endif
1.11      daniel     95:     if (in->netIO != NULL)
                     96:         xmlNanoHTTPClose(in->netIO);
1.1       daniel     97:     if (in->fd >= 0)
                     98:         close(in->fd);
1.3       veillard   99:     memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
1.8       daniel    100:     xmlFree(in);
1.1       daniel    101: }
                    102: 
                    103: /**
                    104:  * xmlParserInputBufferCreateFilename:
                    105:  * @filename:  a C string containing the filename
                    106:  * @enc:  the charset encoding if known
                    107:  *
                    108:  * Create a buffered parser input for the progressive parsing of a file
                    109:  * If filename is "-' then we use stdin as the input.
                    110:  * Automatic support for ZLIB/Compress compressed document is provided
                    111:  * by default if found at compile-time.
                    112:  *
                    113:  * Returns the new parser input or NULL
                    114:  */
                    115: xmlParserInputBufferPtr
                    116: xmlParserInputBufferCreateFilename(const char *filename, xmlCharEncoding enc) {
                    117:     xmlParserInputBufferPtr ret;
                    118: #ifdef HAVE_ZLIB_H
1.12      daniel    119:     gzFile input = 0;
1.1       daniel    120: #else
                    121:     int input = -1;
                    122: #endif
1.11      daniel    123:     void *netIO = NULL;
1.1       daniel    124: 
                    125:     if (filename == NULL) return(NULL);
                    126: 
1.11      daniel    127:     if (!strncmp(filename, "http://", 7)) {
                    128:         netIO = xmlNanoHTTPOpen(filename, NULL);
                    129:         if (netIO == NULL) {
                    130: #ifdef VERBOSE_FAILURE
                    131:             fprintf (stderr, "Cannot read URL %s\n", filename);
                    132:             perror ("xmlNanoHTTPOpen failed");
                    133: #endif
                    134:             return(NULL);
                    135:        }
                    136:     } else if (!strcmp(filename, "-")) {
1.1       daniel    137: #ifdef HAVE_ZLIB_H
                    138:         input = gzdopen (fileno(stdin), "r");
                    139:         if (input == NULL) {
1.2       daniel    140: #ifdef VERBOSE_FAILURE
1.1       daniel    141:             fprintf (stderr, "Cannot read from stdin\n");
                    142:             perror ("gzdopen failed");
1.2       daniel    143: #endif
1.1       daniel    144:             return(NULL);
                    145:        }
                    146: #else
                    147: #ifdef WIN32
                    148:         input = -1;
                    149: #else
                    150:         input = fileno(stdin);
                    151: #endif
                    152:         if (input < 0) {
1.2       daniel    153: #ifdef VERBOSE_FAILURE
1.1       daniel    154:             fprintf (stderr, "Cannot read from stdin\n");
                    155:             perror ("open failed");
1.2       daniel    156: #endif
                    157:            return(NULL);
1.1       daniel    158:        }
                    159: #endif
                    160:     } else {
                    161: #ifdef HAVE_ZLIB_H
                    162:        input = gzopen (filename, "r");
                    163:        if (input == NULL) {
1.2       daniel    164: #ifdef VERBOSE_FAILURE
1.1       daniel    165:            fprintf (stderr, "Cannot read file %s :\n", filename);
                    166:            perror ("gzopen failed");
1.2       daniel    167: #endif
1.1       daniel    168:            return(NULL);
                    169:        }
                    170: #else
                    171: #ifdef WIN32
                    172:        input = _open (filename, O_RDONLY | _O_BINARY);
                    173: #else
                    174:        input = open (filename, O_RDONLY);
                    175: #endif
                    176:        if (input < 0) {
1.2       daniel    177: #ifdef VERBOSE_FAILURE
1.1       daniel    178:            fprintf (stderr, "Cannot read file %s :\n", filename);
                    179:            perror ("open failed");
1.2       daniel    180: #endif
1.1       daniel    181:            return(NULL);
                    182:        }
                    183: #endif
                    184:     }
                    185:     /* 
1.6       daniel    186:      * TODO : get the 4 first bytes and decode the charset
1.1       daniel    187:      * if enc == XML_CHAR_ENCODING_NONE
                    188:      * plug some encoding conversion routines here. !!!
                    189:      * enc = xmlDetectCharEncoding(buffer);
                    190:      */
                    191: 
                    192:     ret = xmlAllocParserInputBuffer(enc);
                    193:     if (ret != NULL) {
                    194: #ifdef HAVE_ZLIB_H
                    195:         ret->gzfile = input;
                    196: #else
                    197:         ret->fd = input;
                    198: #endif
1.11      daniel    199:         ret->netIO = netIO;
1.1       daniel    200:     }
                    201:     xmlParserInputBufferRead(ret, 4);
                    202: 
                    203:     return(ret);
                    204: }
                    205: 
                    206: /**
                    207:  * xmlParserInputBufferCreateFile:
                    208:  * @file:  a FILE* 
                    209:  * @enc:  the charset encoding if known
                    210:  *
                    211:  * Create a buffered parser input for the progressive parsing of a FILE *
                    212:  * buffered C I/O
                    213:  *
                    214:  * Returns the new parser input or NULL
                    215:  */
                    216: xmlParserInputBufferPtr
                    217: xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
                    218:     xmlParserInputBufferPtr ret;
                    219: 
                    220:     if (file == NULL) return(NULL);
                    221: 
                    222:     ret = xmlAllocParserInputBuffer(enc);
                    223:     if (ret != NULL)
                    224:         ret->file = file;
                    225: 
                    226:     return(ret);
                    227: }
                    228: 
                    229: /**
                    230:  * xmlParserInputBufferCreateFd:
                    231:  * @fd:  a file descriptor number
                    232:  * @enc:  the charset encoding if known
                    233:  *
                    234:  * Create a buffered parser input for the progressive parsing for the input
                    235:  * from a file descriptor
                    236:  *
                    237:  * Returns the new parser input or NULL
                    238:  */
                    239: xmlParserInputBufferPtr
                    240: xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
                    241:     xmlParserInputBufferPtr ret;
                    242: 
                    243:     if (fd < 0) return(NULL);
                    244: 
                    245:     ret = xmlAllocParserInputBuffer(enc);
                    246:     if (ret != NULL)
                    247:         ret->fd = fd;
                    248: 
                    249:     return(ret);
                    250: }
                    251: 
                    252: /**
1.14    ! daniel    253:  * xmlParserInputBufferPush:
        !           254:  * @in:  a buffered parser input
        !           255:  * @buf:  an char array
        !           256:  * @len:  the size in bytes of the array.
        !           257:  *
        !           258:  * Push the content of the arry in the input buffer
        !           259:  * This routine handle the I18N transcoding to internal UTF-8
        !           260:  * This is used when operating the parser in progressive (push) mode.
        !           261:  *
        !           262:  * Returns the number of chars read and stored in the buffer, or -1
        !           263:  *         in case of error.
        !           264:  */
        !           265: int
        !           266: xmlParserInputBufferPush(xmlParserInputBufferPtr in, int len, char *buf) {
        !           267:     char *buffer = NULL;
        !           268:     int nbchars = 0;
        !           269: 
        !           270:     if (len < 0) return(0);
        !           271:     if (in->encoder != NULL) {
        !           272:         xmlChar *buf;
        !           273: 
        !           274:        buf = (xmlChar *) xmlMalloc((len + 1) * 2 * sizeof(xmlChar));
        !           275:        if (buf == NULL) {
        !           276:            fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
        !           277:            xmlFree(buffer);
        !           278:            return(-1);
        !           279:        }
        !           280:        nbchars = in->encoder->input(buf, (len + 1) * 2 * sizeof(xmlChar),
        !           281:                                     BAD_CAST buffer, len);
        !           282:        /*
        !           283:         * TODO : we really need to have something atomic or the 
        !           284:         *        encoder must report the number of bytes read
        !           285:         */
        !           286:         buf[nbchars] = 0;
        !           287:         xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
        !           288:        xmlFree(buf);
        !           289:     } else {
        !           290:        nbchars = len;
        !           291:         buffer[nbchars] = 0;
        !           292:         xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
        !           293:     }
        !           294: #ifdef DEBUG_INPUT
        !           295:     fprintf(stderr, "I/O: pushed %d chars, buffer %d/%d\n",
        !           296:             nbchars, in->buffer->use, in->buffer->size);
        !           297: #endif
        !           298:     return(nbchars);
        !           299: }
        !           300: 
        !           301: /**
1.1       daniel    302:  * xmlParserInputBufferGrow:
                    303:  * @in:  a buffered parser input
                    304:  * @len:  indicative value of the amount of chars to read
                    305:  *
                    306:  * Grow up the content of the input buffer, the old data are preserved
                    307:  * This routine handle the I18N transcoding to internal UTF-8
1.14    ! daniel    308:  * This routine is used when operating the parser in normal (pull) mode
1.7       daniel    309:  * TODO: one should be able to remove one extra copy
1.1       daniel    310:  *
                    311:  * Returns the number of chars read and stored in the buffer, or -1
                    312:  *         in case of error.
                    313:  */
                    314: int
                    315: xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
                    316:     char *buffer = NULL;
                    317: #ifdef HAVE_ZLIB_H
                    318:     gzFile input = (gzFile) in->gzfile;
                    319: #endif
                    320:     int res = 0;
                    321:     int nbchars = 0;
                    322:     int buffree;
                    323: 
                    324:     if ((len <= MINLEN) && (len != 4)) 
                    325:         len = MINLEN;
                    326:     buffree = in->buffer->size - in->buffer->use;
                    327:     if (buffree <= 0) {
                    328:         fprintf(stderr, "xmlParserInputBufferGrow : buffer full !\n");
                    329:        return(0);
                    330:     }
                    331:     if (len > buffree) 
                    332:         len = buffree;
                    333: 
1.8       daniel    334:     buffer = xmlMalloc((len + 1) * sizeof(char));
1.1       daniel    335:     if (buffer == NULL) {
                    336:         fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
                    337:        return(-1);
                    338:     }
1.11      daniel    339:     if (in->netIO != NULL) {
                    340:         res = xmlNanoHTTPRead(in->netIO, &buffer[0], len);
                    341:     } else if (in->file != NULL) {
1.1       daniel    342:        res = fread(&buffer[0], 1, len, in->file);
                    343: #ifdef HAVE_ZLIB_H
                    344:     } else if (in->gzfile != NULL) {
                    345:        res = gzread(input, &buffer[0], len);
                    346: #endif
                    347:     } else if (in->fd >= 0) {
                    348:        res = read(in->fd, &buffer[0], len);
                    349:     } else {
                    350:         fprintf(stderr, "xmlParserInputBufferGrow : no input !\n");
1.8       daniel    351:        xmlFree(buffer);
1.1       daniel    352:        return(-1);
                    353:     }
                    354:     if (res == 0) {
1.8       daniel    355:        xmlFree(buffer);
1.1       daniel    356:         return(0);
                    357:     }
                    358:     if (res < 0) {
                    359:        perror ("read error");
1.8       daniel    360:        xmlFree(buffer);
1.1       daniel    361:        return(-1);
                    362:     }
                    363:     if (in->encoder != NULL) {
1.13      daniel    364:         xmlChar *buf;
1.1       daniel    365: 
1.13      daniel    366:        buf = (xmlChar *) xmlMalloc((res + 1) * 2 * sizeof(xmlChar));
1.1       daniel    367:        if (buf == NULL) {
                    368:            fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
1.8       daniel    369:            xmlFree(buffer);
1.1       daniel    370:            return(-1);
                    371:        }
1.13      daniel    372:        nbchars = in->encoder->input(buf, (res + 1) * 2 * sizeof(xmlChar),
1.6       daniel    373:                                     BAD_CAST buffer, res);
1.3       veillard  374:         buf[nbchars] = 0;
1.13      daniel    375:         xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
1.8       daniel    376:        xmlFree(buf);
1.1       daniel    377:     } else {
                    378:        nbchars = res;
1.3       veillard  379:         buffer[nbchars] = 0;
1.13      daniel    380:         xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
1.1       daniel    381:     }
                    382: #ifdef DEBUG_INPUT
                    383:     fprintf(stderr, "I/O: read %d chars, buffer %d/%d\n",
                    384:             nbchars, in->buffer->use, in->buffer->size);
                    385: #endif
1.8       daniel    386:     xmlFree(buffer);
1.1       daniel    387:     return(nbchars);
                    388: }
                    389: 
                    390: /**
                    391:  * xmlParserInputBufferRead:
                    392:  * @in:  a buffered parser input
                    393:  * @len:  indicative value of the amount of chars to read
                    394:  *
                    395:  * Refresh the content of the input buffer, the old data are considered
                    396:  * consumed
                    397:  * This routine handle the I18N transcoding to internal UTF-8
                    398:  *
                    399:  * Returns the number of chars read and stored in the buffer, or -1
                    400:  *         in case of error.
                    401:  */
                    402: int
                    403: xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
                    404:     /* xmlBufferEmpty(in->buffer); */
                    405:     return(xmlParserInputBufferGrow(in, len));
1.4       daniel    406: }
                    407: 
                    408: /*
                    409:  * xmlParserGetDirectory:
                    410:  * @filename:  the path to a file
                    411:  *
                    412:  * lookup the directory for that file
                    413:  *
                    414:  * Returns a new allocated string containing the directory, or NULL.
                    415:  */
                    416: char *
                    417: xmlParserGetDirectory(const char *filename) {
                    418:     char *ret = NULL;
                    419:     char dir[1024];
                    420:     char *cur;
                    421:     char sep = '/';
                    422: 
                    423:     if (filename == NULL) return(NULL);
                    424: #ifdef WIN32
                    425:     sep = '\\';
                    426: #endif
                    427: 
                    428:     strncpy(dir, filename, 1023);
                    429:     dir[1023] = 0;
                    430:     cur = &dir[strlen(dir)];
                    431:     while (cur > dir) {
                    432:          if (*cur == sep) break;
                    433:         cur --;
                    434:     }
                    435:     if (*cur == sep) {
                    436:         if (cur == dir) dir[1] = 0;
                    437:        else *cur = 0;
1.8       daniel    438:        ret = xmlMemStrdup(dir);
1.4       daniel    439:     } else {
                    440:         if (getcwd(dir, 1024) != NULL) {
                    441:            dir[1023] = 0;
1.8       daniel    442:            ret = xmlMemStrdup(dir);
1.4       daniel    443:        }
                    444:     }
                    445:     return(ret);
1.5       daniel    446: }
                    447: 
                    448: /****************************************************************
                    449:  *                                                             *
                    450:  *             External entities loading                       *
                    451:  *                                                             *
                    452:  ****************************************************************/
                    453: 
                    454: /*
                    455:  * xmlDefaultExternalEntityLoader:
                    456:  * @URL:  the URL for the entity to load
                    457:  * @ID:  the System ID for the entity to load
                    458:  * @context:  the context in which the entity is called or NULL
                    459:  *
                    460:  * By default we don't load external entitites, yet.
                    461:  * TODO: get a sample http implementation and scan for existing one
                    462:  *       at compile time.
                    463:  *
                    464:  * Returns a new allocated xmlParserInputPtr, or NULL.
                    465:  */
                    466: static
                    467: xmlParserInputPtr
                    468: xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
                    469:                                xmlParserInputPtr context) {
                    470: #ifdef DEBUG_EXTERNAL_ENTITIES
                    471:     fprintf(stderr, "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
                    472: #endif
                    473:     return(NULL);
                    474: }
                    475: 
                    476: static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
                    477:        xmlDefaultExternalEntityLoader;
                    478: 
                    479: /*
                    480:  * xmlSetExternalEntityLoader:
                    481:  * @f:  the new entity resolver function
                    482:  *
                    483:  * Changes the defaultexternal entity resolver function for the application
                    484:  */
                    485: void
                    486: xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
                    487:     xmlCurrentExternalEntityLoader = f;
                    488: }
                    489: 
                    490: /*
                    491:  * xmlGetExternalEntityLoader:
                    492:  *
                    493:  * Get the default external entity resolver function for the application
                    494:  *
                    495:  * Returns the xmlExternalEntityLoader function pointer
                    496:  */
                    497: xmlExternalEntityLoader
                    498: xmlGetExternalEntityLoader(void) {
                    499:     return(xmlCurrentExternalEntityLoader);
                    500: }
                    501: 
                    502: /*
                    503:  * xmlLoadExternalEntity:
                    504:  * @URL:  the URL for the entity to load
                    505:  * @ID:  the System ID for the entity to load
                    506:  * @context:  the context in which the entity is called or NULL
                    507:  *
                    508:  * Load an external entity, note that the use of this function for
                    509:  * unparsed entities may generate problems
1.6       daniel    510:  * TODO: a more generic External entitiy API must be designed
1.5       daniel    511:  *
                    512:  * Returns the xmlParserInputPtr or NULL
                    513:  */
                    514: xmlParserInputPtr
                    515: xmlLoadExternalEntity(const char *URL, const char *ID,
                    516:                       xmlParserInputPtr context) {
                    517:     return(xmlCurrentExternalEntityLoader(URL, ID, context));
1.1       daniel    518: }
                    519: 

Webmaster