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