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