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