File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xmlIO.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:30 2014 UTC (10 years ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

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

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