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