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