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