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