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