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