File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xmlIO.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:37:58 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    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>