Annotation of XML/xmlIO.c, revision 1.12

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: /**
                    253:  * xmlParserInputBufferGrow:
                    254:  * @in:  a buffered parser input
                    255:  * @len:  indicative value of the amount of chars to read
                    256:  *
                    257:  * Grow up the content of the input buffer, the old data are preserved
                    258:  * This routine handle the I18N transcoding to internal UTF-8
1.7       daniel    259:  * TODO: one should be able to remove one extra copy
1.1       daniel    260:  *
                    261:  * Returns the number of chars read and stored in the buffer, or -1
                    262:  *         in case of error.
                    263:  */
                    264: int
                    265: xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
                    266:     char *buffer = NULL;
                    267: #ifdef HAVE_ZLIB_H
                    268:     gzFile input = (gzFile) in->gzfile;
                    269: #endif
                    270:     int res = 0;
                    271:     int nbchars = 0;
                    272:     int buffree;
                    273: 
                    274:     if ((len <= MINLEN) && (len != 4)) 
                    275:         len = MINLEN;
                    276:     buffree = in->buffer->size - in->buffer->use;
                    277:     if (buffree <= 0) {
                    278:         fprintf(stderr, "xmlParserInputBufferGrow : buffer full !\n");
                    279:        return(0);
                    280:     }
                    281:     if (len > buffree) 
                    282:         len = buffree;
                    283: 
1.8       daniel    284:     buffer = xmlMalloc((len + 1) * sizeof(char));
1.1       daniel    285:     if (buffer == NULL) {
                    286:         fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
                    287:        return(-1);
                    288:     }
1.11      daniel    289:     if (in->netIO != NULL) {
                    290:         res = xmlNanoHTTPRead(in->netIO, &buffer[0], len);
                    291:     } else if (in->file != NULL) {
1.1       daniel    292:        res = fread(&buffer[0], 1, len, in->file);
                    293: #ifdef HAVE_ZLIB_H
                    294:     } else if (in->gzfile != NULL) {
                    295:        res = gzread(input, &buffer[0], len);
                    296: #endif
                    297:     } else if (in->fd >= 0) {
                    298:        res = read(in->fd, &buffer[0], len);
                    299:     } else {
                    300:         fprintf(stderr, "xmlParserInputBufferGrow : no input !\n");
1.8       daniel    301:        xmlFree(buffer);
1.1       daniel    302:        return(-1);
                    303:     }
                    304:     if (res == 0) {
1.8       daniel    305:        xmlFree(buffer);
1.1       daniel    306:         return(0);
                    307:     }
                    308:     if (res < 0) {
                    309:        perror ("read error");
1.8       daniel    310:        xmlFree(buffer);
1.1       daniel    311:        return(-1);
                    312:     }
                    313:     if (in->encoder != NULL) {
                    314:         CHAR *buf;
                    315: 
1.8       daniel    316:        buf = (CHAR *) xmlMalloc((res + 1) * 2 * sizeof(CHAR));
1.1       daniel    317:        if (buf == NULL) {
                    318:            fprintf(stderr, "xmlParserInputBufferGrow : out of memory !\n");
1.8       daniel    319:            xmlFree(buffer);
1.1       daniel    320:            return(-1);
                    321:        }
                    322:        nbchars = in->encoder->input(buf, (res + 1) * 2 * sizeof(CHAR),
1.6       daniel    323:                                     BAD_CAST buffer, res);
1.3       veillard  324:         buf[nbchars] = 0;
1.1       daniel    325:         xmlBufferAdd(in->buffer, (CHAR *) buf, nbchars);
1.8       daniel    326:        xmlFree(buf);
1.1       daniel    327:     } else {
                    328:        nbchars = res;
1.3       veillard  329:         buffer[nbchars] = 0;
1.1       daniel    330:         xmlBufferAdd(in->buffer, (CHAR *) buffer, nbchars);
                    331:     }
                    332: #ifdef DEBUG_INPUT
                    333:     fprintf(stderr, "I/O: read %d chars, buffer %d/%d\n",
                    334:             nbchars, in->buffer->use, in->buffer->size);
                    335: #endif
1.8       daniel    336:     xmlFree(buffer);
1.1       daniel    337:     return(nbchars);
                    338: }
                    339: 
                    340: /**
                    341:  * xmlParserInputBufferRead:
                    342:  * @in:  a buffered parser input
                    343:  * @len:  indicative value of the amount of chars to read
                    344:  *
                    345:  * Refresh the content of the input buffer, the old data are considered
                    346:  * consumed
                    347:  * This routine handle the I18N transcoding to internal UTF-8
                    348:  *
                    349:  * Returns the number of chars read and stored in the buffer, or -1
                    350:  *         in case of error.
                    351:  */
                    352: int
                    353: xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
                    354:     /* xmlBufferEmpty(in->buffer); */
                    355:     return(xmlParserInputBufferGrow(in, len));
1.4       daniel    356: }
                    357: 
                    358: /*
                    359:  * xmlParserGetDirectory:
                    360:  * @filename:  the path to a file
                    361:  *
                    362:  * lookup the directory for that file
                    363:  *
                    364:  * Returns a new allocated string containing the directory, or NULL.
                    365:  */
                    366: char *
                    367: xmlParserGetDirectory(const char *filename) {
                    368:     char *ret = NULL;
                    369:     char dir[1024];
                    370:     char *cur;
                    371:     char sep = '/';
                    372: 
                    373:     if (filename == NULL) return(NULL);
                    374: #ifdef WIN32
                    375:     sep = '\\';
                    376: #endif
                    377: 
                    378:     strncpy(dir, filename, 1023);
                    379:     dir[1023] = 0;
                    380:     cur = &dir[strlen(dir)];
                    381:     while (cur > dir) {
                    382:          if (*cur == sep) break;
                    383:         cur --;
                    384:     }
                    385:     if (*cur == sep) {
                    386:         if (cur == dir) dir[1] = 0;
                    387:        else *cur = 0;
1.8       daniel    388:        ret = xmlMemStrdup(dir);
1.4       daniel    389:     } else {
                    390:         if (getcwd(dir, 1024) != NULL) {
                    391:            dir[1023] = 0;
1.8       daniel    392:            ret = xmlMemStrdup(dir);
1.4       daniel    393:        }
                    394:     }
                    395:     return(ret);
1.5       daniel    396: }
                    397: 
                    398: /****************************************************************
                    399:  *                                                             *
                    400:  *             External entities loading                       *
                    401:  *                                                             *
                    402:  ****************************************************************/
                    403: 
                    404: /*
                    405:  * xmlDefaultExternalEntityLoader:
                    406:  * @URL:  the URL for the entity to load
                    407:  * @ID:  the System ID for the entity to load
                    408:  * @context:  the context in which the entity is called or NULL
                    409:  *
                    410:  * By default we don't load external entitites, yet.
                    411:  * TODO: get a sample http implementation and scan for existing one
                    412:  *       at compile time.
                    413:  *
                    414:  * Returns a new allocated xmlParserInputPtr, or NULL.
                    415:  */
                    416: static
                    417: xmlParserInputPtr
                    418: xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
                    419:                                xmlParserInputPtr context) {
                    420: #ifdef DEBUG_EXTERNAL_ENTITIES
                    421:     fprintf(stderr, "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
                    422: #endif
                    423:     return(NULL);
                    424: }
                    425: 
                    426: static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
                    427:        xmlDefaultExternalEntityLoader;
                    428: 
                    429: /*
                    430:  * xmlSetExternalEntityLoader:
                    431:  * @f:  the new entity resolver function
                    432:  *
                    433:  * Changes the defaultexternal entity resolver function for the application
                    434:  */
                    435: void
                    436: xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
                    437:     xmlCurrentExternalEntityLoader = f;
                    438: }
                    439: 
                    440: /*
                    441:  * xmlGetExternalEntityLoader:
                    442:  *
                    443:  * Get the default external entity resolver function for the application
                    444:  *
                    445:  * Returns the xmlExternalEntityLoader function pointer
                    446:  */
                    447: xmlExternalEntityLoader
                    448: xmlGetExternalEntityLoader(void) {
                    449:     return(xmlCurrentExternalEntityLoader);
                    450: }
                    451: 
                    452: /*
                    453:  * xmlLoadExternalEntity:
                    454:  * @URL:  the URL for the entity to load
                    455:  * @ID:  the System ID for the entity to load
                    456:  * @context:  the context in which the entity is called or NULL
                    457:  *
                    458:  * Load an external entity, note that the use of this function for
                    459:  * unparsed entities may generate problems
1.6       daniel    460:  * TODO: a more generic External entitiy API must be designed
1.5       daniel    461:  *
                    462:  * Returns the xmlParserInputPtr or NULL
                    463:  */
                    464: xmlParserInputPtr
                    465: xmlLoadExternalEntity(const char *URL, const char *ID,
                    466:                       xmlParserInputPtr context) {
                    467:     return(xmlCurrentExternalEntityLoader(URL, ID, context));
1.1       daniel    468: }
                    469: 

Webmaster