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