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