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