Annotation of embedaddon/libxml2/xmlIO.c, revision 1.1.1.1

1.1       misho       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.com
                      7:  *
                      8:  * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
                      9:  */
                     10: 
                     11: #define IN_LIBXML
                     12: #include "libxml.h"
                     13: 
                     14: #include <string.h>
                     15: #ifdef HAVE_ERRNO_H
                     16: #include <errno.h>
                     17: #endif
                     18: 
                     19: 
                     20: #ifdef HAVE_SYS_TYPES_H
                     21: #include <sys/types.h>
                     22: #endif
                     23: #ifdef HAVE_SYS_STAT_H
                     24: #include <sys/stat.h>
                     25: #endif
                     26: #ifdef HAVE_FCNTL_H
                     27: #include <fcntl.h>
                     28: #endif
                     29: #ifdef HAVE_UNISTD_H
                     30: #include <unistd.h>
                     31: #endif
                     32: #ifdef HAVE_STDLIB_H
                     33: #include <stdlib.h>
                     34: #endif
                     35: #ifdef HAVE_ZLIB_H
                     36: #include <zlib.h>
                     37: #endif
                     38: 
                     39: #if defined(WIN32) || defined(_WIN32)
                     40: #include <windows.h>
                     41: #endif
                     42: 
                     43: #if defined(_WIN32_WCE)
                     44: #include <winnls.h> /* for CP_UTF8 */
                     45: #endif
                     46: 
                     47: /* Figure a portable way to know if a file is a directory. */
                     48: #ifndef HAVE_STAT
                     49: #  ifdef HAVE__STAT
                     50:      /* MS C library seems to define stat and _stat. The definition
                     51:         is identical. Still, mapping them to each other causes a warning. */
                     52: #    ifndef _MSC_VER
                     53: #      define stat(x,y) _stat(x,y)
                     54: #    endif
                     55: #    define HAVE_STAT
                     56: #  endif
                     57: #else
                     58: #  ifdef HAVE__STAT
                     59: #    if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
                     60: #      define stat _stat
                     61: #    endif
                     62: #  endif
                     63: #endif
                     64: #ifdef HAVE_STAT
                     65: #  ifndef S_ISDIR
                     66: #    ifdef _S_ISDIR
                     67: #      define S_ISDIR(x) _S_ISDIR(x)
                     68: #    else
                     69: #      ifdef S_IFDIR
                     70: #        ifndef S_IFMT
                     71: #          ifdef _S_IFMT
                     72: #            define S_IFMT _S_IFMT
                     73: #          endif
                     74: #        endif
                     75: #        ifdef S_IFMT
                     76: #          define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
                     77: #        endif
                     78: #      endif
                     79: #    endif
                     80: #  endif
                     81: #endif
                     82: 
                     83: #include <libxml/xmlmemory.h>
                     84: #include <libxml/parser.h>
                     85: #include <libxml/parserInternals.h>
                     86: #include <libxml/xmlIO.h>
                     87: #include <libxml/uri.h>
                     88: #include <libxml/nanohttp.h>
                     89: #include <libxml/nanoftp.h>
                     90: #include <libxml/xmlerror.h>
                     91: #ifdef LIBXML_CATALOG_ENABLED
                     92: #include <libxml/catalog.h>
                     93: #endif
                     94: #include <libxml/globals.h>
                     95: 
                     96: /* #define VERBOSE_FAILURE */
                     97: /* #define DEBUG_EXTERNAL_ENTITIES */
                     98: /* #define DEBUG_INPUT */
                     99: 
                    100: #ifdef DEBUG_INPUT
                    101: #define MINLEN 40
                    102: #else
                    103: #define MINLEN 4000
                    104: #endif
                    105: 
                    106: /*
                    107:  * Input I/O callback sets
                    108:  */
                    109: typedef struct _xmlInputCallback {
                    110:     xmlInputMatchCallback matchcallback;
                    111:     xmlInputOpenCallback opencallback;
                    112:     xmlInputReadCallback readcallback;
                    113:     xmlInputCloseCallback closecallback;
                    114: } xmlInputCallback;
                    115: 
                    116: #define MAX_INPUT_CALLBACK 15
                    117: 
                    118: static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
                    119: static int xmlInputCallbackNr = 0;
                    120: static int xmlInputCallbackInitialized = 0;
                    121: 
                    122: #ifdef LIBXML_OUTPUT_ENABLED
                    123: /*
                    124:  * Output I/O callback sets
                    125:  */
                    126: typedef struct _xmlOutputCallback {
                    127:     xmlOutputMatchCallback matchcallback;
                    128:     xmlOutputOpenCallback opencallback;
                    129:     xmlOutputWriteCallback writecallback;
                    130:     xmlOutputCloseCallback closecallback;
                    131: } xmlOutputCallback;
                    132: 
                    133: #define MAX_OUTPUT_CALLBACK 15
                    134: 
                    135: static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
                    136: static int xmlOutputCallbackNr = 0;
                    137: static int xmlOutputCallbackInitialized = 0;
                    138: 
                    139: xmlOutputBufferPtr
                    140: xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
                    141: #endif /* LIBXML_OUTPUT_ENABLED */
                    142: 
                    143: /************************************************************************
                    144:  *                                                                     *
                    145:  *             Tree memory error handler                               *
                    146:  *                                                                     *
                    147:  ************************************************************************/
                    148: 
                    149: static const char *IOerr[] = {
                    150:     "Unknown IO error",         /* UNKNOWN */
                    151:     "Permission denied",       /* EACCES */
                    152:     "Resource temporarily unavailable",/* EAGAIN */
                    153:     "Bad file descriptor",     /* EBADF */
                    154:     "Bad message",             /* EBADMSG */
                    155:     "Resource busy",           /* EBUSY */
                    156:     "Operation canceled",      /* ECANCELED */
                    157:     "No child processes",      /* ECHILD */
                    158:     "Resource deadlock avoided",/* EDEADLK */
                    159:     "Domain error",            /* EDOM */
                    160:     "File exists",             /* EEXIST */
                    161:     "Bad address",             /* EFAULT */
                    162:     "File too large",          /* EFBIG */
                    163:     "Operation in progress",   /* EINPROGRESS */
                    164:     "Interrupted function call",/* EINTR */
                    165:     "Invalid argument",                /* EINVAL */
                    166:     "Input/output error",      /* EIO */
                    167:     "Is a directory",          /* EISDIR */
                    168:     "Too many open files",     /* EMFILE */
                    169:     "Too many links",          /* EMLINK */
                    170:     "Inappropriate message buffer length",/* EMSGSIZE */
                    171:     "Filename too long",       /* ENAMETOOLONG */
                    172:     "Too many open files in system",/* ENFILE */
                    173:     "No such device",          /* ENODEV */
                    174:     "No such file or directory",/* ENOENT */
                    175:     "Exec format error",       /* ENOEXEC */
                    176:     "No locks available",      /* ENOLCK */
                    177:     "Not enough space",                /* ENOMEM */
                    178:     "No space left on device", /* ENOSPC */
                    179:     "Function not implemented",        /* ENOSYS */
                    180:     "Not a directory",         /* ENOTDIR */
                    181:     "Directory not empty",     /* ENOTEMPTY */
                    182:     "Not supported",           /* ENOTSUP */
                    183:     "Inappropriate I/O control operation",/* ENOTTY */
                    184:     "No such device or address",/* ENXIO */
                    185:     "Operation not permitted", /* EPERM */
                    186:     "Broken pipe",             /* EPIPE */
                    187:     "Result too large",                /* ERANGE */
                    188:     "Read-only file system",   /* EROFS */
                    189:     "Invalid seek",            /* ESPIPE */
                    190:     "No such process",         /* ESRCH */
                    191:     "Operation timed out",     /* ETIMEDOUT */
                    192:     "Improper link",           /* EXDEV */
                    193:     "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
                    194:     "encoder error",           /* XML_IO_ENCODER */
                    195:     "flush error",
                    196:     "write error",
                    197:     "no input",
                    198:     "buffer full",
                    199:     "loading error",
                    200:     "not a socket",            /* ENOTSOCK */
                    201:     "already connected",       /* EISCONN */
                    202:     "connection refused",      /* ECONNREFUSED */
                    203:     "unreachable network",     /* ENETUNREACH */
                    204:     "adddress in use",         /* EADDRINUSE */
                    205:     "already in use",          /* EALREADY */
                    206:     "unknown address familly", /* EAFNOSUPPORT */
                    207: };
                    208: 
                    209: #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
                    210: /**
                    211:  * __xmlIOWin32UTF8ToWChar:
                    212:  * @u8String:  uft-8 string
                    213:  *
                    214:  * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
                    215:  */
                    216: static wchar_t *
                    217: __xmlIOWin32UTF8ToWChar(const char *u8String)
                    218: {
                    219:     wchar_t *wString = NULL;
                    220: 
                    221:     if (u8String) {
                    222:         int wLen =
                    223:             MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
                    224:                                 -1, NULL, 0);
                    225:         if (wLen) {
                    226:             wString = xmlMalloc(wLen * sizeof(wchar_t));
                    227:             if (wString) {
                    228:                 if (MultiByteToWideChar
                    229:                     (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
                    230:                     xmlFree(wString);
                    231:                     wString = NULL;
                    232:                 }
                    233:             }
                    234:         }
                    235:     }
                    236: 
                    237:     return wString;
                    238: }
                    239: #endif
                    240: 
                    241: /**
                    242:  * xmlIOErrMemory:
                    243:  * @extra:  extra informations
                    244:  *
                    245:  * Handle an out of memory condition
                    246:  */
                    247: static void
                    248: xmlIOErrMemory(const char *extra)
                    249: {
                    250:     __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
                    251: }
                    252: 
                    253: /**
                    254:  * __xmlIOErr:
                    255:  * @code:  the error number
                    256:  * @
                    257:  * @extra:  extra informations
                    258:  *
                    259:  * Handle an I/O error
                    260:  */
                    261: void
                    262: __xmlIOErr(int domain, int code, const char *extra)
                    263: {
                    264:     unsigned int idx;
                    265: 
                    266:     if (code == 0) {
                    267: #ifdef HAVE_ERRNO_H
                    268:        if (errno == 0) code = 0;
                    269: #ifdef EACCES
                    270:         else if (errno == EACCES) code = XML_IO_EACCES;
                    271: #endif
                    272: #ifdef EAGAIN
                    273:         else if (errno == EAGAIN) code = XML_IO_EAGAIN;
                    274: #endif
                    275: #ifdef EBADF
                    276:         else if (errno == EBADF) code = XML_IO_EBADF;
                    277: #endif
                    278: #ifdef EBADMSG
                    279:         else if (errno == EBADMSG) code = XML_IO_EBADMSG;
                    280: #endif
                    281: #ifdef EBUSY
                    282:         else if (errno == EBUSY) code = XML_IO_EBUSY;
                    283: #endif
                    284: #ifdef ECANCELED
                    285:         else if (errno == ECANCELED) code = XML_IO_ECANCELED;
                    286: #endif
                    287: #ifdef ECHILD
                    288:         else if (errno == ECHILD) code = XML_IO_ECHILD;
                    289: #endif
                    290: #ifdef EDEADLK
                    291:         else if (errno == EDEADLK) code = XML_IO_EDEADLK;
                    292: #endif
                    293: #ifdef EDOM
                    294:         else if (errno == EDOM) code = XML_IO_EDOM;
                    295: #endif
                    296: #ifdef EEXIST
                    297:         else if (errno == EEXIST) code = XML_IO_EEXIST;
                    298: #endif
                    299: #ifdef EFAULT
                    300:         else if (errno == EFAULT) code = XML_IO_EFAULT;
                    301: #endif
                    302: #ifdef EFBIG
                    303:         else if (errno == EFBIG) code = XML_IO_EFBIG;
                    304: #endif
                    305: #ifdef EINPROGRESS
                    306:         else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
                    307: #endif
                    308: #ifdef EINTR
                    309:         else if (errno == EINTR) code = XML_IO_EINTR;
                    310: #endif
                    311: #ifdef EINVAL
                    312:         else if (errno == EINVAL) code = XML_IO_EINVAL;
                    313: #endif
                    314: #ifdef EIO
                    315:         else if (errno == EIO) code = XML_IO_EIO;
                    316: #endif
                    317: #ifdef EISDIR
                    318:         else if (errno == EISDIR) code = XML_IO_EISDIR;
                    319: #endif
                    320: #ifdef EMFILE
                    321:         else if (errno == EMFILE) code = XML_IO_EMFILE;
                    322: #endif
                    323: #ifdef EMLINK
                    324:         else if (errno == EMLINK) code = XML_IO_EMLINK;
                    325: #endif
                    326: #ifdef EMSGSIZE
                    327:         else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
                    328: #endif
                    329: #ifdef ENAMETOOLONG
                    330:         else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
                    331: #endif
                    332: #ifdef ENFILE
                    333:         else if (errno == ENFILE) code = XML_IO_ENFILE;
                    334: #endif
                    335: #ifdef ENODEV
                    336:         else if (errno == ENODEV) code = XML_IO_ENODEV;
                    337: #endif
                    338: #ifdef ENOENT
                    339:         else if (errno == ENOENT) code = XML_IO_ENOENT;
                    340: #endif
                    341: #ifdef ENOEXEC
                    342:         else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
                    343: #endif
                    344: #ifdef ENOLCK
                    345:         else if (errno == ENOLCK) code = XML_IO_ENOLCK;
                    346: #endif
                    347: #ifdef ENOMEM
                    348:         else if (errno == ENOMEM) code = XML_IO_ENOMEM;
                    349: #endif
                    350: #ifdef ENOSPC
                    351:         else if (errno == ENOSPC) code = XML_IO_ENOSPC;
                    352: #endif
                    353: #ifdef ENOSYS
                    354:         else if (errno == ENOSYS) code = XML_IO_ENOSYS;
                    355: #endif
                    356: #ifdef ENOTDIR
                    357:         else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
                    358: #endif
                    359: #ifdef ENOTEMPTY
                    360:         else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
                    361: #endif
                    362: #ifdef ENOTSUP
                    363:         else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
                    364: #endif
                    365: #ifdef ENOTTY
                    366:         else if (errno == ENOTTY) code = XML_IO_ENOTTY;
                    367: #endif
                    368: #ifdef ENXIO
                    369:         else if (errno == ENXIO) code = XML_IO_ENXIO;
                    370: #endif
                    371: #ifdef EPERM
                    372:         else if (errno == EPERM) code = XML_IO_EPERM;
                    373: #endif
                    374: #ifdef EPIPE
                    375:         else if (errno == EPIPE) code = XML_IO_EPIPE;
                    376: #endif
                    377: #ifdef ERANGE
                    378:         else if (errno == ERANGE) code = XML_IO_ERANGE;
                    379: #endif
                    380: #ifdef EROFS
                    381:         else if (errno == EROFS) code = XML_IO_EROFS;
                    382: #endif
                    383: #ifdef ESPIPE
                    384:         else if (errno == ESPIPE) code = XML_IO_ESPIPE;
                    385: #endif
                    386: #ifdef ESRCH
                    387:         else if (errno == ESRCH) code = XML_IO_ESRCH;
                    388: #endif
                    389: #ifdef ETIMEDOUT
                    390:         else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
                    391: #endif
                    392: #ifdef EXDEV
                    393:         else if (errno == EXDEV) code = XML_IO_EXDEV;
                    394: #endif
                    395: #ifdef ENOTSOCK
                    396:         else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
                    397: #endif
                    398: #ifdef EISCONN
                    399:         else if (errno == EISCONN) code = XML_IO_EISCONN;
                    400: #endif
                    401: #ifdef ECONNREFUSED
                    402:         else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
                    403: #endif
                    404: #ifdef ETIMEDOUT
                    405:         else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
                    406: #endif
                    407: #ifdef ENETUNREACH
                    408:         else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
                    409: #endif
                    410: #ifdef EADDRINUSE
                    411:         else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
                    412: #endif
                    413: #ifdef EINPROGRESS
                    414:         else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
                    415: #endif
                    416: #ifdef EALREADY
                    417:         else if (errno == EALREADY) code = XML_IO_EALREADY;
                    418: #endif
                    419: #ifdef EAFNOSUPPORT
                    420:         else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
                    421: #endif
                    422:         else code = XML_IO_UNKNOWN;
                    423: #endif /* HAVE_ERRNO_H */
                    424:     }
                    425:     idx = 0;
                    426:     if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
                    427:     if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
                    428: 
                    429:     __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
                    430: }
                    431: 
                    432: /**
                    433:  * xmlIOErr:
                    434:  * @code:  the error number
                    435:  * @extra:  extra informations
                    436:  *
                    437:  * Handle an I/O error
                    438:  */
                    439: static void
                    440: xmlIOErr(int code, const char *extra)
                    441: {
                    442:     __xmlIOErr(XML_FROM_IO, code, extra);
                    443: }
                    444: 
                    445: /**
                    446:  * __xmlLoaderErr:
                    447:  * @ctx: the parser context
                    448:  * @extra:  extra informations
                    449:  *
                    450:  * Handle a resource access error
                    451:  */
                    452: void
                    453: __xmlLoaderErr(void *ctx, const char *msg, const char *filename)
                    454: {
                    455:     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
                    456:     xmlStructuredErrorFunc schannel = NULL;
                    457:     xmlGenericErrorFunc channel = NULL;
                    458:     void *data = NULL;
                    459:     xmlErrorLevel level = XML_ERR_ERROR;
                    460: 
                    461:     if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
                    462:         (ctxt->instate == XML_PARSER_EOF))
                    463:        return;
                    464:     if ((ctxt != NULL) && (ctxt->sax != NULL)) {
                    465:         if (ctxt->validate) {
                    466:            channel = ctxt->sax->error;
                    467:            level = XML_ERR_ERROR;
                    468:        } else {
                    469:            channel = ctxt->sax->warning;
                    470:            level = XML_ERR_WARNING;
                    471:        }
                    472:        if (ctxt->sax->initialized == XML_SAX2_MAGIC)
                    473:            schannel = ctxt->sax->serror;
                    474:        data = ctxt->userData;
                    475:     }
                    476:     __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
                    477:                     XML_IO_LOAD_ERROR, level, NULL, 0,
                    478:                    filename, NULL, NULL, 0, 0,
                    479:                    msg, filename);
                    480: 
                    481: }
                    482: 
                    483: /************************************************************************
                    484:  *                                                                     *
                    485:  *             Tree memory error handler                               *
                    486:  *                                                                     *
                    487:  ************************************************************************/
                    488: /**
                    489:  * xmlNormalizeWindowsPath:
                    490:  * @path: the input file path
                    491:  *
                    492:  * This function is obsolete. Please see xmlURIFromPath in uri.c for
                    493:  * a better solution.
                    494:  *
                    495:  * Returns a canonicalized version of the path
                    496:  */
                    497: xmlChar *
                    498: xmlNormalizeWindowsPath(const xmlChar *path)
                    499: {
                    500:     return xmlCanonicPath(path);
                    501: }
                    502: 
                    503: /**
                    504:  * xmlCleanupInputCallbacks:
                    505:  *
                    506:  * clears the entire input callback table. this includes the
                    507:  * compiled-in I/O.
                    508:  */
                    509: void
                    510: xmlCleanupInputCallbacks(void)
                    511: {
                    512:     int i;
                    513: 
                    514:     if (!xmlInputCallbackInitialized)
                    515:         return;
                    516: 
                    517:     for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
                    518:         xmlInputCallbackTable[i].matchcallback = NULL;
                    519:         xmlInputCallbackTable[i].opencallback = NULL;
                    520:         xmlInputCallbackTable[i].readcallback = NULL;
                    521:         xmlInputCallbackTable[i].closecallback = NULL;
                    522:     }
                    523: 
                    524:     xmlInputCallbackNr = 0;
                    525:     xmlInputCallbackInitialized = 0;
                    526: }
                    527: 
                    528: /**
                    529:  * xmlPopInputCallbacks:
                    530:  *
                    531:  * Clear the top input callback from the input stack. this includes the
                    532:  * compiled-in I/O.
                    533:  *
                    534:  * Returns the number of input callback registered or -1 in case of error.
                    535:  */
                    536: int
                    537: xmlPopInputCallbacks(void)
                    538: {
                    539:     if (!xmlInputCallbackInitialized)
                    540:         return(-1);
                    541: 
                    542:     if (xmlInputCallbackNr <= 0)
                    543:         return(-1);
                    544: 
                    545:     xmlInputCallbackNr--;
                    546:     xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
                    547:     xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
                    548:     xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
                    549:     xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
                    550: 
                    551:     return(xmlInputCallbackNr);
                    552: }
                    553: 
                    554: #ifdef LIBXML_OUTPUT_ENABLED
                    555: /**
                    556:  * xmlCleanupOutputCallbacks:
                    557:  *
                    558:  * clears the entire output callback table. this includes the
                    559:  * compiled-in I/O callbacks.
                    560:  */
                    561: void
                    562: xmlCleanupOutputCallbacks(void)
                    563: {
                    564:     int i;
                    565: 
                    566:     if (!xmlOutputCallbackInitialized)
                    567:         return;
                    568: 
                    569:     for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
                    570:         xmlOutputCallbackTable[i].matchcallback = NULL;
                    571:         xmlOutputCallbackTable[i].opencallback = NULL;
                    572:         xmlOutputCallbackTable[i].writecallback = NULL;
                    573:         xmlOutputCallbackTable[i].closecallback = NULL;
                    574:     }
                    575: 
                    576:     xmlOutputCallbackNr = 0;
                    577:     xmlOutputCallbackInitialized = 0;
                    578: }
                    579: #endif /* LIBXML_OUTPUT_ENABLED */
                    580: 
                    581: /************************************************************************
                    582:  *                                                                     *
                    583:  *             Standard I/O for file accesses                          *
                    584:  *                                                                     *
                    585:  ************************************************************************/
                    586: 
                    587: #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
                    588: 
                    589: /**
                    590:  *  xmlWrapOpenUtf8:
                    591:  * @path:  the path in utf-8 encoding
                    592:  * @mode:  type of access (0 - read, 1 - write)
                    593:  *
                    594:  * function opens the file specified by @path
                    595:  *
                    596:  */
                    597: static FILE*
                    598: xmlWrapOpenUtf8(const char *path,int mode)
                    599: {
                    600:     FILE *fd = NULL;
                    601:     wchar_t *wPath;
                    602: 
                    603:     wPath = __xmlIOWin32UTF8ToWChar(path);
                    604:     if(wPath)
                    605:     {
                    606:        fd = _wfopen(wPath, mode ? L"wb" : L"rb");
                    607:        xmlFree(wPath);
                    608:     }
                    609:     /* maybe path in native encoding */
                    610:     if(fd == NULL)
                    611:        fd = fopen(path, mode ? "wb" : "rb");
                    612: 
                    613:     return fd;
                    614: }
                    615: 
                    616: #ifdef HAVE_ZLIB_H
                    617: static gzFile
                    618: xmlWrapGzOpenUtf8(const char *path, const char *mode)
                    619: {
                    620:     gzFile fd;
                    621:     wchar_t *wPath;
                    622: 
                    623:     fd = gzopen (path, mode);
                    624:     if (fd)
                    625:         return fd;
                    626: 
                    627:     wPath = __xmlIOWin32UTF8ToWChar(path);
                    628:     if(wPath)
                    629:     {
                    630:        int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
                    631: #ifdef _O_BINARY
                    632:         m |= (strstr(mode, "b") ? _O_BINARY : 0);
                    633: #endif
                    634:        d = _wopen(wPath, m);
                    635:        if (d >= 0)
                    636:            fd = gzdopen(d, mode);
                    637:         xmlFree(wPath);
                    638:     }
                    639: 
                    640:     return fd;
                    641: }
                    642: #endif
                    643: 
                    644: /**
                    645:  *  xmlWrapStatUtf8:
                    646:  * @path:  the path in utf-8 encoding
                    647:  * @info:  structure that stores results
                    648:  *
                    649:  * function obtains information about the file or directory
                    650:  *
                    651:  */
                    652: static int
                    653: xmlWrapStatUtf8(const char *path,struct stat *info)
                    654: {
                    655: #ifdef HAVE_STAT
                    656:     int retval = -1;
                    657:     wchar_t *wPath;
                    658: 
                    659:     wPath = __xmlIOWin32UTF8ToWChar(path);
                    660:     if (wPath)
                    661:     {
                    662:        retval = _wstat(wPath,info);
                    663:        xmlFree(wPath);
                    664:     }
                    665:     /* maybe path in native encoding */
                    666:     if(retval < 0)
                    667:        retval = stat(path,info);
                    668:     return retval;
                    669: #else
                    670:     return -1;
                    671: #endif
                    672: }
                    673: 
                    674: /**
                    675:  *  xmlWrapOpenNative:
                    676:  * @path:  the path
                    677:  * @mode:  type of access (0 - read, 1 - write)
                    678:  *
                    679:  * function opens the file specified by @path
                    680:  *
                    681:  */
                    682: static FILE*
                    683: xmlWrapOpenNative(const char *path,int mode)
                    684: {
                    685:     return fopen(path,mode ? "wb" : "rb");
                    686: }
                    687: 
                    688: /**
                    689:  *  xmlWrapStatNative:
                    690:  * @path:  the path
                    691:  * @info:  structure that stores results
                    692:  *
                    693:  * function obtains information about the file or directory
                    694:  *
                    695:  */
                    696: static int
                    697: xmlWrapStatNative(const char *path,struct stat *info)
                    698: {
                    699: #ifdef HAVE_STAT
                    700:     return stat(path,info);
                    701: #else
                    702:     return -1;
                    703: #endif
                    704: }
                    705: 
                    706: typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
                    707: static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
                    708: typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
                    709: static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
                    710: #ifdef HAVE_ZLIB_H
                    711: typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode);
                    712: static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen;
                    713: #endif
                    714: /**
                    715:  * xmlInitPlatformSpecificIo:
                    716:  *
                    717:  * Initialize platform specific features.
                    718:  */
                    719: static void
                    720: xmlInitPlatformSpecificIo(void)
                    721: {
                    722:     static int xmlPlatformIoInitialized = 0;
                    723:     OSVERSIONINFO osvi;
                    724: 
                    725:     if(xmlPlatformIoInitialized)
                    726:       return;
                    727: 
                    728:     osvi.dwOSVersionInfoSize = sizeof(osvi);
                    729: 
                    730:     if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
                    731:       xmlWrapStat = xmlWrapStatUtf8;
                    732:       xmlWrapOpen = xmlWrapOpenUtf8;
                    733: #ifdef HAVE_ZLIB_H
                    734:       xmlWrapGzOpen = xmlWrapGzOpenUtf8;
                    735: #endif
                    736:     } else {
                    737:       xmlWrapStat = xmlWrapStatNative;
                    738:       xmlWrapOpen = xmlWrapOpenNative;
                    739: #ifdef HAVE_ZLIB_H
                    740:       xmlWrapGzOpen = gzopen;
                    741: #endif
                    742:     }
                    743: 
                    744:     xmlPlatformIoInitialized = 1;
                    745:     return;
                    746: }
                    747: 
                    748: #endif
                    749: 
                    750: /**
                    751:  * xmlCheckFilename:
                    752:  * @path:  the path to check
                    753:  *
                    754:  * function checks to see if @path is a valid source
                    755:  * (file, socket...) for XML.
                    756:  *
                    757:  * if stat is not available on the target machine,
                    758:  * returns 1.  if stat fails, returns 0 (if calling
                    759:  * stat on the filename fails, it can't be right).
                    760:  * if stat succeeds and the file is a directory,
                    761:  * returns 2.  otherwise returns 1.
                    762:  */
                    763: 
                    764: int
                    765: xmlCheckFilename (const char *path)
                    766: {
                    767: #ifdef HAVE_STAT
                    768:        struct stat stat_buffer;
                    769: #endif
                    770:        if (path == NULL)
                    771:                return(0);
                    772: 
                    773: #ifdef HAVE_STAT
                    774: #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
                    775:     if (xmlWrapStat(path, &stat_buffer) == -1)
                    776:         return 0;
                    777: #else
                    778:     if (stat(path, &stat_buffer) == -1)
                    779:         return 0;
                    780: #endif
                    781: #ifdef S_ISDIR
                    782:     if (S_ISDIR(stat_buffer.st_mode))
                    783:         return 2;
                    784: #endif
                    785: #endif /* HAVE_STAT */
                    786:     return 1;
                    787: }
                    788: 
                    789: static int
                    790: xmlNop(void) {
                    791:     return(0);
                    792: }
                    793: 
                    794: /**
                    795:  * xmlFdRead:
                    796:  * @context:  the I/O context
                    797:  * @buffer:  where to drop data
                    798:  * @len:  number of bytes to read
                    799:  *
                    800:  * Read @len bytes to @buffer from the I/O channel.
                    801:  *
                    802:  * Returns the number of bytes written
                    803:  */
                    804: static int
                    805: xmlFdRead (void * context, char * buffer, int len) {
                    806:     int ret;
                    807: 
                    808:     ret = read((int) (long) context, &buffer[0], len);
                    809:     if (ret < 0) xmlIOErr(0, "read()");
                    810:     return(ret);
                    811: }
                    812: 
                    813: #ifdef LIBXML_OUTPUT_ENABLED
                    814: /**
                    815:  * xmlFdWrite:
                    816:  * @context:  the I/O context
                    817:  * @buffer:  where to get data
                    818:  * @len:  number of bytes to write
                    819:  *
                    820:  * Write @len bytes from @buffer to the I/O channel.
                    821:  *
                    822:  * Returns the number of bytes written
                    823:  */
                    824: static int
                    825: xmlFdWrite (void * context, const char * buffer, int len) {
                    826:     int ret = 0;
                    827: 
                    828:     if (len > 0) {
                    829:        ret = write((int) (long) context, &buffer[0], len);
                    830:        if (ret < 0) xmlIOErr(0, "write()");
                    831:     }
                    832:     return(ret);
                    833: }
                    834: #endif /* LIBXML_OUTPUT_ENABLED */
                    835: 
                    836: /**
                    837:  * xmlFdClose:
                    838:  * @context:  the I/O context
                    839:  *
                    840:  * Close an I/O channel
                    841:  *
                    842:  * Returns 0 in case of success and error code otherwise
                    843:  */
                    844: static int
                    845: xmlFdClose (void * context) {
                    846:     int ret;
                    847:     ret = close((int) (long) context);
                    848:     if (ret < 0) xmlIOErr(0, "close()");
                    849:     return(ret);
                    850: }
                    851: 
                    852: /**
                    853:  * xmlFileMatch:
                    854:  * @filename:  the URI for matching
                    855:  *
                    856:  * input from FILE *
                    857:  *
                    858:  * Returns 1 if matches, 0 otherwise
                    859:  */
                    860: int
                    861: xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
                    862:     return(1);
                    863: }
                    864: 
                    865: /**
                    866:  * xmlFileOpen_real:
                    867:  * @filename:  the URI for matching
                    868:  *
                    869:  * input from FILE *, supports compressed input
                    870:  * if @filename is " " then the standard input is used
                    871:  *
                    872:  * Returns an I/O context or NULL in case of error
                    873:  */
                    874: static void *
                    875: xmlFileOpen_real (const char *filename) {
                    876:     const char *path = NULL;
                    877:     FILE *fd;
                    878: 
                    879:     if (filename == NULL)
                    880:         return(NULL);
                    881: 
                    882:     if (!strcmp(filename, "-")) {
                    883:        fd = stdin;
                    884:        return((void *) fd);
                    885:     }
                    886: 
                    887:     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
                    888: #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
                    889:        path = &filename[17];
                    890: #else
                    891:        path = &filename[16];
                    892: #endif
                    893:     } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
                    894: #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
                    895:        path = &filename[8];
                    896: #else
                    897:        path = &filename[7];
                    898: #endif
                    899:     } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
                    900:         /* lots of generators seems to lazy to read RFC 1738 */
                    901: #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
                    902:        path = &filename[6];
                    903: #else
                    904:        path = &filename[5];
                    905: #endif
                    906:     } else
                    907:        path = filename;
                    908: 
                    909:     if (path == NULL)
                    910:        return(NULL);
                    911:     if (!xmlCheckFilename(path))
                    912:         return(NULL);
                    913: 
                    914: #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
                    915:     fd = xmlWrapOpen(path, 0);
                    916: #else
                    917:     fd = fopen(path, "r");
                    918: #endif /* WIN32 */
                    919:     if (fd == NULL) xmlIOErr(0, path);
                    920:     return((void *) fd);
                    921: }
                    922: 
                    923: /**
                    924:  * xmlFileOpen:
                    925:  * @filename:  the URI for matching
                    926:  *
                    927:  * Wrapper around xmlFileOpen_real that try it with an unescaped
                    928:  * version of @filename, if this fails fallback to @filename
                    929:  *
                    930:  * Returns a handler or NULL in case or failure
                    931:  */
                    932: void *
                    933: xmlFileOpen (const char *filename) {
                    934:     char *unescaped;
                    935:     void *retval;
                    936: 
                    937:     retval = xmlFileOpen_real(filename);
                    938:     if (retval == NULL) {
                    939:        unescaped = xmlURIUnescapeString(filename, 0, NULL);
                    940:        if (unescaped != NULL) {
                    941:            retval = xmlFileOpen_real(unescaped);
                    942:            xmlFree(unescaped);
                    943:        }
                    944:     }
                    945: 
                    946:     return retval;
                    947: }
                    948: 
                    949: #ifdef LIBXML_OUTPUT_ENABLED
                    950: /**
                    951:  * xmlFileOpenW:
                    952:  * @filename:  the URI for matching
                    953:  *
                    954:  * output to from FILE *,
                    955:  * if @filename is "-" then the standard output is used
                    956:  *
                    957:  * Returns an I/O context or NULL in case of error
                    958:  */
                    959: static void *
                    960: xmlFileOpenW (const char *filename) {
                    961:     const char *path = NULL;
                    962:     FILE *fd;
                    963: 
                    964:     if (!strcmp(filename, "-")) {
                    965:        fd = stdout;
                    966:        return((void *) fd);
                    967:     }
                    968: 
                    969:     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
                    970: #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
                    971:        path = &filename[17];
                    972: #else
                    973:        path = &filename[16];
                    974: #endif
                    975:     else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
                    976: #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
                    977:        path = &filename[8];
                    978: #else
                    979:        path = &filename[7];
                    980: #endif
                    981:     } else
                    982:        path = filename;
                    983: 
                    984:     if (path == NULL)
                    985:        return(NULL);
                    986: 
                    987: #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
                    988:     fd = xmlWrapOpen(path, 1);
                    989: #else
                    990:           fd = fopen(path, "wb");
                    991: #endif /* WIN32 */
                    992: 
                    993:         if (fd == NULL) xmlIOErr(0, path);
                    994:     return((void *) fd);
                    995: }
                    996: #endif /* LIBXML_OUTPUT_ENABLED */
                    997: 
                    998: /**
                    999:  * xmlFileRead:
                   1000:  * @context:  the I/O context
                   1001:  * @buffer:  where to drop data
                   1002:  * @len:  number of bytes to write
                   1003:  *
                   1004:  * Read @len bytes to @buffer from the I/O channel.
                   1005:  *
                   1006:  * Returns the number of bytes written or < 0 in case of failure
                   1007:  */
                   1008: int
                   1009: xmlFileRead (void * context, char * buffer, int len) {
                   1010:     int ret;
                   1011:     if ((context == NULL) || (buffer == NULL))
                   1012:         return(-1);
                   1013:     ret = fread(&buffer[0], 1,  len, (FILE *) context);
                   1014:     if (ret < 0) xmlIOErr(0, "fread()");
                   1015:     return(ret);
                   1016: }
                   1017: 
                   1018: #ifdef LIBXML_OUTPUT_ENABLED
                   1019: /**
                   1020:  * xmlFileWrite:
                   1021:  * @context:  the I/O context
                   1022:  * @buffer:  where to drop data
                   1023:  * @len:  number of bytes to write
                   1024:  *
                   1025:  * Write @len bytes from @buffer to the I/O channel.
                   1026:  *
                   1027:  * Returns the number of bytes written
                   1028:  */
                   1029: static int
                   1030: xmlFileWrite (void * context, const char * buffer, int len) {
                   1031:     int items;
                   1032: 
                   1033:     if ((context == NULL) || (buffer == NULL))
                   1034:         return(-1);
                   1035:     items = fwrite(&buffer[0], len, 1, (FILE *) context);
                   1036:     if ((items == 0) && (ferror((FILE *) context))) {
                   1037:         xmlIOErr(0, "fwrite()");
                   1038:        return(-1);
                   1039:     }
                   1040:     return(items * len);
                   1041: }
                   1042: #endif /* LIBXML_OUTPUT_ENABLED */
                   1043: 
                   1044: /**
                   1045:  * xmlFileClose:
                   1046:  * @context:  the I/O context
                   1047:  *
                   1048:  * Close an I/O channel
                   1049:  *
                   1050:  * Returns 0 or -1 in case of error
                   1051:  */
                   1052: int
                   1053: xmlFileClose (void * context) {
                   1054:     FILE *fil;
                   1055:     int ret;
                   1056: 
                   1057:     if (context == NULL)
                   1058:         return(-1);
                   1059:     fil = (FILE *) context;
                   1060:     if ((fil == stdout) || (fil == stderr)) {
                   1061:         ret = fflush(fil);
                   1062:        if (ret < 0)
                   1063:            xmlIOErr(0, "fflush()");
                   1064:        return(0);
                   1065:     }
                   1066:     if (fil == stdin)
                   1067:        return(0);
                   1068:     ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
                   1069:     if (ret < 0)
                   1070:         xmlIOErr(0, "fclose()");
                   1071:     return(ret);
                   1072: }
                   1073: 
                   1074: /**
                   1075:  * xmlFileFlush:
                   1076:  * @context:  the I/O context
                   1077:  *
                   1078:  * Flush an I/O channel
                   1079:  */
                   1080: static int
                   1081: xmlFileFlush (void * context) {
                   1082:     int ret;
                   1083: 
                   1084:     if (context == NULL)
                   1085:         return(-1);
                   1086:     ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
                   1087:     if (ret < 0)
                   1088:         xmlIOErr(0, "fflush()");
                   1089:     return(ret);
                   1090: }
                   1091: 
                   1092: #ifdef LIBXML_OUTPUT_ENABLED
                   1093: /**
                   1094:  * xmlBufferWrite:
                   1095:  * @context:  the xmlBuffer
                   1096:  * @buffer:  the data to write
                   1097:  * @len:  number of bytes to write
                   1098:  *
                   1099:  * Write @len bytes from @buffer to the xml buffer
                   1100:  *
                   1101:  * Returns the number of bytes written
                   1102:  */
                   1103: static int
                   1104: xmlBufferWrite (void * context, const char * buffer, int len) {
                   1105:     int ret;
                   1106: 
                   1107:     ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
                   1108:     if (ret != 0)
                   1109:         return(-1);
                   1110:     return(len);
                   1111: }
                   1112: #endif
                   1113: 
                   1114: #ifdef HAVE_ZLIB_H
                   1115: /************************************************************************
                   1116:  *                                                                     *
                   1117:  *             I/O for compressed file accesses                        *
                   1118:  *                                                                     *
                   1119:  ************************************************************************/
                   1120: /**
                   1121:  * xmlGzfileMatch:
                   1122:  * @filename:  the URI for matching
                   1123:  *
                   1124:  * input from compressed file test
                   1125:  *
                   1126:  * Returns 1 if matches, 0 otherwise
                   1127:  */
                   1128: static int
                   1129: xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
                   1130:     return(1);
                   1131: }
                   1132: 
                   1133: /**
                   1134:  * xmlGzfileOpen_real:
                   1135:  * @filename:  the URI for matching
                   1136:  *
                   1137:  * input from compressed file open
                   1138:  * if @filename is " " then the standard input is used
                   1139:  *
                   1140:  * Returns an I/O context or NULL in case of error
                   1141:  */
                   1142: static void *
                   1143: xmlGzfileOpen_real (const char *filename) {
                   1144:     const char *path = NULL;
                   1145:     gzFile fd;
                   1146: 
                   1147:     if (!strcmp(filename, "-")) {
                   1148:         fd = gzdopen(dup(0), "rb");
                   1149:        return((void *) fd);
                   1150:     }
                   1151: 
                   1152:     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
                   1153: #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
                   1154:        path = &filename[17];
                   1155: #else
                   1156:        path = &filename[16];
                   1157: #endif
                   1158:     else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
                   1159: #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
                   1160:        path = &filename[8];
                   1161: #else
                   1162:        path = &filename[7];
                   1163: #endif
                   1164:     } else
                   1165:        path = filename;
                   1166: 
                   1167:     if (path == NULL)
                   1168:        return(NULL);
                   1169:     if (!xmlCheckFilename(path))
                   1170:         return(NULL);
                   1171: 
                   1172: #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
                   1173:     fd = xmlWrapGzOpen(path, "rb");
                   1174: #else
                   1175:     fd = gzopen(path, "rb");
                   1176: #endif
                   1177:     return((void *) fd);
                   1178: }
                   1179: 
                   1180: /**
                   1181:  * xmlGzfileOpen:
                   1182:  * @filename:  the URI for matching
                   1183:  *
                   1184:  * Wrapper around xmlGzfileOpen if the open fais, it will
                   1185:  * try to unescape @filename
                   1186:  */
                   1187: static void *
                   1188: xmlGzfileOpen (const char *filename) {
                   1189:     char *unescaped;
                   1190:     void *retval;
                   1191: 
                   1192:     retval = xmlGzfileOpen_real(filename);
                   1193:     if (retval == NULL) {
                   1194:        unescaped = xmlURIUnescapeString(filename, 0, NULL);
                   1195:        if (unescaped != NULL) {
                   1196:            retval = xmlGzfileOpen_real(unescaped);
                   1197:        }
                   1198:        xmlFree(unescaped);
                   1199:     }
                   1200:     return retval;
                   1201: }
                   1202: 
                   1203: #ifdef LIBXML_OUTPUT_ENABLED
                   1204: /**
                   1205:  * xmlGzfileOpenW:
                   1206:  * @filename:  the URI for matching
                   1207:  * @compression:  the compression factor (0 - 9 included)
                   1208:  *
                   1209:  * input from compressed file open
                   1210:  * if @filename is " " then the standard input is used
                   1211:  *
                   1212:  * Returns an I/O context or NULL in case of error
                   1213:  */
                   1214: static void *
                   1215: xmlGzfileOpenW (const char *filename, int compression) {
                   1216:     const char *path = NULL;
                   1217:     char mode[15];
                   1218:     gzFile fd;
                   1219: 
                   1220:     snprintf(mode, sizeof(mode), "wb%d", compression);
                   1221:     if (!strcmp(filename, "-")) {
                   1222:         fd = gzdopen(dup(1), mode);
                   1223:        return((void *) fd);
                   1224:     }
                   1225: 
                   1226:     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
                   1227: #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
                   1228:        path = &filename[17];
                   1229: #else
                   1230:        path = &filename[16];
                   1231: #endif
                   1232:     else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
                   1233: #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
                   1234:        path = &filename[8];
                   1235: #else
                   1236:        path = &filename[7];
                   1237: #endif
                   1238:     } else
                   1239:        path = filename;
                   1240: 
                   1241:     if (path == NULL)
                   1242:        return(NULL);
                   1243: 
                   1244: #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
                   1245:     fd = xmlWrapGzOpen(path, mode);
                   1246: #else
                   1247:     fd = gzopen(path, mode);
                   1248: #endif
                   1249:     return((void *) fd);
                   1250: }
                   1251: #endif /* LIBXML_OUTPUT_ENABLED */
                   1252: 
                   1253: /**
                   1254:  * xmlGzfileRead:
                   1255:  * @context:  the I/O context
                   1256:  * @buffer:  where to drop data
                   1257:  * @len:  number of bytes to write
                   1258:  *
                   1259:  * Read @len bytes to @buffer from the compressed I/O channel.
                   1260:  *
                   1261:  * Returns the number of bytes written
                   1262:  */
                   1263: static int
                   1264: xmlGzfileRead (void * context, char * buffer, int len) {
                   1265:     int ret;
                   1266: 
                   1267:     ret = gzread((gzFile) context, &buffer[0], len);
                   1268:     if (ret < 0) xmlIOErr(0, "gzread()");
                   1269:     return(ret);
                   1270: }
                   1271: 
                   1272: #ifdef LIBXML_OUTPUT_ENABLED
                   1273: /**
                   1274:  * xmlGzfileWrite:
                   1275:  * @context:  the I/O context
                   1276:  * @buffer:  where to drop data
                   1277:  * @len:  number of bytes to write
                   1278:  *
                   1279:  * Write @len bytes from @buffer to the compressed I/O channel.
                   1280:  *
                   1281:  * Returns the number of bytes written
                   1282:  */
                   1283: static int
                   1284: xmlGzfileWrite (void * context, const char * buffer, int len) {
                   1285:     int ret;
                   1286: 
                   1287:     ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
                   1288:     if (ret < 0) xmlIOErr(0, "gzwrite()");
                   1289:     return(ret);
                   1290: }
                   1291: #endif /* LIBXML_OUTPUT_ENABLED */
                   1292: 
                   1293: /**
                   1294:  * xmlGzfileClose:
                   1295:  * @context:  the I/O context
                   1296:  *
                   1297:  * Close a compressed I/O channel
                   1298:  */
                   1299: static int
                   1300: xmlGzfileClose (void * context) {
                   1301:     int ret;
                   1302: 
                   1303:     ret =  (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
                   1304:     if (ret < 0) xmlIOErr(0, "gzclose()");
                   1305:     return(ret);
                   1306: }
                   1307: #endif /* HAVE_ZLIB_H */
                   1308: 
                   1309: #ifdef LIBXML_HTTP_ENABLED
                   1310: /************************************************************************
                   1311:  *                                                                     *
                   1312:  *                     I/O for HTTP file accesses                      *
                   1313:  *                                                                     *
                   1314:  ************************************************************************/
                   1315: 
                   1316: #ifdef LIBXML_OUTPUT_ENABLED
                   1317: typedef struct xmlIOHTTPWriteCtxt_
                   1318: {
                   1319:     int                        compression;
                   1320: 
                   1321:     char *             uri;
                   1322: 
                   1323:     void *             doc_buff;
                   1324: 
                   1325: } xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
                   1326: 
                   1327: #ifdef HAVE_ZLIB_H
                   1328: 
                   1329: #define DFLT_WBITS             ( -15 )
                   1330: #define DFLT_MEM_LVL           ( 8 )
                   1331: #define GZ_MAGIC1              ( 0x1f )
                   1332: #define GZ_MAGIC2              ( 0x8b )
                   1333: #define LXML_ZLIB_OS_CODE      ( 0x03 )
                   1334: #define INIT_HTTP_BUFF_SIZE    ( 32768 )
                   1335: #define DFLT_ZLIB_RATIO                ( 5 )
                   1336: 
                   1337: /*
                   1338: **  Data structure and functions to work with sending compressed data
                   1339: **  via HTTP.
                   1340: */
                   1341: 
                   1342: typedef struct xmlZMemBuff_
                   1343: {
                   1344:    unsigned long       size;
                   1345:    unsigned long       crc;
                   1346: 
                   1347:    unsigned char *     zbuff;
                   1348:    z_stream            zctrl;
                   1349: 
                   1350: } xmlZMemBuff, *xmlZMemBuffPtr;
                   1351: 
                   1352: /**
                   1353:  * append_reverse_ulong
                   1354:  * @buff:  Compressed memory buffer
                   1355:  * @data:  Unsigned long to append
                   1356:  *
                   1357:  * Append a unsigned long in reverse byte order to the end of the
                   1358:  * memory buffer.
                   1359:  */
                   1360: static void
                   1361: append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
                   1362: 
                   1363:     int                idx;
                   1364: 
                   1365:     if ( buff == NULL )
                   1366:        return;
                   1367: 
                   1368:     /*
                   1369:     **  This is plagiarized from putLong in gzio.c (zlib source) where
                   1370:     **  the number "4" is hardcoded.  If zlib is ever patched to
                   1371:     **  support 64 bit file sizes, this code would need to be patched
                   1372:     **  as well.
                   1373:     */
                   1374: 
                   1375:     for ( idx = 0; idx < 4; idx++ ) {
                   1376:        *buff->zctrl.next_out = ( data & 0xff );
                   1377:        data >>= 8;
                   1378:        buff->zctrl.next_out++;
                   1379:     }
                   1380: 
                   1381:     return;
                   1382: }
                   1383: 
                   1384: /**
                   1385:  *
                   1386:  * xmlFreeZMemBuff
                   1387:  * @buff:  The memory buffer context to clear
                   1388:  *
                   1389:  * Release all the resources associated with the compressed memory buffer.
                   1390:  */
                   1391: static void
                   1392: xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
                   1393: 
                   1394: #ifdef DEBUG_HTTP
                   1395:     int z_err;
                   1396: #endif
                   1397: 
                   1398:     if ( buff == NULL )
                   1399:        return;
                   1400: 
                   1401:     xmlFree( buff->zbuff );
                   1402: #ifdef DEBUG_HTTP
                   1403:     z_err = deflateEnd( &buff->zctrl );
                   1404:     if ( z_err != Z_OK )
                   1405:        xmlGenericError( xmlGenericErrorContext,
                   1406:                        "xmlFreeZMemBuff:  Error releasing zlib context:  %d\n",
                   1407:                        z_err );
                   1408: #else
                   1409:     deflateEnd( &buff->zctrl );
                   1410: #endif
                   1411: 
                   1412:     xmlFree( buff );
                   1413:     return;
                   1414: }
                   1415: 
                   1416: /**
                   1417:  * xmlCreateZMemBuff
                   1418:  *@compression:        Compression value to use
                   1419:  *
                   1420:  * Create a memory buffer to hold the compressed XML document.  The
                   1421:  * compressed document in memory will end up being identical to what
                   1422:  * would be created if gzopen/gzwrite/gzclose were being used to
                   1423:  * write the document to disk.  The code for the header/trailer data to
                   1424:  * the compression is plagiarized from the zlib source files.
                   1425:  */
                   1426: static void *
                   1427: xmlCreateZMemBuff( int compression ) {
                   1428: 
                   1429:     int                        z_err;
                   1430:     int                        hdr_lgth;
                   1431:     xmlZMemBuffPtr     buff = NULL;
                   1432: 
                   1433:     if ( ( compression < 1 ) || ( compression > 9 ) )
                   1434:        return ( NULL );
                   1435: 
                   1436:     /*  Create the control and data areas  */
                   1437: 
                   1438:     buff = xmlMalloc( sizeof( xmlZMemBuff ) );
                   1439:     if ( buff == NULL ) {
                   1440:        xmlIOErrMemory("creating buffer context");
                   1441:        return ( NULL );
                   1442:     }
                   1443: 
                   1444:     (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
                   1445:     buff->size = INIT_HTTP_BUFF_SIZE;
                   1446:     buff->zbuff = xmlMalloc( buff->size );
                   1447:     if ( buff->zbuff == NULL ) {
                   1448:        xmlFreeZMemBuff( buff );
                   1449:        xmlIOErrMemory("creating buffer");
                   1450:        return ( NULL );
                   1451:     }
                   1452: 
                   1453:     z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
                   1454:                            DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
                   1455:     if ( z_err != Z_OK ) {
                   1456:        xmlChar msg[500];
                   1457:        xmlFreeZMemBuff( buff );
                   1458:        buff = NULL;
                   1459:        xmlStrPrintf(msg, 500,
                   1460:                    (const xmlChar *) "xmlCreateZMemBuff:  %s %d\n",
                   1461:                    "Error initializing compression context.  ZLIB error:",
                   1462:                    z_err );
                   1463:        xmlIOErr(XML_IO_WRITE, (const char *) msg);
                   1464:        return ( NULL );
                   1465:     }
                   1466: 
                   1467:     /*  Set the header data.  The CRC will be needed for the trailer  */
                   1468:     buff->crc = crc32( 0L, NULL, 0 );
                   1469:     hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
                   1470:                        "%c%c%c%c%c%c%c%c%c%c",
                   1471:                        GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
                   1472:                        0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
                   1473:     buff->zctrl.next_out  = buff->zbuff + hdr_lgth;
                   1474:     buff->zctrl.avail_out = buff->size - hdr_lgth;
                   1475: 
                   1476:     return ( buff );
                   1477: }
                   1478: 
                   1479: /**
                   1480:  * xmlZMemBuffExtend
                   1481:  * @buff:  Buffer used to compress and consolidate data.
                   1482:  * @ext_amt:   Number of bytes to extend the buffer.
                   1483:  *
                   1484:  * Extend the internal buffer used to store the compressed data by the
                   1485:  * specified amount.
                   1486:  *
                   1487:  * Returns 0 on success or -1 on failure to extend the buffer.  On failure
                   1488:  * the original buffer still exists at the original size.
                   1489:  */
                   1490: static int
                   1491: xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
                   1492: 
                   1493:     int                        rc = -1;
                   1494:     size_t             new_size;
                   1495:     size_t             cur_used;
                   1496: 
                   1497:     unsigned char *    tmp_ptr = NULL;
                   1498: 
                   1499:     if ( buff == NULL )
                   1500:        return ( -1 );
                   1501: 
                   1502:     else if ( ext_amt == 0 )
                   1503:        return ( 0 );
                   1504: 
                   1505:     cur_used = buff->zctrl.next_out - buff->zbuff;
                   1506:     new_size = buff->size + ext_amt;
                   1507: 
                   1508: #ifdef DEBUG_HTTP
                   1509:     if ( cur_used > new_size )
                   1510:        xmlGenericError( xmlGenericErrorContext,
                   1511:                        "xmlZMemBuffExtend:  %s\n%s %d bytes.\n",
                   1512:                        "Buffer overwrite detected during compressed memory",
                   1513:                        "buffer extension.  Overflowed by",
                   1514:                        (cur_used - new_size ) );
                   1515: #endif
                   1516: 
                   1517:     tmp_ptr = xmlRealloc( buff->zbuff, new_size );
                   1518:     if ( tmp_ptr != NULL ) {
                   1519:        rc = 0;
                   1520:        buff->size  = new_size;
                   1521:        buff->zbuff = tmp_ptr;
                   1522:        buff->zctrl.next_out  = tmp_ptr + cur_used;
                   1523:        buff->zctrl.avail_out = new_size - cur_used;
                   1524:     }
                   1525:     else {
                   1526:        xmlChar msg[500];
                   1527:        xmlStrPrintf(msg, 500,
                   1528:                    (const xmlChar *) "xmlZMemBuffExtend:  %s %lu bytes.\n",
                   1529:                    "Allocation failure extending output buffer to",
                   1530:                    new_size );
                   1531:        xmlIOErr(XML_IO_WRITE, (const char *) msg);
                   1532:     }
                   1533: 
                   1534:     return ( rc );
                   1535: }
                   1536: 
                   1537: /**
                   1538:  * xmlZMemBuffAppend
                   1539:  * @buff:  Buffer used to compress and consolidate data
                   1540:  * @src:   Uncompressed source content to append to buffer
                   1541:  * @len:   Length of source data to append to buffer
                   1542:  *
                   1543:  * Compress and append data to the internal buffer.  The data buffer
                   1544:  * will be expanded if needed to store the additional data.
                   1545:  *
                   1546:  * Returns the number of bytes appended to the buffer or -1 on error.
                   1547:  */
                   1548: static int
                   1549: xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
                   1550: 
                   1551:     int                z_err;
                   1552:     size_t     min_accept;
                   1553: 
                   1554:     if ( ( buff == NULL ) || ( src == NULL ) )
                   1555:        return ( -1 );
                   1556: 
                   1557:     buff->zctrl.avail_in = len;
                   1558:     buff->zctrl.next_in  = (unsigned char *)src;
                   1559:     while ( buff->zctrl.avail_in > 0 ) {
                   1560:        /*
                   1561:        **  Extend the buffer prior to deflate call if a reasonable amount
                   1562:        **  of output buffer space is not available.
                   1563:        */
                   1564:        min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
                   1565:        if ( buff->zctrl.avail_out <= min_accept ) {
                   1566:            if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
                   1567:                return ( -1 );
                   1568:        }
                   1569: 
                   1570:        z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
                   1571:        if ( z_err != Z_OK ) {
                   1572:            xmlChar msg[500];
                   1573:            xmlStrPrintf(msg, 500,
                   1574:                        (const xmlChar *) "xmlZMemBuffAppend:  %s %d %s - %d",
                   1575:                        "Compression error while appending",
                   1576:                        len, "bytes to buffer.  ZLIB error", z_err );
                   1577:            xmlIOErr(XML_IO_WRITE, (const char *) msg);
                   1578:            return ( -1 );
                   1579:        }
                   1580:     }
                   1581: 
                   1582:     buff->crc = crc32( buff->crc, (unsigned char *)src, len );
                   1583: 
                   1584:     return ( len );
                   1585: }
                   1586: 
                   1587: /**
                   1588:  * xmlZMemBuffGetContent
                   1589:  * @buff:  Compressed memory content buffer
                   1590:  * @data_ref:  Pointer reference to point to compressed content
                   1591:  *
                   1592:  * Flushes the compression buffers, appends gzip file trailers and
                   1593:  * returns the compressed content and length of the compressed data.
                   1594:  * NOTE:  The gzip trailer code here is plagiarized from zlib source.
                   1595:  *
                   1596:  * Returns the length of the compressed data or -1 on error.
                   1597:  */
                   1598: static int
                   1599: xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
                   1600: 
                   1601:     int                zlgth = -1;
                   1602:     int                z_err;
                   1603: 
                   1604:     if ( ( buff == NULL ) || ( data_ref == NULL ) )
                   1605:        return ( -1 );
                   1606: 
                   1607:     /*  Need to loop until compression output buffers are flushed  */
                   1608: 
                   1609:     do
                   1610:     {
                   1611:        z_err = deflate( &buff->zctrl, Z_FINISH );
                   1612:        if ( z_err == Z_OK ) {
                   1613:            /*  In this case Z_OK means more buffer space needed  */
                   1614: 
                   1615:            if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
                   1616:                return ( -1 );
                   1617:        }
                   1618:     }
                   1619:     while ( z_err == Z_OK );
                   1620: 
                   1621:     /*  If the compression state is not Z_STREAM_END, some error occurred  */
                   1622: 
                   1623:     if ( z_err == Z_STREAM_END ) {
                   1624: 
                   1625:        /*  Need to append the gzip data trailer  */
                   1626: 
                   1627:        if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
                   1628:            if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
                   1629:                return ( -1 );
                   1630:        }
                   1631: 
                   1632:        /*
                   1633:        **  For whatever reason, the CRC and length data are pushed out
                   1634:        **  in reverse byte order.  So a memcpy can't be used here.
                   1635:        */
                   1636: 
                   1637:        append_reverse_ulong( buff, buff->crc );
                   1638:        append_reverse_ulong( buff, buff->zctrl.total_in );
                   1639: 
                   1640:        zlgth = buff->zctrl.next_out - buff->zbuff;
                   1641:        *data_ref = (char *)buff->zbuff;
                   1642:     }
                   1643: 
                   1644:     else {
                   1645:        xmlChar msg[500];
                   1646:        xmlStrPrintf(msg, 500,
                   1647:                    (const xmlChar *) "xmlZMemBuffGetContent:  %s - %d\n",
                   1648:                    "Error flushing zlib buffers.  Error code", z_err );
                   1649:        xmlIOErr(XML_IO_WRITE, (const char *) msg);
                   1650:     }
                   1651: 
                   1652:     return ( zlgth );
                   1653: }
                   1654: #endif /* LIBXML_OUTPUT_ENABLED */
                   1655: #endif  /*  HAVE_ZLIB_H  */
                   1656: 
                   1657: #ifdef LIBXML_OUTPUT_ENABLED
                   1658: /**
                   1659:  * xmlFreeHTTPWriteCtxt
                   1660:  * @ctxt:  Context to cleanup
                   1661:  *
                   1662:  * Free allocated memory and reclaim system resources.
                   1663:  *
                   1664:  * No return value.
                   1665:  */
                   1666: static void
                   1667: xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
                   1668: {
                   1669:     if ( ctxt->uri != NULL )
                   1670:        xmlFree( ctxt->uri );
                   1671: 
                   1672:     if ( ctxt->doc_buff != NULL ) {
                   1673: 
                   1674: #ifdef HAVE_ZLIB_H
                   1675:        if ( ctxt->compression > 0 ) {
                   1676:            xmlFreeZMemBuff( ctxt->doc_buff );
                   1677:        }
                   1678:        else
                   1679: #endif
                   1680:        {
                   1681:            xmlOutputBufferClose( ctxt->doc_buff );
                   1682:        }
                   1683:     }
                   1684: 
                   1685:     xmlFree( ctxt );
                   1686:     return;
                   1687: }
                   1688: #endif /* LIBXML_OUTPUT_ENABLED */
                   1689: 
                   1690: 
                   1691: /**
                   1692:  * xmlIOHTTPMatch:
                   1693:  * @filename:  the URI for matching
                   1694:  *
                   1695:  * check if the URI matches an HTTP one
                   1696:  *
                   1697:  * Returns 1 if matches, 0 otherwise
                   1698:  */
                   1699: int
                   1700: xmlIOHTTPMatch (const char *filename) {
                   1701:     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
                   1702:        return(1);
                   1703:     return(0);
                   1704: }
                   1705: 
                   1706: /**
                   1707:  * xmlIOHTTPOpen:
                   1708:  * @filename:  the URI for matching
                   1709:  *
                   1710:  * open an HTTP I/O channel
                   1711:  *
                   1712:  * Returns an I/O context or NULL in case of error
                   1713:  */
                   1714: void *
                   1715: xmlIOHTTPOpen (const char *filename) {
                   1716:     return(xmlNanoHTTPOpen(filename, NULL));
                   1717: }
                   1718: 
                   1719: #ifdef LIBXML_OUTPUT_ENABLED
                   1720: /**
                   1721:  * xmlIOHTTPOpenW:
                   1722:  * @post_uri:  The destination URI for the document
                   1723:  * @compression:  The compression desired for the document.
                   1724:  *
                   1725:  * Open a temporary buffer to collect the document for a subsequent HTTP POST
                   1726:  * request.  Non-static as is called from the output buffer creation routine.
                   1727:  *
                   1728:  * Returns an I/O context or NULL in case of error.
                   1729:  */
                   1730: 
                   1731: void *
                   1732: xmlIOHTTPOpenW(const char *post_uri, int compression)
                   1733: {
                   1734: 
                   1735:     xmlIOHTTPWriteCtxtPtr ctxt = NULL;
                   1736: 
                   1737:     if (post_uri == NULL)
                   1738:         return (NULL);
                   1739: 
                   1740:     ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
                   1741:     if (ctxt == NULL) {
                   1742:        xmlIOErrMemory("creating HTTP output context");
                   1743:         return (NULL);
                   1744:     }
                   1745: 
                   1746:     (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
                   1747: 
                   1748:     ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
                   1749:     if (ctxt->uri == NULL) {
                   1750:        xmlIOErrMemory("copying URI");
                   1751:         xmlFreeHTTPWriteCtxt(ctxt);
                   1752:         return (NULL);
                   1753:     }
                   1754: 
                   1755:     /*
                   1756:      * **  Since the document length is required for an HTTP post,
                   1757:      * **  need to put the document into a buffer.  A memory buffer
                   1758:      * **  is being used to avoid pushing the data to disk and back.
                   1759:      */
                   1760: 
                   1761: #ifdef HAVE_ZLIB_H
                   1762:     if ((compression > 0) && (compression <= 9)) {
                   1763: 
                   1764:         ctxt->compression = compression;
                   1765:         ctxt->doc_buff = xmlCreateZMemBuff(compression);
                   1766:     } else
                   1767: #endif
                   1768:     {
                   1769:         /*  Any character conversions should have been done before this  */
                   1770: 
                   1771:         ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
                   1772:     }
                   1773: 
                   1774:     if (ctxt->doc_buff == NULL) {
                   1775:         xmlFreeHTTPWriteCtxt(ctxt);
                   1776:         ctxt = NULL;
                   1777:     }
                   1778: 
                   1779:     return (ctxt);
                   1780: }
                   1781: #endif /* LIBXML_OUTPUT_ENABLED */
                   1782: 
                   1783: #ifdef LIBXML_OUTPUT_ENABLED
                   1784: /**
                   1785:  * xmlIOHTTPDfltOpenW
                   1786:  * @post_uri:  The destination URI for this document.
                   1787:  *
                   1788:  * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
                   1789:  * HTTP post command.  This function should generally not be used as
                   1790:  * the open callback is short circuited in xmlOutputBufferCreateFile.
                   1791:  *
                   1792:  * Returns a pointer to the new IO context.
                   1793:  */
                   1794: static void *
                   1795: xmlIOHTTPDfltOpenW( const char * post_uri ) {
                   1796:     return ( xmlIOHTTPOpenW( post_uri, 0 ) );
                   1797: }
                   1798: #endif /* LIBXML_OUTPUT_ENABLED */
                   1799: 
                   1800: /**
                   1801:  * xmlIOHTTPRead:
                   1802:  * @context:  the I/O context
                   1803:  * @buffer:  where to drop data
                   1804:  * @len:  number of bytes to write
                   1805:  *
                   1806:  * Read @len bytes to @buffer from the I/O channel.
                   1807:  *
                   1808:  * Returns the number of bytes written
                   1809:  */
                   1810: int
                   1811: xmlIOHTTPRead(void * context, char * buffer, int len) {
                   1812:     if ((buffer == NULL) || (len < 0)) return(-1);
                   1813:     return(xmlNanoHTTPRead(context, &buffer[0], len));
                   1814: }
                   1815: 
                   1816: #ifdef LIBXML_OUTPUT_ENABLED
                   1817: /**
                   1818:  * xmlIOHTTPWrite
                   1819:  * @context:  previously opened writing context
                   1820:  * @buffer:   data to output to temporary buffer
                   1821:  * @len:      bytes to output
                   1822:  *
                   1823:  * Collect data from memory buffer into a temporary file for later
                   1824:  * processing.
                   1825:  *
                   1826:  * Returns number of bytes written.
                   1827:  */
                   1828: 
                   1829: static int
                   1830: xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
                   1831: 
                   1832:     xmlIOHTTPWriteCtxtPtr      ctxt = context;
                   1833: 
                   1834:     if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
                   1835:        return ( -1 );
                   1836: 
                   1837:     if ( len > 0 ) {
                   1838: 
                   1839:        /*  Use gzwrite or fwrite as previously setup in the open call  */
                   1840: 
                   1841: #ifdef HAVE_ZLIB_H
                   1842:        if ( ctxt->compression > 0 )
                   1843:            len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
                   1844: 
                   1845:        else
                   1846: #endif
                   1847:            len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
                   1848: 
                   1849:        if ( len < 0 ) {
                   1850:            xmlChar msg[500];
                   1851:            xmlStrPrintf(msg, 500,
                   1852:                        (const xmlChar *) "xmlIOHTTPWrite:  %s\n%s '%s'.\n",
                   1853:                        "Error appending to internal buffer.",
                   1854:                        "Error sending document to URI",
                   1855:                        ctxt->uri );
                   1856:            xmlIOErr(XML_IO_WRITE, (const char *) msg);
                   1857:        }
                   1858:     }
                   1859: 
                   1860:     return ( len );
                   1861: }
                   1862: #endif /* LIBXML_OUTPUT_ENABLED */
                   1863: 
                   1864: 
                   1865: /**
                   1866:  * xmlIOHTTPClose:
                   1867:  * @context:  the I/O context
                   1868:  *
                   1869:  * Close an HTTP I/O channel
                   1870:  *
                   1871:  * Returns 0
                   1872:  */
                   1873: int
                   1874: xmlIOHTTPClose (void * context) {
                   1875:     xmlNanoHTTPClose(context);
                   1876:     return 0;
                   1877: }
                   1878: 
                   1879: #ifdef LIBXML_OUTPUT_ENABLED
                   1880: /**
                   1881:  * xmlIOHTTCloseWrite
                   1882:  * @context:  The I/O context
                   1883:  * @http_mthd: The HTTP method to be used when sending the data
                   1884:  *
                   1885:  * Close the transmit HTTP I/O channel and actually send the data.
                   1886:  */
                   1887: static int
                   1888: xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
                   1889: 
                   1890:     int                                close_rc = -1;
                   1891:     int                                http_rtn = 0;
                   1892:     int                                content_lgth = 0;
                   1893:     xmlIOHTTPWriteCtxtPtr      ctxt = context;
                   1894: 
                   1895:     char *                     http_content = NULL;
                   1896:     char *                     content_encoding = NULL;
                   1897:     char *                     content_type = (char *) "text/xml";
                   1898:     void *                     http_ctxt = NULL;
                   1899: 
                   1900:     if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
                   1901:        return ( -1 );
                   1902: 
                   1903:     /*  Retrieve the content from the appropriate buffer  */
                   1904: 
                   1905: #ifdef HAVE_ZLIB_H
                   1906: 
                   1907:     if ( ctxt->compression > 0 ) {
                   1908:        content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
                   1909:        content_encoding = (char *) "Content-Encoding: gzip";
                   1910:     }
                   1911:     else
                   1912: #endif
                   1913:     {
                   1914:        /*  Pull the data out of the memory output buffer  */
                   1915: 
                   1916:        xmlOutputBufferPtr      dctxt = ctxt->doc_buff;
                   1917:        http_content = (char *)dctxt->buffer->content;
                   1918:        content_lgth = dctxt->buffer->use;
                   1919:     }
                   1920: 
                   1921:     if ( http_content == NULL ) {
                   1922:        xmlChar msg[500];
                   1923:        xmlStrPrintf(msg, 500,
                   1924:                     (const xmlChar *) "xmlIOHTTPCloseWrite:  %s '%s' %s '%s'.\n",
                   1925:                     "Error retrieving content.\nUnable to",
                   1926:                     http_mthd, "data to URI", ctxt->uri );
                   1927:        xmlIOErr(XML_IO_WRITE, (const char *) msg);
                   1928:     }
                   1929: 
                   1930:     else {
                   1931: 
                   1932:        http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
                   1933:                                        &content_type, content_encoding,
                   1934:                                        content_lgth );
                   1935: 
                   1936:        if ( http_ctxt != NULL ) {
                   1937: #ifdef DEBUG_HTTP
                   1938:            /*  If testing/debugging - dump reply with request content  */
                   1939: 
                   1940:            FILE *      tst_file = NULL;
                   1941:            char        buffer[ 4096 ];
                   1942:            char *      dump_name = NULL;
                   1943:            int         avail;
                   1944: 
                   1945:            xmlGenericError( xmlGenericErrorContext,
                   1946:                        "xmlNanoHTTPCloseWrite:  HTTP %s to\n%s returned %d.\n",
                   1947:                        http_mthd, ctxt->uri,
                   1948:                        xmlNanoHTTPReturnCode( http_ctxt ) );
                   1949: 
                   1950:            /*
                   1951:            **  Since either content or reply may be gzipped,
                   1952:            **  dump them to separate files instead of the
                   1953:            **  standard error context.
                   1954:            */
                   1955: 
                   1956:            dump_name = tempnam( NULL, "lxml" );
                   1957:            if ( dump_name != NULL ) {
                   1958:                (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
                   1959: 
                   1960:                tst_file = fopen( buffer, "wb" );
                   1961:                if ( tst_file != NULL ) {
                   1962:                    xmlGenericError( xmlGenericErrorContext,
                   1963:                        "Transmitted content saved in file:  %s\n", buffer );
                   1964: 
                   1965:                    fwrite( http_content, sizeof( char ),
                   1966:                                        content_lgth, tst_file );
                   1967:                    fclose( tst_file );
                   1968:                }
                   1969: 
                   1970:                (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
                   1971:                tst_file = fopen( buffer, "wb" );
                   1972:                if ( tst_file != NULL ) {
                   1973:                    xmlGenericError( xmlGenericErrorContext,
                   1974:                        "Reply content saved in file:  %s\n", buffer );
                   1975: 
                   1976: 
                   1977:                    while ( (avail = xmlNanoHTTPRead( http_ctxt,
                   1978:                                        buffer, sizeof( buffer ) )) > 0 ) {
                   1979: 
                   1980:                        fwrite( buffer, sizeof( char ), avail, tst_file );
                   1981:                    }
                   1982: 
                   1983:                    fclose( tst_file );
                   1984:                }
                   1985: 
                   1986:                free( dump_name );
                   1987:            }
                   1988: #endif  /*  DEBUG_HTTP  */
                   1989: 
                   1990:            http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
                   1991:            if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
                   1992:                close_rc = 0;
                   1993:            else {
                   1994:                 xmlChar msg[500];
                   1995:                 xmlStrPrintf(msg, 500,
                   1996:     (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
                   1997:                            http_mthd, content_lgth,
                   1998:                            "bytes to URI", ctxt->uri,
                   1999:                            "failed.  HTTP return code:", http_rtn );
                   2000:                xmlIOErr(XML_IO_WRITE, (const char *) msg);
                   2001:             }
                   2002: 
                   2003:            xmlNanoHTTPClose( http_ctxt );
                   2004:            xmlFree( content_type );
                   2005:        }
                   2006:     }
                   2007: 
                   2008:     /*  Final cleanups  */
                   2009: 
                   2010:     xmlFreeHTTPWriteCtxt( ctxt );
                   2011: 
                   2012:     return ( close_rc );
                   2013: }
                   2014: 
                   2015: /**
                   2016:  * xmlIOHTTPClosePut
                   2017:  *
                   2018:  * @context:  The I/O context
                   2019:  *
                   2020:  * Close the transmit HTTP I/O channel and actually send data using a PUT
                   2021:  * HTTP method.
                   2022:  */
                   2023: static int
                   2024: xmlIOHTTPClosePut( void * ctxt ) {
                   2025:     return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
                   2026: }
                   2027: 
                   2028: 
                   2029: /**
                   2030:  * xmlIOHTTPClosePost
                   2031:  *
                   2032:  * @context:  The I/O context
                   2033:  *
                   2034:  * Close the transmit HTTP I/O channel and actually send data using a POST
                   2035:  * HTTP method.
                   2036:  */
                   2037: static int
                   2038: xmlIOHTTPClosePost( void * ctxt ) {
                   2039:     return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
                   2040: }
                   2041: #endif /* LIBXML_OUTPUT_ENABLED */
                   2042: 
                   2043: #endif /* LIBXML_HTTP_ENABLED */
                   2044: 
                   2045: #ifdef LIBXML_FTP_ENABLED
                   2046: /************************************************************************
                   2047:  *                                                                     *
                   2048:  *                     I/O for FTP file accesses                       *
                   2049:  *                                                                     *
                   2050:  ************************************************************************/
                   2051: /**
                   2052:  * xmlIOFTPMatch:
                   2053:  * @filename:  the URI for matching
                   2054:  *
                   2055:  * check if the URI matches an FTP one
                   2056:  *
                   2057:  * Returns 1 if matches, 0 otherwise
                   2058:  */
                   2059: int
                   2060: xmlIOFTPMatch (const char *filename) {
                   2061:     if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
                   2062:        return(1);
                   2063:     return(0);
                   2064: }
                   2065: 
                   2066: /**
                   2067:  * xmlIOFTPOpen:
                   2068:  * @filename:  the URI for matching
                   2069:  *
                   2070:  * open an FTP I/O channel
                   2071:  *
                   2072:  * Returns an I/O context or NULL in case of error
                   2073:  */
                   2074: void *
                   2075: xmlIOFTPOpen (const char *filename) {
                   2076:     return(xmlNanoFTPOpen(filename));
                   2077: }
                   2078: 
                   2079: /**
                   2080:  * xmlIOFTPRead:
                   2081:  * @context:  the I/O context
                   2082:  * @buffer:  where to drop data
                   2083:  * @len:  number of bytes to write
                   2084:  *
                   2085:  * Read @len bytes to @buffer from the I/O channel.
                   2086:  *
                   2087:  * Returns the number of bytes written
                   2088:  */
                   2089: int
                   2090: xmlIOFTPRead(void * context, char * buffer, int len) {
                   2091:     if ((buffer == NULL) || (len < 0)) return(-1);
                   2092:     return(xmlNanoFTPRead(context, &buffer[0], len));
                   2093: }
                   2094: 
                   2095: /**
                   2096:  * xmlIOFTPClose:
                   2097:  * @context:  the I/O context
                   2098:  *
                   2099:  * Close an FTP I/O channel
                   2100:  *
                   2101:  * Returns 0
                   2102:  */
                   2103: int
                   2104: xmlIOFTPClose (void * context) {
                   2105:     return ( xmlNanoFTPClose(context) );
                   2106: }
                   2107: #endif /* LIBXML_FTP_ENABLED */
                   2108: 
                   2109: 
                   2110: /**
                   2111:  * xmlRegisterInputCallbacks:
                   2112:  * @matchFunc:  the xmlInputMatchCallback
                   2113:  * @openFunc:  the xmlInputOpenCallback
                   2114:  * @readFunc:  the xmlInputReadCallback
                   2115:  * @closeFunc:  the xmlInputCloseCallback
                   2116:  *
                   2117:  * Register a new set of I/O callback for handling parser input.
                   2118:  *
                   2119:  * Returns the registered handler number or -1 in case of error
                   2120:  */
                   2121: int
                   2122: xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
                   2123:        xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
                   2124:        xmlInputCloseCallback closeFunc) {
                   2125:     if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
                   2126:        return(-1);
                   2127:     }
                   2128:     xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
                   2129:     xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
                   2130:     xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
                   2131:     xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
                   2132:     xmlInputCallbackInitialized = 1;
                   2133:     return(xmlInputCallbackNr++);
                   2134: }
                   2135: 
                   2136: #ifdef LIBXML_OUTPUT_ENABLED
                   2137: /**
                   2138:  * xmlRegisterOutputCallbacks:
                   2139:  * @matchFunc:  the xmlOutputMatchCallback
                   2140:  * @openFunc:  the xmlOutputOpenCallback
                   2141:  * @writeFunc:  the xmlOutputWriteCallback
                   2142:  * @closeFunc:  the xmlOutputCloseCallback
                   2143:  *
                   2144:  * Register a new set of I/O callback for handling output.
                   2145:  *
                   2146:  * Returns the registered handler number or -1 in case of error
                   2147:  */
                   2148: int
                   2149: xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
                   2150:        xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
                   2151:        xmlOutputCloseCallback closeFunc) {
                   2152:     if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
                   2153:        return(-1);
                   2154:     }
                   2155:     xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
                   2156:     xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
                   2157:     xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
                   2158:     xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
                   2159:     xmlOutputCallbackInitialized = 1;
                   2160:     return(xmlOutputCallbackNr++);
                   2161: }
                   2162: #endif /* LIBXML_OUTPUT_ENABLED */
                   2163: 
                   2164: /**
                   2165:  * xmlRegisterDefaultInputCallbacks:
                   2166:  *
                   2167:  * Registers the default compiled-in I/O handlers.
                   2168:  */
                   2169: void
                   2170: xmlRegisterDefaultInputCallbacks(void) {
                   2171:     if (xmlInputCallbackInitialized)
                   2172:        return;
                   2173: 
                   2174: #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
                   2175:     xmlInitPlatformSpecificIo();
                   2176: #endif
                   2177: 
                   2178:     xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
                   2179:                              xmlFileRead, xmlFileClose);
                   2180: #ifdef HAVE_ZLIB_H
                   2181:     xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
                   2182:                              xmlGzfileRead, xmlGzfileClose);
                   2183: #endif /* HAVE_ZLIB_H */
                   2184: 
                   2185: #ifdef LIBXML_HTTP_ENABLED
                   2186:     xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
                   2187:                              xmlIOHTTPRead, xmlIOHTTPClose);
                   2188: #endif /* LIBXML_HTTP_ENABLED */
                   2189: 
                   2190: #ifdef LIBXML_FTP_ENABLED
                   2191:     xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
                   2192:                              xmlIOFTPRead, xmlIOFTPClose);
                   2193: #endif /* LIBXML_FTP_ENABLED */
                   2194:     xmlInputCallbackInitialized = 1;
                   2195: }
                   2196: 
                   2197: #ifdef LIBXML_OUTPUT_ENABLED
                   2198: /**
                   2199:  * xmlRegisterDefaultOutputCallbacks:
                   2200:  *
                   2201:  * Registers the default compiled-in I/O handlers.
                   2202:  */
                   2203: void
                   2204: xmlRegisterDefaultOutputCallbacks (void) {
                   2205:     if (xmlOutputCallbackInitialized)
                   2206:        return;
                   2207: 
                   2208: #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
                   2209:     xmlInitPlatformSpecificIo();
                   2210: #endif
                   2211: 
                   2212:     xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
                   2213:                              xmlFileWrite, xmlFileClose);
                   2214: 
                   2215: #ifdef LIBXML_HTTP_ENABLED
                   2216:     xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
                   2217:                               xmlIOHTTPWrite, xmlIOHTTPClosePut);
                   2218: #endif
                   2219: 
                   2220: /*********************************
                   2221:  No way a-priori to distinguish between gzipped files from
                   2222:  uncompressed ones except opening if existing then closing
                   2223:  and saving with same compression ratio ... a pain.
                   2224: 
                   2225: #ifdef HAVE_ZLIB_H
                   2226:     xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
                   2227:                               xmlGzfileWrite, xmlGzfileClose);
                   2228: #endif
                   2229: 
                   2230:  Nor FTP PUT ....
                   2231: #ifdef LIBXML_FTP_ENABLED
                   2232:     xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
                   2233:                               xmlIOFTPWrite, xmlIOFTPClose);
                   2234: #endif
                   2235:  **********************************/
                   2236:     xmlOutputCallbackInitialized = 1;
                   2237: }
                   2238: 
                   2239: #ifdef LIBXML_HTTP_ENABLED
                   2240: /**
                   2241:  * xmlRegisterHTTPPostCallbacks:
                   2242:  *
                   2243:  * By default, libxml submits HTTP output requests using the "PUT" method.
                   2244:  * Calling this method changes the HTTP output method to use the "POST"
                   2245:  * method instead.
                   2246:  *
                   2247:  */
                   2248: void
                   2249: xmlRegisterHTTPPostCallbacks( void ) {
                   2250: 
                   2251:     /*  Register defaults if not done previously  */
                   2252: 
                   2253:     if ( xmlOutputCallbackInitialized == 0 )
                   2254:        xmlRegisterDefaultOutputCallbacks( );
                   2255: 
                   2256:     xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
                   2257:                               xmlIOHTTPWrite, xmlIOHTTPClosePost);
                   2258:     return;
                   2259: }
                   2260: #endif
                   2261: #endif /* LIBXML_OUTPUT_ENABLED */
                   2262: 
                   2263: /**
                   2264:  * xmlAllocParserInputBuffer:
                   2265:  * @enc:  the charset encoding if known
                   2266:  *
                   2267:  * Create a buffered parser input for progressive parsing
                   2268:  *
                   2269:  * Returns the new parser input or NULL
                   2270:  */
                   2271: xmlParserInputBufferPtr
                   2272: xmlAllocParserInputBuffer(xmlCharEncoding enc) {
                   2273:     xmlParserInputBufferPtr ret;
                   2274: 
                   2275:     ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
                   2276:     if (ret == NULL) {
                   2277:        xmlIOErrMemory("creating input buffer");
                   2278:        return(NULL);
                   2279:     }
                   2280:     memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
                   2281:     ret->buffer = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
                   2282:     if (ret->buffer == NULL) {
                   2283:         xmlFree(ret);
                   2284:        return(NULL);
                   2285:     }
                   2286:     ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
                   2287:     ret->encoder = xmlGetCharEncodingHandler(enc);
                   2288:     if (ret->encoder != NULL)
                   2289:         ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
                   2290:     else
                   2291:         ret->raw = NULL;
                   2292:     ret->readcallback = NULL;
                   2293:     ret->closecallback = NULL;
                   2294:     ret->context = NULL;
                   2295:     ret->compressed = -1;
                   2296:     ret->rawconsumed = 0;
                   2297: 
                   2298:     return(ret);
                   2299: }
                   2300: 
                   2301: #ifdef LIBXML_OUTPUT_ENABLED
                   2302: /**
                   2303:  * xmlAllocOutputBuffer:
                   2304:  * @encoder:  the encoding converter or NULL
                   2305:  *
                   2306:  * Create a buffered parser output
                   2307:  *
                   2308:  * Returns the new parser output or NULL
                   2309:  */
                   2310: xmlOutputBufferPtr
                   2311: xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
                   2312:     xmlOutputBufferPtr ret;
                   2313: 
                   2314:     ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
                   2315:     if (ret == NULL) {
                   2316:        xmlIOErrMemory("creating output buffer");
                   2317:        return(NULL);
                   2318:     }
                   2319:     memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
                   2320:     ret->buffer = xmlBufferCreate();
                   2321:     if (ret->buffer == NULL) {
                   2322:         xmlFree(ret);
                   2323:        return(NULL);
                   2324:     }
                   2325: 
                   2326:     /* try to avoid a performance problem with Windows realloc() */
                   2327:     if (ret->buffer->alloc == XML_BUFFER_ALLOC_EXACT)
                   2328:         ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
                   2329: 
                   2330:     ret->encoder = encoder;
                   2331:     if (encoder != NULL) {
                   2332:         ret->conv = xmlBufferCreateSize(4000);
                   2333:        if (ret->conv == NULL) {
                   2334:            xmlFree(ret);
                   2335:            return(NULL);
                   2336:        }
                   2337: 
                   2338:        /*
                   2339:         * This call is designed to initiate the encoder state
                   2340:         */
                   2341:        xmlCharEncOutFunc(encoder, ret->conv, NULL);
                   2342:     } else
                   2343:         ret->conv = NULL;
                   2344:     ret->writecallback = NULL;
                   2345:     ret->closecallback = NULL;
                   2346:     ret->context = NULL;
                   2347:     ret->written = 0;
                   2348: 
                   2349:     return(ret);
                   2350: }
                   2351: 
                   2352: /**
                   2353:  * xmlAllocOutputBufferInternal:
                   2354:  * @encoder:  the encoding converter or NULL
                   2355:  *
                   2356:  * Create a buffered parser output
                   2357:  *
                   2358:  * Returns the new parser output or NULL
                   2359:  */
                   2360: xmlOutputBufferPtr
                   2361: xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
                   2362:     xmlOutputBufferPtr ret;
                   2363: 
                   2364:     ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
                   2365:     if (ret == NULL) {
                   2366:        xmlIOErrMemory("creating output buffer");
                   2367:        return(NULL);
                   2368:     }
                   2369:     memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
                   2370:     ret->buffer = xmlBufferCreate();
                   2371:     if (ret->buffer == NULL) {
                   2372:         xmlFree(ret);
                   2373:        return(NULL);
                   2374:     }
                   2375: 
                   2376: 
                   2377:     /*
                   2378:      * For conversion buffers we use the special IO handling
                   2379:      * We don't do that from the exported API to avoid confusing
                   2380:      * user's code.
                   2381:      */
                   2382:     ret->buffer->alloc = XML_BUFFER_ALLOC_IO;
                   2383:     ret->buffer->contentIO = ret->buffer->content;
                   2384: 
                   2385:     ret->encoder = encoder;
                   2386:     if (encoder != NULL) {
                   2387:         ret->conv = xmlBufferCreateSize(4000);
                   2388:        if (ret->conv == NULL) {
                   2389:            xmlFree(ret);
                   2390:            return(NULL);
                   2391:        }
                   2392: 
                   2393:        /*
                   2394:         * This call is designed to initiate the encoder state
                   2395:         */
                   2396:        xmlCharEncOutFunc(encoder, ret->conv, NULL);
                   2397:     } else
                   2398:         ret->conv = NULL;
                   2399:     ret->writecallback = NULL;
                   2400:     ret->closecallback = NULL;
                   2401:     ret->context = NULL;
                   2402:     ret->written = 0;
                   2403: 
                   2404:     return(ret);
                   2405: }
                   2406: 
                   2407: #endif /* LIBXML_OUTPUT_ENABLED */
                   2408: 
                   2409: /**
                   2410:  * xmlFreeParserInputBuffer:
                   2411:  * @in:  a buffered parser input
                   2412:  *
                   2413:  * Free up the memory used by a buffered parser input
                   2414:  */
                   2415: void
                   2416: xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
                   2417:     if (in == NULL) return;
                   2418: 
                   2419:     if (in->raw) {
                   2420:         xmlBufferFree(in->raw);
                   2421:        in->raw = NULL;
                   2422:     }
                   2423:     if (in->encoder != NULL) {
                   2424:         xmlCharEncCloseFunc(in->encoder);
                   2425:     }
                   2426:     if (in->closecallback != NULL) {
                   2427:        in->closecallback(in->context);
                   2428:     }
                   2429:     if (in->buffer != NULL) {
                   2430:         xmlBufferFree(in->buffer);
                   2431:        in->buffer = NULL;
                   2432:     }
                   2433: 
                   2434:     xmlFree(in);
                   2435: }
                   2436: 
                   2437: #ifdef LIBXML_OUTPUT_ENABLED
                   2438: /**
                   2439:  * xmlOutputBufferClose:
                   2440:  * @out:  a buffered output
                   2441:  *
                   2442:  * flushes and close the output I/O channel
                   2443:  * and free up all the associated resources
                   2444:  *
                   2445:  * Returns the number of byte written or -1 in case of error.
                   2446:  */
                   2447: int
                   2448: xmlOutputBufferClose(xmlOutputBufferPtr out)
                   2449: {
                   2450:     int written;
                   2451:     int err_rc = 0;
                   2452: 
                   2453:     if (out == NULL)
                   2454:         return (-1);
                   2455:     if (out->writecallback != NULL)
                   2456:         xmlOutputBufferFlush(out);
                   2457:     if (out->closecallback != NULL) {
                   2458:         err_rc = out->closecallback(out->context);
                   2459:     }
                   2460:     written = out->written;
                   2461:     if (out->conv) {
                   2462:         xmlBufferFree(out->conv);
                   2463:         out->conv = NULL;
                   2464:     }
                   2465:     if (out->encoder != NULL) {
                   2466:         xmlCharEncCloseFunc(out->encoder);
                   2467:     }
                   2468:     if (out->buffer != NULL) {
                   2469:         xmlBufferFree(out->buffer);
                   2470:         out->buffer = NULL;
                   2471:     }
                   2472: 
                   2473:     if (out->error)
                   2474:         err_rc = -1;
                   2475:     xmlFree(out);
                   2476:     return ((err_rc == 0) ? written : err_rc);
                   2477: }
                   2478: #endif /* LIBXML_OUTPUT_ENABLED */
                   2479: 
                   2480: xmlParserInputBufferPtr
                   2481: __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
                   2482:     xmlParserInputBufferPtr ret;
                   2483:     int i = 0;
                   2484:     void *context = NULL;
                   2485: 
                   2486:     if (xmlInputCallbackInitialized == 0)
                   2487:        xmlRegisterDefaultInputCallbacks();
                   2488: 
                   2489:     if (URI == NULL) return(NULL);
                   2490: 
                   2491:     /*
                   2492:      * Try to find one of the input accept method accepting that scheme
                   2493:      * Go in reverse to give precedence to user defined handlers.
                   2494:      */
                   2495:     if (context == NULL) {
                   2496:        for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
                   2497:            if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
                   2498:                (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
                   2499:                context = xmlInputCallbackTable[i].opencallback(URI);
                   2500:                if (context != NULL) {
                   2501:                    break;
                   2502:                }
                   2503:            }
                   2504:        }
                   2505:     }
                   2506:     if (context == NULL) {
                   2507:        return(NULL);
                   2508:     }
                   2509: 
                   2510:     /*
                   2511:      * Allocate the Input buffer front-end.
                   2512:      */
                   2513:     ret = xmlAllocParserInputBuffer(enc);
                   2514:     if (ret != NULL) {
                   2515:        ret->context = context;
                   2516:        ret->readcallback = xmlInputCallbackTable[i].readcallback;
                   2517:        ret->closecallback = xmlInputCallbackTable[i].closecallback;
                   2518: #ifdef HAVE_ZLIB_H
                   2519:        if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
                   2520:                (strcmp(URI, "-") != 0)) {
                   2521: #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
                   2522:             ret->compressed = !gzdirect(context);
                   2523: #else
                   2524:            if (((z_stream *)context)->avail_in > 4) {
                   2525:                char *cptr, buff4[4];
                   2526:                cptr = (char *) ((z_stream *)context)->next_in;
                   2527:                if (gzread(context, buff4, 4) == 4) {
                   2528:                    if (strncmp(buff4, cptr, 4) == 0)
                   2529:                        ret->compressed = 0;
                   2530:                    else
                   2531:                        ret->compressed = 1;
                   2532:                    gzrewind(context);
                   2533:                }
                   2534:            }
                   2535: #endif
                   2536:        }
                   2537: #endif
                   2538:     }
                   2539:     else
                   2540:       xmlInputCallbackTable[i].closecallback (context);
                   2541: 
                   2542:     return(ret);
                   2543: }
                   2544: 
                   2545: /**
                   2546:  * xmlParserInputBufferCreateFilename:
                   2547:  * @URI:  a C string containing the URI or filename
                   2548:  * @enc:  the charset encoding if known
                   2549:  *
                   2550:  * Create a buffered parser input for the progressive parsing of a file
                   2551:  * If filename is "-' then we use stdin as the input.
                   2552:  * Automatic support for ZLIB/Compress compressed document is provided
                   2553:  * by default if found at compile-time.
                   2554:  * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
                   2555:  *
                   2556:  * Returns the new parser input or NULL
                   2557:  */
                   2558: xmlParserInputBufferPtr
                   2559: xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
                   2560:     if ((xmlParserInputBufferCreateFilenameValue)) {
                   2561:                return xmlParserInputBufferCreateFilenameValue(URI, enc);
                   2562:        }
                   2563:        return __xmlParserInputBufferCreateFilename(URI, enc);
                   2564: }
                   2565: 
                   2566: #ifdef LIBXML_OUTPUT_ENABLED
                   2567: xmlOutputBufferPtr
                   2568: __xmlOutputBufferCreateFilename(const char *URI,
                   2569:                               xmlCharEncodingHandlerPtr encoder,
                   2570:                               int compression ATTRIBUTE_UNUSED) {
                   2571:     xmlOutputBufferPtr ret;
                   2572:     xmlURIPtr puri;
                   2573:     int i = 0;
                   2574:     void *context = NULL;
                   2575:     char *unescaped = NULL;
                   2576: #ifdef HAVE_ZLIB_H
                   2577:     int is_file_uri = 1;
                   2578: #endif
                   2579: 
                   2580:     if (xmlOutputCallbackInitialized == 0)
                   2581:        xmlRegisterDefaultOutputCallbacks();
                   2582: 
                   2583:     if (URI == NULL) return(NULL);
                   2584: 
                   2585:     puri = xmlParseURI(URI);
                   2586:     if (puri != NULL) {
                   2587: #ifdef HAVE_ZLIB_H
                   2588:         if ((puri->scheme != NULL) &&
                   2589:            (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
                   2590:            is_file_uri = 0;
                   2591: #endif
                   2592:        /*
                   2593:         * try to limit the damages of the URI unescaping code.
                   2594:         */
                   2595:        if ((puri->scheme == NULL) ||
                   2596:            (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
                   2597:            unescaped = xmlURIUnescapeString(URI, 0, NULL);
                   2598:        xmlFreeURI(puri);
                   2599:     }
                   2600: 
                   2601:     /*
                   2602:      * Try to find one of the output accept method accepting that scheme
                   2603:      * Go in reverse to give precedence to user defined handlers.
                   2604:      * try with an unescaped version of the URI
                   2605:      */
                   2606:     if (unescaped != NULL) {
                   2607: #ifdef HAVE_ZLIB_H
                   2608:        if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
                   2609:            context = xmlGzfileOpenW(unescaped, compression);
                   2610:            if (context != NULL) {
                   2611:                ret = xmlAllocOutputBufferInternal(encoder);
                   2612:                if (ret != NULL) {
                   2613:                    ret->context = context;
                   2614:                    ret->writecallback = xmlGzfileWrite;
                   2615:                    ret->closecallback = xmlGzfileClose;
                   2616:                }
                   2617:                xmlFree(unescaped);
                   2618:                return(ret);
                   2619:            }
                   2620:        }
                   2621: #endif
                   2622:        for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
                   2623:            if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
                   2624:                (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
                   2625: #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
                   2626:                /*  Need to pass compression parameter into HTTP open calls  */
                   2627:                if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
                   2628:                    context = xmlIOHTTPOpenW(unescaped, compression);
                   2629:                else
                   2630: #endif
                   2631:                    context = xmlOutputCallbackTable[i].opencallback(unescaped);
                   2632:                if (context != NULL)
                   2633:                    break;
                   2634:            }
                   2635:        }
                   2636:        xmlFree(unescaped);
                   2637:     }
                   2638: 
                   2639:     /*
                   2640:      * If this failed try with a non-escaped URI this may be a strange
                   2641:      * filename
                   2642:      */
                   2643:     if (context == NULL) {
                   2644: #ifdef HAVE_ZLIB_H
                   2645:        if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
                   2646:            context = xmlGzfileOpenW(URI, compression);
                   2647:            if (context != NULL) {
                   2648:                ret = xmlAllocOutputBufferInternal(encoder);
                   2649:                if (ret != NULL) {
                   2650:                    ret->context = context;
                   2651:                    ret->writecallback = xmlGzfileWrite;
                   2652:                    ret->closecallback = xmlGzfileClose;
                   2653:                }
                   2654:                return(ret);
                   2655:            }
                   2656:        }
                   2657: #endif
                   2658:        for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
                   2659:            if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
                   2660:                (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
                   2661: #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
                   2662:                /*  Need to pass compression parameter into HTTP open calls  */
                   2663:                if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
                   2664:                    context = xmlIOHTTPOpenW(URI, compression);
                   2665:                else
                   2666: #endif
                   2667:                    context = xmlOutputCallbackTable[i].opencallback(URI);
                   2668:                if (context != NULL)
                   2669:                    break;
                   2670:            }
                   2671:        }
                   2672:     }
                   2673: 
                   2674:     if (context == NULL) {
                   2675:        return(NULL);
                   2676:     }
                   2677: 
                   2678:     /*
                   2679:      * Allocate the Output buffer front-end.
                   2680:      */
                   2681:     ret = xmlAllocOutputBufferInternal(encoder);
                   2682:     if (ret != NULL) {
                   2683:        ret->context = context;
                   2684:        ret->writecallback = xmlOutputCallbackTable[i].writecallback;
                   2685:        ret->closecallback = xmlOutputCallbackTable[i].closecallback;
                   2686:     }
                   2687:     return(ret);
                   2688: }
                   2689: 
                   2690: /**
                   2691:  * xmlOutputBufferCreateFilename:
                   2692:  * @URI:  a C string containing the URI or filename
                   2693:  * @encoder:  the encoding converter or NULL
                   2694:  * @compression:  the compression ration (0 none, 9 max).
                   2695:  *
                   2696:  * Create a buffered  output for the progressive saving of a file
                   2697:  * If filename is "-' then we use stdout as the output.
                   2698:  * Automatic support for ZLIB/Compress compressed document is provided
                   2699:  * by default if found at compile-time.
                   2700:  * TODO: currently if compression is set, the library only support
                   2701:  *       writing to a local file.
                   2702:  *
                   2703:  * Returns the new output or NULL
                   2704:  */
                   2705: xmlOutputBufferPtr
                   2706: xmlOutputBufferCreateFilename(const char *URI,
                   2707:                               xmlCharEncodingHandlerPtr encoder,
                   2708:                               int compression ATTRIBUTE_UNUSED) {
                   2709:     if ((xmlOutputBufferCreateFilenameValue)) {
                   2710:                return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
                   2711:        }
                   2712:        return __xmlOutputBufferCreateFilename(URI, encoder, compression);
                   2713: }
                   2714: #endif /* LIBXML_OUTPUT_ENABLED */
                   2715: 
                   2716: /**
                   2717:  * xmlParserInputBufferCreateFile:
                   2718:  * @file:  a FILE*
                   2719:  * @enc:  the charset encoding if known
                   2720:  *
                   2721:  * Create a buffered parser input for the progressive parsing of a FILE *
                   2722:  * buffered C I/O
                   2723:  *
                   2724:  * Returns the new parser input or NULL
                   2725:  */
                   2726: xmlParserInputBufferPtr
                   2727: xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
                   2728:     xmlParserInputBufferPtr ret;
                   2729: 
                   2730:     if (xmlInputCallbackInitialized == 0)
                   2731:        xmlRegisterDefaultInputCallbacks();
                   2732: 
                   2733:     if (file == NULL) return(NULL);
                   2734: 
                   2735:     ret = xmlAllocParserInputBuffer(enc);
                   2736:     if (ret != NULL) {
                   2737:         ret->context = file;
                   2738:        ret->readcallback = xmlFileRead;
                   2739:        ret->closecallback = xmlFileFlush;
                   2740:     }
                   2741: 
                   2742:     return(ret);
                   2743: }
                   2744: 
                   2745: #ifdef LIBXML_OUTPUT_ENABLED
                   2746: /**
                   2747:  * xmlOutputBufferCreateFile:
                   2748:  * @file:  a FILE*
                   2749:  * @encoder:  the encoding converter or NULL
                   2750:  *
                   2751:  * Create a buffered output for the progressive saving to a FILE *
                   2752:  * buffered C I/O
                   2753:  *
                   2754:  * Returns the new parser output or NULL
                   2755:  */
                   2756: xmlOutputBufferPtr
                   2757: xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
                   2758:     xmlOutputBufferPtr ret;
                   2759: 
                   2760:     if (xmlOutputCallbackInitialized == 0)
                   2761:        xmlRegisterDefaultOutputCallbacks();
                   2762: 
                   2763:     if (file == NULL) return(NULL);
                   2764: 
                   2765:     ret = xmlAllocOutputBufferInternal(encoder);
                   2766:     if (ret != NULL) {
                   2767:         ret->context = file;
                   2768:        ret->writecallback = xmlFileWrite;
                   2769:        ret->closecallback = xmlFileFlush;
                   2770:     }
                   2771: 
                   2772:     return(ret);
                   2773: }
                   2774: 
                   2775: /**
                   2776:  * xmlOutputBufferCreateBuffer:
                   2777:  * @buffer:  a xmlBufferPtr
                   2778:  * @encoder:  the encoding converter or NULL
                   2779:  *
                   2780:  * Create a buffered output for the progressive saving to a xmlBuffer
                   2781:  *
                   2782:  * Returns the new parser output or NULL
                   2783:  */
                   2784: xmlOutputBufferPtr
                   2785: xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
                   2786:                             xmlCharEncodingHandlerPtr encoder) {
                   2787:     xmlOutputBufferPtr ret;
                   2788: 
                   2789:     if (buffer == NULL) return(NULL);
                   2790: 
                   2791:     ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
                   2792:                                   xmlBufferWrite,
                   2793:                                   (xmlOutputCloseCallback)
                   2794:                                   NULL, (void *) buffer, encoder);
                   2795: 
                   2796:     return(ret);
                   2797: }
                   2798: 
                   2799: #endif /* LIBXML_OUTPUT_ENABLED */
                   2800: 
                   2801: /**
                   2802:  * xmlParserInputBufferCreateFd:
                   2803:  * @fd:  a file descriptor number
                   2804:  * @enc:  the charset encoding if known
                   2805:  *
                   2806:  * Create a buffered parser input for the progressive parsing for the input
                   2807:  * from a file descriptor
                   2808:  *
                   2809:  * Returns the new parser input or NULL
                   2810:  */
                   2811: xmlParserInputBufferPtr
                   2812: xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
                   2813:     xmlParserInputBufferPtr ret;
                   2814: 
                   2815:     if (fd < 0) return(NULL);
                   2816: 
                   2817:     ret = xmlAllocParserInputBuffer(enc);
                   2818:     if (ret != NULL) {
                   2819:         ret->context = (void *) (long) fd;
                   2820:        ret->readcallback = xmlFdRead;
                   2821:        ret->closecallback = xmlFdClose;
                   2822:     }
                   2823: 
                   2824:     return(ret);
                   2825: }
                   2826: 
                   2827: /**
                   2828:  * xmlParserInputBufferCreateMem:
                   2829:  * @mem:  the memory input
                   2830:  * @size:  the length of the memory block
                   2831:  * @enc:  the charset encoding if known
                   2832:  *
                   2833:  * Create a buffered parser input for the progressive parsing for the input
                   2834:  * from a memory area.
                   2835:  *
                   2836:  * Returns the new parser input or NULL
                   2837:  */
                   2838: xmlParserInputBufferPtr
                   2839: xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
                   2840:     xmlParserInputBufferPtr ret;
                   2841:     int errcode;
                   2842: 
                   2843:     if (size <= 0) return(NULL);
                   2844:     if (mem == NULL) return(NULL);
                   2845: 
                   2846:     ret = xmlAllocParserInputBuffer(enc);
                   2847:     if (ret != NULL) {
                   2848:         ret->context = (void *) mem;
                   2849:        ret->readcallback = (xmlInputReadCallback) xmlNop;
                   2850:        ret->closecallback = NULL;
                   2851:        errcode = xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
                   2852:        if (errcode != 0) {
                   2853:            xmlFree(ret);
                   2854:            return(NULL);
                   2855:        }
                   2856:     }
                   2857: 
                   2858:     return(ret);
                   2859: }
                   2860: 
                   2861: /**
                   2862:  * xmlParserInputBufferCreateStatic:
                   2863:  * @mem:  the memory input
                   2864:  * @size:  the length of the memory block
                   2865:  * @enc:  the charset encoding if known
                   2866:  *
                   2867:  * Create a buffered parser input for the progressive parsing for the input
                   2868:  * from an immutable memory area. This will not copy the memory area to
                   2869:  * the buffer, but the memory is expected to be available until the end of
                   2870:  * the parsing, this is useful for example when using mmap'ed file.
                   2871:  *
                   2872:  * Returns the new parser input or NULL
                   2873:  */
                   2874: xmlParserInputBufferPtr
                   2875: xmlParserInputBufferCreateStatic(const char *mem, int size,
                   2876:                                  xmlCharEncoding enc) {
                   2877:     xmlParserInputBufferPtr ret;
                   2878: 
                   2879:     if (size <= 0) return(NULL);
                   2880:     if (mem == NULL) return(NULL);
                   2881: 
                   2882:     ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
                   2883:     if (ret == NULL) {
                   2884:        xmlIOErrMemory("creating input buffer");
                   2885:        return(NULL);
                   2886:     }
                   2887:     memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
                   2888:     ret->buffer = xmlBufferCreateStatic((void *)mem, (size_t) size);
                   2889:     if (ret->buffer == NULL) {
                   2890:         xmlFree(ret);
                   2891:        return(NULL);
                   2892:     }
                   2893:     ret->encoder = xmlGetCharEncodingHandler(enc);
                   2894:     if (ret->encoder != NULL)
                   2895:         ret->raw = xmlBufferCreateSize(2 * xmlDefaultBufferSize);
                   2896:     else
                   2897:         ret->raw = NULL;
                   2898:     ret->compressed = -1;
                   2899:     ret->context = (void *) mem;
                   2900:     ret->readcallback = NULL;
                   2901:     ret->closecallback = NULL;
                   2902: 
                   2903:     return(ret);
                   2904: }
                   2905: 
                   2906: #ifdef LIBXML_OUTPUT_ENABLED
                   2907: /**
                   2908:  * xmlOutputBufferCreateFd:
                   2909:  * @fd:  a file descriptor number
                   2910:  * @encoder:  the encoding converter or NULL
                   2911:  *
                   2912:  * Create a buffered output for the progressive saving
                   2913:  * to a file descriptor
                   2914:  *
                   2915:  * Returns the new parser output or NULL
                   2916:  */
                   2917: xmlOutputBufferPtr
                   2918: xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
                   2919:     xmlOutputBufferPtr ret;
                   2920: 
                   2921:     if (fd < 0) return(NULL);
                   2922: 
                   2923:     ret = xmlAllocOutputBufferInternal(encoder);
                   2924:     if (ret != NULL) {
                   2925:         ret->context = (void *) (long) fd;
                   2926:        ret->writecallback = xmlFdWrite;
                   2927:        ret->closecallback = NULL;
                   2928:     }
                   2929: 
                   2930:     return(ret);
                   2931: }
                   2932: #endif /* LIBXML_OUTPUT_ENABLED */
                   2933: 
                   2934: /**
                   2935:  * xmlParserInputBufferCreateIO:
                   2936:  * @ioread:  an I/O read function
                   2937:  * @ioclose:  an I/O close function
                   2938:  * @ioctx:  an I/O handler
                   2939:  * @enc:  the charset encoding if known
                   2940:  *
                   2941:  * Create a buffered parser input for the progressive parsing for the input
                   2942:  * from an I/O handler
                   2943:  *
                   2944:  * Returns the new parser input or NULL
                   2945:  */
                   2946: xmlParserInputBufferPtr
                   2947: xmlParserInputBufferCreateIO(xmlInputReadCallback   ioread,
                   2948:         xmlInputCloseCallback  ioclose, void *ioctx, xmlCharEncoding enc) {
                   2949:     xmlParserInputBufferPtr ret;
                   2950: 
                   2951:     if (ioread == NULL) return(NULL);
                   2952: 
                   2953:     ret = xmlAllocParserInputBuffer(enc);
                   2954:     if (ret != NULL) {
                   2955:         ret->context = (void *) ioctx;
                   2956:        ret->readcallback = ioread;
                   2957:        ret->closecallback = ioclose;
                   2958:     }
                   2959: 
                   2960:     return(ret);
                   2961: }
                   2962: 
                   2963: #ifdef LIBXML_OUTPUT_ENABLED
                   2964: /**
                   2965:  * xmlOutputBufferCreateIO:
                   2966:  * @iowrite:  an I/O write function
                   2967:  * @ioclose:  an I/O close function
                   2968:  * @ioctx:  an I/O handler
                   2969:  * @encoder:  the charset encoding if known
                   2970:  *
                   2971:  * Create a buffered output for the progressive saving
                   2972:  * to an I/O handler
                   2973:  *
                   2974:  * Returns the new parser output or NULL
                   2975:  */
                   2976: xmlOutputBufferPtr
                   2977: xmlOutputBufferCreateIO(xmlOutputWriteCallback   iowrite,
                   2978:         xmlOutputCloseCallback  ioclose, void *ioctx,
                   2979:         xmlCharEncodingHandlerPtr encoder) {
                   2980:     xmlOutputBufferPtr ret;
                   2981: 
                   2982:     if (iowrite == NULL) return(NULL);
                   2983: 
                   2984:     ret = xmlAllocOutputBufferInternal(encoder);
                   2985:     if (ret != NULL) {
                   2986:         ret->context = (void *) ioctx;
                   2987:        ret->writecallback = iowrite;
                   2988:        ret->closecallback = ioclose;
                   2989:     }
                   2990: 
                   2991:     return(ret);
                   2992: }
                   2993: #endif /* LIBXML_OUTPUT_ENABLED */
                   2994: 
                   2995: /**
                   2996:  * xmlParserInputBufferCreateFilenameDefault:
                   2997:  * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
                   2998:  *
                   2999:  * Registers a callback for URI input file handling
                   3000:  *
                   3001:  * Returns the old value of the registration function
                   3002:  */
                   3003: xmlParserInputBufferCreateFilenameFunc
                   3004: xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
                   3005: {
                   3006:     xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
                   3007:     if (old == NULL) {
                   3008:                old = __xmlParserInputBufferCreateFilename;
                   3009:        }
                   3010: 
                   3011:     xmlParserInputBufferCreateFilenameValue = func;
                   3012:     return(old);
                   3013: }
                   3014: 
                   3015: /**
                   3016:  * xmlOutputBufferCreateFilenameDefault:
                   3017:  * @func: function pointer to the new OutputBufferCreateFilenameFunc
                   3018:  *
                   3019:  * Registers a callback for URI output file handling
                   3020:  *
                   3021:  * Returns the old value of the registration function
                   3022:  */
                   3023: xmlOutputBufferCreateFilenameFunc
                   3024: xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
                   3025: {
                   3026:     xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
                   3027: #ifdef LIBXML_OUTPUT_ENABLED
                   3028:     if (old == NULL) {
                   3029:                old = __xmlOutputBufferCreateFilename;
                   3030:        }
                   3031: #endif
                   3032:     xmlOutputBufferCreateFilenameValue = func;
                   3033:     return(old);
                   3034: }
                   3035: 
                   3036: /**
                   3037:  * xmlParserInputBufferPush:
                   3038:  * @in:  a buffered parser input
                   3039:  * @len:  the size in bytes of the array.
                   3040:  * @buf:  an char array
                   3041:  *
                   3042:  * Push the content of the arry in the input buffer
                   3043:  * This routine handle the I18N transcoding to internal UTF-8
                   3044:  * This is used when operating the parser in progressive (push) mode.
                   3045:  *
                   3046:  * Returns the number of chars read and stored in the buffer, or -1
                   3047:  *         in case of error.
                   3048:  */
                   3049: int
                   3050: xmlParserInputBufferPush(xmlParserInputBufferPtr in,
                   3051:                         int len, const char *buf) {
                   3052:     int nbchars = 0;
                   3053:     int ret;
                   3054: 
                   3055:     if (len < 0) return(0);
                   3056:     if ((in == NULL) || (in->error)) return(-1);
                   3057:     if (in->encoder != NULL) {
                   3058:         unsigned int use;
                   3059: 
                   3060:         /*
                   3061:         * Store the data in the incoming raw buffer
                   3062:         */
                   3063:         if (in->raw == NULL) {
                   3064:            in->raw = xmlBufferCreate();
                   3065:        }
                   3066:        ret = xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
                   3067:        if (ret != 0)
                   3068:            return(-1);
                   3069: 
                   3070:        /*
                   3071:         * convert as much as possible to the parser reading buffer.
                   3072:         */
                   3073:        use = in->raw->use;
                   3074:        nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
                   3075:        if (nbchars < 0) {
                   3076:            xmlIOErr(XML_IO_ENCODER, NULL);
                   3077:            in->error = XML_IO_ENCODER;
                   3078:            return(-1);
                   3079:        }
                   3080:        in->rawconsumed += (use - in->raw->use);
                   3081:     } else {
                   3082:        nbchars = len;
                   3083:         ret = xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
                   3084:        if (ret != 0)
                   3085:            return(-1);
                   3086:     }
                   3087: #ifdef DEBUG_INPUT
                   3088:     xmlGenericError(xmlGenericErrorContext,
                   3089:            "I/O: pushed %d chars, buffer %d/%d\n",
                   3090:             nbchars, in->buffer->use, in->buffer->size);
                   3091: #endif
                   3092:     return(nbchars);
                   3093: }
                   3094: 
                   3095: /**
                   3096:  * endOfInput:
                   3097:  *
                   3098:  * When reading from an Input channel indicated end of file or error
                   3099:  * don't reread from it again.
                   3100:  */
                   3101: static int
                   3102: endOfInput (void * context ATTRIBUTE_UNUSED,
                   3103:            char * buffer ATTRIBUTE_UNUSED,
                   3104:            int len ATTRIBUTE_UNUSED) {
                   3105:     return(0);
                   3106: }
                   3107: 
                   3108: /**
                   3109:  * xmlParserInputBufferGrow:
                   3110:  * @in:  a buffered parser input
                   3111:  * @len:  indicative value of the amount of chars to read
                   3112:  *
                   3113:  * Grow up the content of the input buffer, the old data are preserved
                   3114:  * This routine handle the I18N transcoding to internal UTF-8
                   3115:  * This routine is used when operating the parser in normal (pull) mode
                   3116:  *
                   3117:  * TODO: one should be able to remove one extra copy by copying directly
                   3118:  *       onto in->buffer or in->raw
                   3119:  *
                   3120:  * Returns the number of chars read and stored in the buffer, or -1
                   3121:  *         in case of error.
                   3122:  */
                   3123: int
                   3124: xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
                   3125:     char *buffer = NULL;
                   3126:     int res = 0;
                   3127:     int nbchars = 0;
                   3128:     int buffree;
                   3129:     unsigned int needSize;
                   3130: 
                   3131:     if ((in == NULL) || (in->error)) return(-1);
                   3132:     if ((len <= MINLEN) && (len != 4))
                   3133:         len = MINLEN;
                   3134: 
                   3135:     buffree = in->buffer->size - in->buffer->use;
                   3136:     if (buffree <= 0) {
                   3137:        xmlIOErr(XML_IO_BUFFER_FULL, NULL);
                   3138:        in->error = XML_IO_BUFFER_FULL;
                   3139:        return(-1);
                   3140:     }
                   3141: 
                   3142:     needSize = in->buffer->use + len + 1;
                   3143:     if (needSize > in->buffer->size){
                   3144:         if (!xmlBufferResize(in->buffer, needSize)){
                   3145:            xmlIOErrMemory("growing input buffer");
                   3146:            in->error = XML_ERR_NO_MEMORY;
                   3147:             return(-1);
                   3148:         }
                   3149:     }
                   3150:     buffer = (char *)&in->buffer->content[in->buffer->use];
                   3151: 
                   3152:     /*
                   3153:      * Call the read method for this I/O type.
                   3154:      */
                   3155:     if (in->readcallback != NULL) {
                   3156:        res = in->readcallback(in->context, &buffer[0], len);
                   3157:        if (res <= 0)
                   3158:            in->readcallback = endOfInput;
                   3159:     } else {
                   3160:        xmlIOErr(XML_IO_NO_INPUT, NULL);
                   3161:        in->error = XML_IO_NO_INPUT;
                   3162:        return(-1);
                   3163:     }
                   3164:     if (res < 0) {
                   3165:        return(-1);
                   3166:     }
                   3167:     len = res;
                   3168:     if (in->encoder != NULL) {
                   3169:         unsigned int use;
                   3170: 
                   3171:         /*
                   3172:         * Store the data in the incoming raw buffer
                   3173:         */
                   3174:         if (in->raw == NULL) {
                   3175:            in->raw = xmlBufferCreate();
                   3176:        }
                   3177:        res = xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
                   3178:        if (res != 0)
                   3179:            return(-1);
                   3180: 
                   3181:        /*
                   3182:         * convert as much as possible to the parser reading buffer.
                   3183:         */
                   3184:        use = in->raw->use;
                   3185:        nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
                   3186:        if (nbchars < 0) {
                   3187:            xmlIOErr(XML_IO_ENCODER, NULL);
                   3188:            in->error = XML_IO_ENCODER;
                   3189:            return(-1);
                   3190:        }
                   3191:        in->rawconsumed += (use - in->raw->use);
                   3192:     } else {
                   3193:        nbchars = len;
                   3194:        in->buffer->use += nbchars;
                   3195:        buffer[nbchars] = 0;
                   3196:     }
                   3197: #ifdef DEBUG_INPUT
                   3198:     xmlGenericError(xmlGenericErrorContext,
                   3199:            "I/O: read %d chars, buffer %d/%d\n",
                   3200:             nbchars, in->buffer->use, in->buffer->size);
                   3201: #endif
                   3202:     return(nbchars);
                   3203: }
                   3204: 
                   3205: /**
                   3206:  * xmlParserInputBufferRead:
                   3207:  * @in:  a buffered parser input
                   3208:  * @len:  indicative value of the amount of chars to read
                   3209:  *
                   3210:  * Refresh the content of the input buffer, the old data are considered
                   3211:  * consumed
                   3212:  * This routine handle the I18N transcoding to internal UTF-8
                   3213:  *
                   3214:  * Returns the number of chars read and stored in the buffer, or -1
                   3215:  *         in case of error.
                   3216:  */
                   3217: int
                   3218: xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
                   3219:     if ((in == NULL) || (in->error)) return(-1);
                   3220:     if (in->readcallback != NULL)
                   3221:        return(xmlParserInputBufferGrow(in, len));
                   3222:     else if ((in->buffer != NULL) &&
                   3223:              (in->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE))
                   3224:        return(0);
                   3225:     else
                   3226:         return(-1);
                   3227: }
                   3228: 
                   3229: #ifdef LIBXML_OUTPUT_ENABLED
                   3230: /**
                   3231:  * xmlOutputBufferWrite:
                   3232:  * @out:  a buffered parser output
                   3233:  * @len:  the size in bytes of the array.
                   3234:  * @buf:  an char array
                   3235:  *
                   3236:  * Write the content of the array in the output I/O buffer
                   3237:  * This routine handle the I18N transcoding from internal UTF-8
                   3238:  * The buffer is lossless, i.e. will store in case of partial
                   3239:  * or delayed writes.
                   3240:  *
                   3241:  * Returns the number of chars immediately written, or -1
                   3242:  *         in case of error.
                   3243:  */
                   3244: int
                   3245: xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
                   3246:     int nbchars = 0; /* number of chars to output to I/O */
                   3247:     int ret;         /* return from function call */
                   3248:     int written = 0; /* number of char written to I/O so far */
                   3249:     int chunk;       /* number of byte curreent processed from buf */
                   3250: 
                   3251:     if ((out == NULL) || (out->error)) return(-1);
                   3252:     if (len < 0) return(0);
                   3253:     if (out->error) return(-1);
                   3254: 
                   3255:     do {
                   3256:        chunk = len;
                   3257:        if (chunk > 4 * MINLEN)
                   3258:            chunk = 4 * MINLEN;
                   3259: 
                   3260:        /*
                   3261:         * first handle encoding stuff.
                   3262:         */
                   3263:        if (out->encoder != NULL) {
                   3264:            /*
                   3265:             * Store the data in the incoming raw buffer
                   3266:             */
                   3267:            if (out->conv == NULL) {
                   3268:                out->conv = xmlBufferCreate();
                   3269:            }
                   3270:            ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
                   3271:            if (ret != 0)
                   3272:                return(-1);
                   3273: 
                   3274:            if ((out->buffer->use < MINLEN) && (chunk == len))
                   3275:                goto done;
                   3276: 
                   3277:            /*
                   3278:             * convert as much as possible to the parser reading buffer.
                   3279:             */
                   3280:            ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
                   3281:            if ((ret < 0) && (ret != -3)) {
                   3282:                xmlIOErr(XML_IO_ENCODER, NULL);
                   3283:                out->error = XML_IO_ENCODER;
                   3284:                return(-1);
                   3285:            }
                   3286:            nbchars = out->conv->use;
                   3287:        } else {
                   3288:            ret = xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
                   3289:            if (ret != 0)
                   3290:                return(-1);
                   3291:            nbchars = out->buffer->use;
                   3292:        }
                   3293:        buf += chunk;
                   3294:        len -= chunk;
                   3295: 
                   3296:        if ((nbchars < MINLEN) && (len <= 0))
                   3297:            goto done;
                   3298: 
                   3299:        if (out->writecallback) {
                   3300:            /*
                   3301:             * second write the stuff to the I/O channel
                   3302:             */
                   3303:            if (out->encoder != NULL) {
                   3304:                ret = out->writecallback(out->context,
                   3305:                                 (const char *)out->conv->content, nbchars);
                   3306:                if (ret >= 0)
                   3307:                    xmlBufferShrink(out->conv, ret);
                   3308:            } else {
                   3309:                ret = out->writecallback(out->context,
                   3310:                                 (const char *)out->buffer->content, nbchars);
                   3311:                if (ret >= 0)
                   3312:                    xmlBufferShrink(out->buffer, ret);
                   3313:            }
                   3314:            if (ret < 0) {
                   3315:                xmlIOErr(XML_IO_WRITE, NULL);
                   3316:                out->error = XML_IO_WRITE;
                   3317:                return(ret);
                   3318:            }
                   3319:            out->written += ret;
                   3320:        }
                   3321:        written += nbchars;
                   3322:     } while (len > 0);
                   3323: 
                   3324: done:
                   3325: #ifdef DEBUG_INPUT
                   3326:     xmlGenericError(xmlGenericErrorContext,
                   3327:            "I/O: wrote %d chars\n", written);
                   3328: #endif
                   3329:     return(written);
                   3330: }
                   3331: 
                   3332: /**
                   3333:  * xmlEscapeContent:
                   3334:  * @out:  a pointer to an array of bytes to store the result
                   3335:  * @outlen:  the length of @out
                   3336:  * @in:  a pointer to an array of unescaped UTF-8 bytes
                   3337:  * @inlen:  the length of @in
                   3338:  *
                   3339:  * Take a block of UTF-8 chars in and escape them.
                   3340:  * Returns 0 if success, or -1 otherwise
                   3341:  * The value of @inlen after return is the number of octets consumed
                   3342:  *     if the return value is positive, else unpredictable.
                   3343:  * The value of @outlen after return is the number of octets consumed.
                   3344:  */
                   3345: static int
                   3346: xmlEscapeContent(unsigned char* out, int *outlen,
                   3347:                  const xmlChar* in, int *inlen) {
                   3348:     unsigned char* outstart = out;
                   3349:     const unsigned char* base = in;
                   3350:     unsigned char* outend = out + *outlen;
                   3351:     const unsigned char* inend;
                   3352: 
                   3353:     inend = in + (*inlen);
                   3354: 
                   3355:     while ((in < inend) && (out < outend)) {
                   3356:        if (*in == '<') {
                   3357:            if (outend - out < 4) break;
                   3358:            *out++ = '&';
                   3359:            *out++ = 'l';
                   3360:            *out++ = 't';
                   3361:            *out++ = ';';
                   3362:        } else if (*in == '>') {
                   3363:            if (outend - out < 4) break;
                   3364:            *out++ = '&';
                   3365:            *out++ = 'g';
                   3366:            *out++ = 't';
                   3367:            *out++ = ';';
                   3368:        } else if (*in == '&') {
                   3369:            if (outend - out < 5) break;
                   3370:            *out++ = '&';
                   3371:            *out++ = 'a';
                   3372:            *out++ = 'm';
                   3373:            *out++ = 'p';
                   3374:            *out++ = ';';
                   3375:        } else if (*in == '\r') {
                   3376:            if (outend - out < 5) break;
                   3377:            *out++ = '&';
                   3378:            *out++ = '#';
                   3379:            *out++ = '1';
                   3380:            *out++ = '3';
                   3381:            *out++ = ';';
                   3382:        } else {
                   3383:            *out++ = (unsigned char) *in;
                   3384:        }
                   3385:        ++in;
                   3386:     }
                   3387:     *outlen = out - outstart;
                   3388:     *inlen = in - base;
                   3389:     return(0);
                   3390: }
                   3391: 
                   3392: /**
                   3393:  * xmlOutputBufferWriteEscape:
                   3394:  * @out:  a buffered parser output
                   3395:  * @str:  a zero terminated UTF-8 string
                   3396:  * @escaping:  an optional escaping function (or NULL)
                   3397:  *
                   3398:  * Write the content of the string in the output I/O buffer
                   3399:  * This routine escapes the caracters and then handle the I18N
                   3400:  * transcoding from internal UTF-8
                   3401:  * The buffer is lossless, i.e. will store in case of partial
                   3402:  * or delayed writes.
                   3403:  *
                   3404:  * Returns the number of chars immediately written, or -1
                   3405:  *         in case of error.
                   3406:  */
                   3407: int
                   3408: xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
                   3409:                            xmlCharEncodingOutputFunc escaping) {
                   3410:     int nbchars = 0; /* number of chars to output to I/O */
                   3411:     int ret;         /* return from function call */
                   3412:     int written = 0; /* number of char written to I/O so far */
                   3413:     int oldwritten=0;/* loop guard */
                   3414:     int chunk;       /* number of byte currently processed from str */
                   3415:     int len;         /* number of bytes in str */
                   3416:     int cons;        /* byte from str consumed */
                   3417: 
                   3418:     if ((out == NULL) || (out->error) || (str == NULL) ||
                   3419:         (out->buffer == NULL) ||
                   3420:        (out->buffer->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) return(-1);
                   3421:     len = strlen((const char *)str);
                   3422:     if (len < 0) return(0);
                   3423:     if (out->error) return(-1);
                   3424:     if (escaping == NULL) escaping = xmlEscapeContent;
                   3425: 
                   3426:     do {
                   3427:         oldwritten = written;
                   3428: 
                   3429:         /*
                   3430:         * how many bytes to consume and how many bytes to store.
                   3431:         */
                   3432:        cons = len;
                   3433:        chunk = (out->buffer->size - out->buffer->use) - 1;
                   3434: 
                   3435:         /*
                   3436:         * make sure we have enough room to save first, if this is
                   3437:         * not the case force a flush, but make sure we stay in the loop
                   3438:         */
                   3439:        if (chunk < 40) {
                   3440:            if (xmlBufferGrow(out->buffer, out->buffer->size + 100) < 0)
                   3441:                return(-1);
                   3442:             oldwritten = -1;
                   3443:            continue;
                   3444:        }
                   3445: 
                   3446:        /*
                   3447:         * first handle encoding stuff.
                   3448:         */
                   3449:        if (out->encoder != NULL) {
                   3450:            /*
                   3451:             * Store the data in the incoming raw buffer
                   3452:             */
                   3453:            if (out->conv == NULL) {
                   3454:                out->conv = xmlBufferCreate();
                   3455:            }
                   3456:            ret = escaping(out->buffer->content + out->buffer->use ,
                   3457:                           &chunk, str, &cons);
                   3458:            if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
                   3459:                return(-1);
                   3460:            out->buffer->use += chunk;
                   3461:            out->buffer->content[out->buffer->use] = 0;
                   3462: 
                   3463:            if ((out->buffer->use < MINLEN) && (cons == len))
                   3464:                goto done;
                   3465: 
                   3466:            /*
                   3467:             * convert as much as possible to the output buffer.
                   3468:             */
                   3469:            ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
                   3470:            if ((ret < 0) && (ret != -3)) {
                   3471:                xmlIOErr(XML_IO_ENCODER, NULL);
                   3472:                out->error = XML_IO_ENCODER;
                   3473:                return(-1);
                   3474:            }
                   3475:            nbchars = out->conv->use;
                   3476:        } else {
                   3477:            ret = escaping(out->buffer->content + out->buffer->use ,
                   3478:                           &chunk, str, &cons);
                   3479:            if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
                   3480:                return(-1);
                   3481:            out->buffer->use += chunk;
                   3482:            out->buffer->content[out->buffer->use] = 0;
                   3483:            nbchars = out->buffer->use;
                   3484:        }
                   3485:        str += cons;
                   3486:        len -= cons;
                   3487: 
                   3488:        if ((nbchars < MINLEN) && (len <= 0))
                   3489:            goto done;
                   3490: 
                   3491:        if (out->writecallback) {
                   3492:            /*
                   3493:             * second write the stuff to the I/O channel
                   3494:             */
                   3495:            if (out->encoder != NULL) {
                   3496:                ret = out->writecallback(out->context,
                   3497:                                 (const char *)out->conv->content, nbchars);
                   3498:                if (ret >= 0)
                   3499:                    xmlBufferShrink(out->conv, ret);
                   3500:            } else {
                   3501:                ret = out->writecallback(out->context,
                   3502:                                 (const char *)out->buffer->content, nbchars);
                   3503:                if (ret >= 0)
                   3504:                    xmlBufferShrink(out->buffer, ret);
                   3505:            }
                   3506:            if (ret < 0) {
                   3507:                xmlIOErr(XML_IO_WRITE, NULL);
                   3508:                out->error = XML_IO_WRITE;
                   3509:                return(ret);
                   3510:            }
                   3511:            out->written += ret;
                   3512:        } else if (out->buffer->size - out->buffer->use < MINLEN) {
                   3513:            xmlBufferResize(out->buffer, out->buffer->size + MINLEN);
                   3514:        }
                   3515:        written += nbchars;
                   3516:     } while ((len > 0) && (oldwritten != written));
                   3517: 
                   3518: done:
                   3519: #ifdef DEBUG_INPUT
                   3520:     xmlGenericError(xmlGenericErrorContext,
                   3521:            "I/O: wrote %d chars\n", written);
                   3522: #endif
                   3523:     return(written);
                   3524: }
                   3525: 
                   3526: /**
                   3527:  * xmlOutputBufferWriteString:
                   3528:  * @out:  a buffered parser output
                   3529:  * @str:  a zero terminated C string
                   3530:  *
                   3531:  * Write the content of the string in the output I/O buffer
                   3532:  * This routine handle the I18N transcoding from internal UTF-8
                   3533:  * The buffer is lossless, i.e. will store in case of partial
                   3534:  * or delayed writes.
                   3535:  *
                   3536:  * Returns the number of chars immediately written, or -1
                   3537:  *         in case of error.
                   3538:  */
                   3539: int
                   3540: xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
                   3541:     int len;
                   3542: 
                   3543:     if ((out == NULL) || (out->error)) return(-1);
                   3544:     if (str == NULL)
                   3545:         return(-1);
                   3546:     len = strlen(str);
                   3547: 
                   3548:     if (len > 0)
                   3549:        return(xmlOutputBufferWrite(out, len, str));
                   3550:     return(len);
                   3551: }
                   3552: 
                   3553: /**
                   3554:  * xmlOutputBufferFlush:
                   3555:  * @out:  a buffered output
                   3556:  *
                   3557:  * flushes the output I/O channel
                   3558:  *
                   3559:  * Returns the number of byte written or -1 in case of error.
                   3560:  */
                   3561: int
                   3562: xmlOutputBufferFlush(xmlOutputBufferPtr out) {
                   3563:     int nbchars = 0, ret = 0;
                   3564: 
                   3565:     if ((out == NULL) || (out->error)) return(-1);
                   3566:     /*
                   3567:      * first handle encoding stuff.
                   3568:      */
                   3569:     if ((out->conv != NULL) && (out->encoder != NULL)) {
                   3570:        /*
                   3571:         * convert as much as possible to the parser reading buffer.
                   3572:         */
                   3573:        nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
                   3574:        if (nbchars < 0) {
                   3575:            xmlIOErr(XML_IO_ENCODER, NULL);
                   3576:            out->error = XML_IO_ENCODER;
                   3577:            return(-1);
                   3578:        }
                   3579:     }
                   3580: 
                   3581:     /*
                   3582:      * second flush the stuff to the I/O channel
                   3583:      */
                   3584:     if ((out->conv != NULL) && (out->encoder != NULL) &&
                   3585:        (out->writecallback != NULL)) {
                   3586:        ret = out->writecallback(out->context,
                   3587:                   (const char *)out->conv->content, out->conv->use);
                   3588:        if (ret >= 0)
                   3589:            xmlBufferShrink(out->conv, ret);
                   3590:     } else if (out->writecallback != NULL) {
                   3591:        ret = out->writecallback(out->context,
                   3592:                   (const char *)out->buffer->content, out->buffer->use);
                   3593:        if (ret >= 0)
                   3594:            xmlBufferShrink(out->buffer, ret);
                   3595:     }
                   3596:     if (ret < 0) {
                   3597:        xmlIOErr(XML_IO_FLUSH, NULL);
                   3598:        out->error = XML_IO_FLUSH;
                   3599:        return(ret);
                   3600:     }
                   3601:     out->written += ret;
                   3602: 
                   3603: #ifdef DEBUG_INPUT
                   3604:     xmlGenericError(xmlGenericErrorContext,
                   3605:            "I/O: flushed %d chars\n", ret);
                   3606: #endif
                   3607:     return(ret);
                   3608: }
                   3609: #endif /* LIBXML_OUTPUT_ENABLED */
                   3610: 
                   3611: /**
                   3612:  * xmlParserGetDirectory:
                   3613:  * @filename:  the path to a file
                   3614:  *
                   3615:  * lookup the directory for that file
                   3616:  *
                   3617:  * Returns a new allocated string containing the directory, or NULL.
                   3618:  */
                   3619: char *
                   3620: xmlParserGetDirectory(const char *filename) {
                   3621:     char *ret = NULL;
                   3622:     char dir[1024];
                   3623:     char *cur;
                   3624: 
                   3625: #ifdef _WIN32_WCE  /* easy way by now ... wince does not have dirs! */
                   3626:     return NULL;
                   3627: #endif
                   3628: 
                   3629:     if (xmlInputCallbackInitialized == 0)
                   3630:        xmlRegisterDefaultInputCallbacks();
                   3631: 
                   3632:     if (filename == NULL) return(NULL);
                   3633: 
                   3634: #if defined(WIN32) && !defined(__CYGWIN__)
                   3635: #   define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
                   3636: #else
                   3637: #   define IS_XMLPGD_SEP(ch) (ch=='/')
                   3638: #endif
                   3639: 
                   3640:     strncpy(dir, filename, 1023);
                   3641:     dir[1023] = 0;
                   3642:     cur = &dir[strlen(dir)];
                   3643:     while (cur > dir) {
                   3644:          if (IS_XMLPGD_SEP(*cur)) break;
                   3645:         cur --;
                   3646:     }
                   3647:     if (IS_XMLPGD_SEP(*cur)) {
                   3648:         if (cur == dir) dir[1] = 0;
                   3649:        else *cur = 0;
                   3650:        ret = xmlMemStrdup(dir);
                   3651:     } else {
                   3652:         if (getcwd(dir, 1024) != NULL) {
                   3653:            dir[1023] = 0;
                   3654:            ret = xmlMemStrdup(dir);
                   3655:        }
                   3656:     }
                   3657:     return(ret);
                   3658: #undef IS_XMLPGD_SEP
                   3659: }
                   3660: 
                   3661: /****************************************************************
                   3662:  *                                                             *
                   3663:  *             External entities loading                       *
                   3664:  *                                                             *
                   3665:  ****************************************************************/
                   3666: 
                   3667: /**
                   3668:  * xmlCheckHTTPInput:
                   3669:  * @ctxt: an XML parser context
                   3670:  * @ret: an XML parser input
                   3671:  *
                   3672:  * Check an input in case it was created from an HTTP stream, in that
                   3673:  * case it will handle encoding and update of the base URL in case of
                   3674:  * redirection. It also checks for HTTP errors in which case the input
                   3675:  * is cleanly freed up and an appropriate error is raised in context
                   3676:  *
                   3677:  * Returns the input or NULL in case of HTTP error.
                   3678:  */
                   3679: xmlParserInputPtr
                   3680: xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
                   3681: #ifdef LIBXML_HTTP_ENABLED
                   3682:     if ((ret != NULL) && (ret->buf != NULL) &&
                   3683:         (ret->buf->readcallback == xmlIOHTTPRead) &&
                   3684:         (ret->buf->context != NULL)) {
                   3685:         const char *encoding;
                   3686:         const char *redir;
                   3687:         const char *mime;
                   3688:         int code;
                   3689: 
                   3690:         code = xmlNanoHTTPReturnCode(ret->buf->context);
                   3691:         if (code >= 400) {
                   3692:             /* fatal error */
                   3693:            if (ret->filename != NULL)
                   3694:                __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
                   3695:                          (const char *) ret->filename);
                   3696:            else
                   3697:                __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
                   3698:             xmlFreeInputStream(ret);
                   3699:             ret = NULL;
                   3700:         } else {
                   3701: 
                   3702:             mime = xmlNanoHTTPMimeType(ret->buf->context);
                   3703:             if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
                   3704:                 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
                   3705:                 encoding = xmlNanoHTTPEncoding(ret->buf->context);
                   3706:                 if (encoding != NULL) {
                   3707:                     xmlCharEncodingHandlerPtr handler;
                   3708: 
                   3709:                     handler = xmlFindCharEncodingHandler(encoding);
                   3710:                     if (handler != NULL) {
                   3711:                         xmlSwitchInputEncoding(ctxt, ret, handler);
                   3712:                     } else {
                   3713:                         __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
                   3714:                                          "Unknown encoding %s",
                   3715:                                          BAD_CAST encoding, NULL);
                   3716:                     }
                   3717:                     if (ret->encoding == NULL)
                   3718:                         ret->encoding = xmlStrdup(BAD_CAST encoding);
                   3719:                 }
                   3720: #if 0
                   3721:             } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
                   3722: #endif
                   3723:             }
                   3724:             redir = xmlNanoHTTPRedir(ret->buf->context);
                   3725:             if (redir != NULL) {
                   3726:                 if (ret->filename != NULL)
                   3727:                     xmlFree((xmlChar *) ret->filename);
                   3728:                 if (ret->directory != NULL) {
                   3729:                     xmlFree((xmlChar *) ret->directory);
                   3730:                     ret->directory = NULL;
                   3731:                 }
                   3732:                 ret->filename =
                   3733:                     (char *) xmlStrdup((const xmlChar *) redir);
                   3734:             }
                   3735:         }
                   3736:     }
                   3737: #endif
                   3738:     return(ret);
                   3739: }
                   3740: 
                   3741: static int xmlNoNetExists(const char *URL) {
                   3742:     const char *path;
                   3743: 
                   3744:     if (URL == NULL)
                   3745:        return(0);
                   3746: 
                   3747:     if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
                   3748: #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
                   3749:        path = &URL[17];
                   3750: #else
                   3751:        path = &URL[16];
                   3752: #endif
                   3753:     else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
                   3754: #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
                   3755:        path = &URL[8];
                   3756: #else
                   3757:        path = &URL[7];
                   3758: #endif
                   3759:     } else
                   3760:        path = URL;
                   3761: 
                   3762:     return xmlCheckFilename(path);
                   3763: }
                   3764: 
                   3765: #ifdef LIBXML_CATALOG_ENABLED
                   3766: 
                   3767: /**
                   3768:  * xmlResolveResourceFromCatalog:
                   3769:  * @URL:  the URL for the entity to load
                   3770:  * @ID:  the System ID for the entity to load
                   3771:  * @ctxt:  the context in which the entity is called or NULL
                   3772:  *
                   3773:  * Resolves the URL and ID against the appropriate catalog.
                   3774:  * This function is used by xmlDefaultExternalEntityLoader and
                   3775:  * xmlNoNetExternalEntityLoader.
                   3776:  *
                   3777:  * Returns a new allocated URL, or NULL.
                   3778:  */
                   3779: static xmlChar *
                   3780: xmlResolveResourceFromCatalog(const char *URL, const char *ID,
                   3781:                               xmlParserCtxtPtr ctxt) {
                   3782:     xmlChar *resource = NULL;
                   3783:     xmlCatalogAllow pref;
                   3784: 
                   3785:     /*
                   3786:      * If the resource doesn't exists as a file,
                   3787:      * try to load it from the resource pointed in the catalogs
                   3788:      */
                   3789:     pref = xmlCatalogGetDefaults();
                   3790: 
                   3791:     if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
                   3792:        /*
                   3793:         * Do a local lookup
                   3794:         */
                   3795:        if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
                   3796:            ((pref == XML_CATA_ALLOW_ALL) ||
                   3797:             (pref == XML_CATA_ALLOW_DOCUMENT))) {
                   3798:            resource = xmlCatalogLocalResolve(ctxt->catalogs,
                   3799:                                              (const xmlChar *)ID,
                   3800:                                              (const xmlChar *)URL);
                   3801:         }
                   3802:        /*
                   3803:         * Try a global lookup
                   3804:         */
                   3805:        if ((resource == NULL) &&
                   3806:            ((pref == XML_CATA_ALLOW_ALL) ||
                   3807:             (pref == XML_CATA_ALLOW_GLOBAL))) {
                   3808:            resource = xmlCatalogResolve((const xmlChar *)ID,
                   3809:                                         (const xmlChar *)URL);
                   3810:        }
                   3811:        if ((resource == NULL) && (URL != NULL))
                   3812:            resource = xmlStrdup((const xmlChar *) URL);
                   3813: 
                   3814:        /*
                   3815:         * TODO: do an URI lookup on the reference
                   3816:         */
                   3817:        if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
                   3818:            xmlChar *tmp = NULL;
                   3819: 
                   3820:            if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
                   3821:                ((pref == XML_CATA_ALLOW_ALL) ||
                   3822:                 (pref == XML_CATA_ALLOW_DOCUMENT))) {
                   3823:                tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
                   3824:            }
                   3825:            if ((tmp == NULL) &&
                   3826:                ((pref == XML_CATA_ALLOW_ALL) ||
                   3827:                 (pref == XML_CATA_ALLOW_GLOBAL))) {
                   3828:                tmp = xmlCatalogResolveURI(resource);
                   3829:            }
                   3830: 
                   3831:            if (tmp != NULL) {
                   3832:                xmlFree(resource);
                   3833:                resource = tmp;
                   3834:            }
                   3835:        }
                   3836:     }
                   3837: 
                   3838:     return resource;
                   3839: }
                   3840: 
                   3841: #endif
                   3842: 
                   3843: /**
                   3844:  * xmlDefaultExternalEntityLoader:
                   3845:  * @URL:  the URL for the entity to load
                   3846:  * @ID:  the System ID for the entity to load
                   3847:  * @ctxt:  the context in which the entity is called or NULL
                   3848:  *
                   3849:  * By default we don't load external entitites, yet.
                   3850:  *
                   3851:  * Returns a new allocated xmlParserInputPtr, or NULL.
                   3852:  */
                   3853: static xmlParserInputPtr
                   3854: xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
                   3855:                                xmlParserCtxtPtr ctxt)
                   3856: {
                   3857:     xmlParserInputPtr ret = NULL;
                   3858:     xmlChar *resource = NULL;
                   3859: 
                   3860: #ifdef DEBUG_EXTERNAL_ENTITIES
                   3861:     xmlGenericError(xmlGenericErrorContext,
                   3862:                     "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
                   3863: #endif
                   3864:     if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
                   3865:         int options = ctxt->options;
                   3866: 
                   3867:        ctxt->options -= XML_PARSE_NONET;
                   3868:         ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
                   3869:        ctxt->options = options;
                   3870:        return(ret);
                   3871:     }
                   3872: #ifdef LIBXML_CATALOG_ENABLED
                   3873:     resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
                   3874: #endif
                   3875: 
                   3876:     if (resource == NULL)
                   3877:         resource = (xmlChar *) URL;
                   3878: 
                   3879:     if (resource == NULL) {
                   3880:         if (ID == NULL)
                   3881:             ID = "NULL";
                   3882:         __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
                   3883:         return (NULL);
                   3884:     }
                   3885:     ret = xmlNewInputFromFile(ctxt, (const char *) resource);
                   3886:     if ((resource != NULL) && (resource != (xmlChar *) URL))
                   3887:         xmlFree(resource);
                   3888:     return (ret);
                   3889: }
                   3890: 
                   3891: static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
                   3892:        xmlDefaultExternalEntityLoader;
                   3893: 
                   3894: /**
                   3895:  * xmlSetExternalEntityLoader:
                   3896:  * @f:  the new entity resolver function
                   3897:  *
                   3898:  * Changes the defaultexternal entity resolver function for the application
                   3899:  */
                   3900: void
                   3901: xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
                   3902:     xmlCurrentExternalEntityLoader = f;
                   3903: }
                   3904: 
                   3905: /**
                   3906:  * xmlGetExternalEntityLoader:
                   3907:  *
                   3908:  * Get the default external entity resolver function for the application
                   3909:  *
                   3910:  * Returns the xmlExternalEntityLoader function pointer
                   3911:  */
                   3912: xmlExternalEntityLoader
                   3913: xmlGetExternalEntityLoader(void) {
                   3914:     return(xmlCurrentExternalEntityLoader);
                   3915: }
                   3916: 
                   3917: /**
                   3918:  * xmlLoadExternalEntity:
                   3919:  * @URL:  the URL for the entity to load
                   3920:  * @ID:  the Public ID for the entity to load
                   3921:  * @ctxt:  the context in which the entity is called or NULL
                   3922:  *
                   3923:  * Load an external entity, note that the use of this function for
                   3924:  * unparsed entities may generate problems
                   3925:  *
                   3926:  * Returns the xmlParserInputPtr or NULL
                   3927:  */
                   3928: xmlParserInputPtr
                   3929: xmlLoadExternalEntity(const char *URL, const char *ID,
                   3930:                       xmlParserCtxtPtr ctxt) {
                   3931:     if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
                   3932:        char *canonicFilename;
                   3933:        xmlParserInputPtr ret;
                   3934: 
                   3935:        canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
                   3936:        if (canonicFilename == NULL) {
                   3937:             xmlIOErrMemory("building canonical path\n");
                   3938:            return(NULL);
                   3939:        }
                   3940: 
                   3941:        ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
                   3942:        xmlFree(canonicFilename);
                   3943:        return(ret);
                   3944:     }
                   3945:     return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
                   3946: }
                   3947: 
                   3948: /************************************************************************
                   3949:  *                                                                     *
                   3950:  *             Disabling Network access                                *
                   3951:  *                                                                     *
                   3952:  ************************************************************************/
                   3953: 
                   3954: /**
                   3955:  * xmlNoNetExternalEntityLoader:
                   3956:  * @URL:  the URL for the entity to load
                   3957:  * @ID:  the System ID for the entity to load
                   3958:  * @ctxt:  the context in which the entity is called or NULL
                   3959:  *
                   3960:  * A specific entity loader disabling network accesses, though still
                   3961:  * allowing local catalog accesses for resolution.
                   3962:  *
                   3963:  * Returns a new allocated xmlParserInputPtr, or NULL.
                   3964:  */
                   3965: xmlParserInputPtr
                   3966: xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
                   3967:                              xmlParserCtxtPtr ctxt) {
                   3968:     xmlParserInputPtr input = NULL;
                   3969:     xmlChar *resource = NULL;
                   3970: 
                   3971: #ifdef LIBXML_CATALOG_ENABLED
                   3972:     resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
                   3973: #endif
                   3974: 
                   3975:     if (resource == NULL)
                   3976:        resource = (xmlChar *) URL;
                   3977: 
                   3978:     if (resource != NULL) {
                   3979:         if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
                   3980:             (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
                   3981:             xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
                   3982:            if (resource != (xmlChar *) URL)
                   3983:                xmlFree(resource);
                   3984:            return(NULL);
                   3985:        }
                   3986:     }
                   3987:     input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
                   3988:     if (resource != (xmlChar *) URL)
                   3989:        xmlFree(resource);
                   3990:     return(input);
                   3991: }
                   3992: 
                   3993: #define bottom_xmlIO
                   3994: #include "elfgcchack.h"

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