File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xmlIO.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jul 22 01:22:19 2013 UTC (10 years, 11 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_8_0p0, v2_8_0, HEAD
2.8.0

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

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