libxml2 2.9.1 clean sources
[tomato.git] / release / src / router / libxml2 / xmlIO.c
blob847cb7edbbda1c5bfc7c2c3b2ad03a5bfe219dcf
1 /*
2 * xmlIO.c : implementation of the I/O interfaces used by the parser
4 * See Copyright for the status of this software.
6 * daniel@veillard.com
8 * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
9 */
11 #define IN_LIBXML
12 #include "libxml.h"
14 #include <string.h>
15 #ifdef HAVE_ERRNO_H
16 #include <errno.h>
17 #endif
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
42 #if defined(WIN32) || defined(_WIN32)
43 #include <windows.h>
44 #endif
46 #if defined(_WIN32_WCE)
47 #include <winnls.h> /* for CP_UTF8 */
48 #endif
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
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>
99 #include "buf.h"
100 #include "enc.h"
102 /* #define VERBOSE_FAILURE */
103 /* #define DEBUG_EXTERNAL_ENTITIES */
104 /* #define DEBUG_INPUT */
106 #ifdef DEBUG_INPUT
107 #define MINLEN 40
108 #else
109 #define MINLEN 4000
110 #endif
113 * Input I/O callback sets
115 typedef struct _xmlInputCallback {
116 xmlInputMatchCallback matchcallback;
117 xmlInputOpenCallback opencallback;
118 xmlInputReadCallback readcallback;
119 xmlInputCloseCallback closecallback;
120 } xmlInputCallback;
122 #define MAX_INPUT_CALLBACK 15
124 static xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
125 static int xmlInputCallbackNr = 0;
126 static int xmlInputCallbackInitialized = 0;
128 #ifdef LIBXML_OUTPUT_ENABLED
130 * Output I/O callback sets
132 typedef struct _xmlOutputCallback {
133 xmlOutputMatchCallback matchcallback;
134 xmlOutputOpenCallback opencallback;
135 xmlOutputWriteCallback writecallback;
136 xmlOutputCloseCallback closecallback;
137 } xmlOutputCallback;
139 #define MAX_OUTPUT_CALLBACK 15
141 static xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
142 static int xmlOutputCallbackNr = 0;
143 static int xmlOutputCallbackInitialized = 0;
145 xmlOutputBufferPtr
146 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder);
147 #endif /* LIBXML_OUTPUT_ENABLED */
149 /************************************************************************
151 * Tree memory error handler *
153 ************************************************************************/
155 static const char *IOerr[] = {
156 "Unknown IO error", /* UNKNOWN */
157 "Permission denied", /* EACCES */
158 "Resource temporarily unavailable",/* EAGAIN */
159 "Bad file descriptor", /* EBADF */
160 "Bad message", /* EBADMSG */
161 "Resource busy", /* EBUSY */
162 "Operation canceled", /* ECANCELED */
163 "No child processes", /* ECHILD */
164 "Resource deadlock avoided",/* EDEADLK */
165 "Domain error", /* EDOM */
166 "File exists", /* EEXIST */
167 "Bad address", /* EFAULT */
168 "File too large", /* EFBIG */
169 "Operation in progress", /* EINPROGRESS */
170 "Interrupted function call",/* EINTR */
171 "Invalid argument", /* EINVAL */
172 "Input/output error", /* EIO */
173 "Is a directory", /* EISDIR */
174 "Too many open files", /* EMFILE */
175 "Too many links", /* EMLINK */
176 "Inappropriate message buffer length",/* EMSGSIZE */
177 "Filename too long", /* ENAMETOOLONG */
178 "Too many open files in system",/* ENFILE */
179 "No such device", /* ENODEV */
180 "No such file or directory",/* ENOENT */
181 "Exec format error", /* ENOEXEC */
182 "No locks available", /* ENOLCK */
183 "Not enough space", /* ENOMEM */
184 "No space left on device", /* ENOSPC */
185 "Function not implemented", /* ENOSYS */
186 "Not a directory", /* ENOTDIR */
187 "Directory not empty", /* ENOTEMPTY */
188 "Not supported", /* ENOTSUP */
189 "Inappropriate I/O control operation",/* ENOTTY */
190 "No such device or address",/* ENXIO */
191 "Operation not permitted", /* EPERM */
192 "Broken pipe", /* EPIPE */
193 "Result too large", /* ERANGE */
194 "Read-only file system", /* EROFS */
195 "Invalid seek", /* ESPIPE */
196 "No such process", /* ESRCH */
197 "Operation timed out", /* ETIMEDOUT */
198 "Improper link", /* EXDEV */
199 "Attempt to load network entity %s", /* XML_IO_NETWORK_ATTEMPT */
200 "encoder error", /* XML_IO_ENCODER */
201 "flush error",
202 "write error",
203 "no input",
204 "buffer full",
205 "loading error",
206 "not a socket", /* ENOTSOCK */
207 "already connected", /* EISCONN */
208 "connection refused", /* ECONNREFUSED */
209 "unreachable network", /* ENETUNREACH */
210 "adddress in use", /* EADDRINUSE */
211 "already in use", /* EALREADY */
212 "unknown address familly", /* EAFNOSUPPORT */
215 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
217 * __xmlIOWin32UTF8ToWChar:
218 * @u8String: uft-8 string
220 * Convert a string from utf-8 to wchar (WINDOWS ONLY!)
222 static wchar_t *
223 __xmlIOWin32UTF8ToWChar(const char *u8String)
225 wchar_t *wString = NULL;
227 if (u8String) {
228 int wLen =
229 MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u8String,
230 -1, NULL, 0);
231 if (wLen) {
232 wString = xmlMalloc(wLen * sizeof(wchar_t));
233 if (wString) {
234 if (MultiByteToWideChar
235 (CP_UTF8, 0, u8String, -1, wString, wLen) == 0) {
236 xmlFree(wString);
237 wString = NULL;
243 return wString;
245 #endif
248 * xmlIOErrMemory:
249 * @extra: extra informations
251 * Handle an out of memory condition
253 static void
254 xmlIOErrMemory(const char *extra)
256 __xmlSimpleError(XML_FROM_IO, XML_ERR_NO_MEMORY, NULL, NULL, extra);
260 * __xmlIOErr:
261 * @code: the error number
263 * @extra: extra informations
265 * Handle an I/O error
267 void
268 __xmlIOErr(int domain, int code, const char *extra)
270 unsigned int idx;
272 if (code == 0) {
273 #ifdef HAVE_ERRNO_H
274 if (errno == 0) code = 0;
275 #ifdef EACCES
276 else if (errno == EACCES) code = XML_IO_EACCES;
277 #endif
278 #ifdef EAGAIN
279 else if (errno == EAGAIN) code = XML_IO_EAGAIN;
280 #endif
281 #ifdef EBADF
282 else if (errno == EBADF) code = XML_IO_EBADF;
283 #endif
284 #ifdef EBADMSG
285 else if (errno == EBADMSG) code = XML_IO_EBADMSG;
286 #endif
287 #ifdef EBUSY
288 else if (errno == EBUSY) code = XML_IO_EBUSY;
289 #endif
290 #ifdef ECANCELED
291 else if (errno == ECANCELED) code = XML_IO_ECANCELED;
292 #endif
293 #ifdef ECHILD
294 else if (errno == ECHILD) code = XML_IO_ECHILD;
295 #endif
296 #ifdef EDEADLK
297 else if (errno == EDEADLK) code = XML_IO_EDEADLK;
298 #endif
299 #ifdef EDOM
300 else if (errno == EDOM) code = XML_IO_EDOM;
301 #endif
302 #ifdef EEXIST
303 else if (errno == EEXIST) code = XML_IO_EEXIST;
304 #endif
305 #ifdef EFAULT
306 else if (errno == EFAULT) code = XML_IO_EFAULT;
307 #endif
308 #ifdef EFBIG
309 else if (errno == EFBIG) code = XML_IO_EFBIG;
310 #endif
311 #ifdef EINPROGRESS
312 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
313 #endif
314 #ifdef EINTR
315 else if (errno == EINTR) code = XML_IO_EINTR;
316 #endif
317 #ifdef EINVAL
318 else if (errno == EINVAL) code = XML_IO_EINVAL;
319 #endif
320 #ifdef EIO
321 else if (errno == EIO) code = XML_IO_EIO;
322 #endif
323 #ifdef EISDIR
324 else if (errno == EISDIR) code = XML_IO_EISDIR;
325 #endif
326 #ifdef EMFILE
327 else if (errno == EMFILE) code = XML_IO_EMFILE;
328 #endif
329 #ifdef EMLINK
330 else if (errno == EMLINK) code = XML_IO_EMLINK;
331 #endif
332 #ifdef EMSGSIZE
333 else if (errno == EMSGSIZE) code = XML_IO_EMSGSIZE;
334 #endif
335 #ifdef ENAMETOOLONG
336 else if (errno == ENAMETOOLONG) code = XML_IO_ENAMETOOLONG;
337 #endif
338 #ifdef ENFILE
339 else if (errno == ENFILE) code = XML_IO_ENFILE;
340 #endif
341 #ifdef ENODEV
342 else if (errno == ENODEV) code = XML_IO_ENODEV;
343 #endif
344 #ifdef ENOENT
345 else if (errno == ENOENT) code = XML_IO_ENOENT;
346 #endif
347 #ifdef ENOEXEC
348 else if (errno == ENOEXEC) code = XML_IO_ENOEXEC;
349 #endif
350 #ifdef ENOLCK
351 else if (errno == ENOLCK) code = XML_IO_ENOLCK;
352 #endif
353 #ifdef ENOMEM
354 else if (errno == ENOMEM) code = XML_IO_ENOMEM;
355 #endif
356 #ifdef ENOSPC
357 else if (errno == ENOSPC) code = XML_IO_ENOSPC;
358 #endif
359 #ifdef ENOSYS
360 else if (errno == ENOSYS) code = XML_IO_ENOSYS;
361 #endif
362 #ifdef ENOTDIR
363 else if (errno == ENOTDIR) code = XML_IO_ENOTDIR;
364 #endif
365 #ifdef ENOTEMPTY
366 else if (errno == ENOTEMPTY) code = XML_IO_ENOTEMPTY;
367 #endif
368 #ifdef ENOTSUP
369 else if (errno == ENOTSUP) code = XML_IO_ENOTSUP;
370 #endif
371 #ifdef ENOTTY
372 else if (errno == ENOTTY) code = XML_IO_ENOTTY;
373 #endif
374 #ifdef ENXIO
375 else if (errno == ENXIO) code = XML_IO_ENXIO;
376 #endif
377 #ifdef EPERM
378 else if (errno == EPERM) code = XML_IO_EPERM;
379 #endif
380 #ifdef EPIPE
381 else if (errno == EPIPE) code = XML_IO_EPIPE;
382 #endif
383 #ifdef ERANGE
384 else if (errno == ERANGE) code = XML_IO_ERANGE;
385 #endif
386 #ifdef EROFS
387 else if (errno == EROFS) code = XML_IO_EROFS;
388 #endif
389 #ifdef ESPIPE
390 else if (errno == ESPIPE) code = XML_IO_ESPIPE;
391 #endif
392 #ifdef ESRCH
393 else if (errno == ESRCH) code = XML_IO_ESRCH;
394 #endif
395 #ifdef ETIMEDOUT
396 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
397 #endif
398 #ifdef EXDEV
399 else if (errno == EXDEV) code = XML_IO_EXDEV;
400 #endif
401 #ifdef ENOTSOCK
402 else if (errno == ENOTSOCK) code = XML_IO_ENOTSOCK;
403 #endif
404 #ifdef EISCONN
405 else if (errno == EISCONN) code = XML_IO_EISCONN;
406 #endif
407 #ifdef ECONNREFUSED
408 else if (errno == ECONNREFUSED) code = XML_IO_ECONNREFUSED;
409 #endif
410 #ifdef ETIMEDOUT
411 else if (errno == ETIMEDOUT) code = XML_IO_ETIMEDOUT;
412 #endif
413 #ifdef ENETUNREACH
414 else if (errno == ENETUNREACH) code = XML_IO_ENETUNREACH;
415 #endif
416 #ifdef EADDRINUSE
417 else if (errno == EADDRINUSE) code = XML_IO_EADDRINUSE;
418 #endif
419 #ifdef EINPROGRESS
420 else if (errno == EINPROGRESS) code = XML_IO_EINPROGRESS;
421 #endif
422 #ifdef EALREADY
423 else if (errno == EALREADY) code = XML_IO_EALREADY;
424 #endif
425 #ifdef EAFNOSUPPORT
426 else if (errno == EAFNOSUPPORT) code = XML_IO_EAFNOSUPPORT;
427 #endif
428 else code = XML_IO_UNKNOWN;
429 #endif /* HAVE_ERRNO_H */
431 idx = 0;
432 if (code >= XML_IO_UNKNOWN) idx = code - XML_IO_UNKNOWN;
433 if (idx >= (sizeof(IOerr) / sizeof(IOerr[0]))) idx = 0;
435 __xmlSimpleError(domain, code, NULL, IOerr[idx], extra);
439 * xmlIOErr:
440 * @code: the error number
441 * @extra: extra informations
443 * Handle an I/O error
445 static void
446 xmlIOErr(int code, const char *extra)
448 __xmlIOErr(XML_FROM_IO, code, extra);
452 * __xmlLoaderErr:
453 * @ctx: the parser context
454 * @extra: extra informations
456 * Handle a resource access error
458 void
459 __xmlLoaderErr(void *ctx, const char *msg, const char *filename)
461 xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
462 xmlStructuredErrorFunc schannel = NULL;
463 xmlGenericErrorFunc channel = NULL;
464 void *data = NULL;
465 xmlErrorLevel level = XML_ERR_ERROR;
467 if ((ctxt != NULL) && (ctxt->disableSAX != 0) &&
468 (ctxt->instate == XML_PARSER_EOF))
469 return;
470 if ((ctxt != NULL) && (ctxt->sax != NULL)) {
471 if (ctxt->validate) {
472 channel = ctxt->sax->error;
473 level = XML_ERR_ERROR;
474 } else {
475 channel = ctxt->sax->warning;
476 level = XML_ERR_WARNING;
478 if (ctxt->sax->initialized == XML_SAX2_MAGIC)
479 schannel = ctxt->sax->serror;
480 data = ctxt->userData;
482 __xmlRaiseError(schannel, channel, data, ctxt, NULL, XML_FROM_IO,
483 XML_IO_LOAD_ERROR, level, NULL, 0,
484 filename, NULL, NULL, 0, 0,
485 msg, filename);
489 /************************************************************************
491 * Tree memory error handler *
493 ************************************************************************/
495 * xmlNormalizeWindowsPath:
496 * @path: the input file path
498 * This function is obsolete. Please see xmlURIFromPath in uri.c for
499 * a better solution.
501 * Returns a canonicalized version of the path
503 xmlChar *
504 xmlNormalizeWindowsPath(const xmlChar *path)
506 return xmlCanonicPath(path);
510 * xmlCleanupInputCallbacks:
512 * clears the entire input callback table. this includes the
513 * compiled-in I/O.
515 void
516 xmlCleanupInputCallbacks(void)
518 int i;
520 if (!xmlInputCallbackInitialized)
521 return;
523 for (i = xmlInputCallbackNr - 1; i >= 0; i--) {
524 xmlInputCallbackTable[i].matchcallback = NULL;
525 xmlInputCallbackTable[i].opencallback = NULL;
526 xmlInputCallbackTable[i].readcallback = NULL;
527 xmlInputCallbackTable[i].closecallback = NULL;
530 xmlInputCallbackNr = 0;
531 xmlInputCallbackInitialized = 0;
535 * xmlPopInputCallbacks:
537 * Clear the top input callback from the input stack. this includes the
538 * compiled-in I/O.
540 * Returns the number of input callback registered or -1 in case of error.
543 xmlPopInputCallbacks(void)
545 if (!xmlInputCallbackInitialized)
546 return(-1);
548 if (xmlInputCallbackNr <= 0)
549 return(-1);
551 xmlInputCallbackNr--;
552 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = NULL;
553 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = NULL;
554 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = NULL;
555 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = NULL;
557 return(xmlInputCallbackNr);
560 #ifdef LIBXML_OUTPUT_ENABLED
562 * xmlCleanupOutputCallbacks:
564 * clears the entire output callback table. this includes the
565 * compiled-in I/O callbacks.
567 void
568 xmlCleanupOutputCallbacks(void)
570 int i;
572 if (!xmlOutputCallbackInitialized)
573 return;
575 for (i = xmlOutputCallbackNr - 1; i >= 0; i--) {
576 xmlOutputCallbackTable[i].matchcallback = NULL;
577 xmlOutputCallbackTable[i].opencallback = NULL;
578 xmlOutputCallbackTable[i].writecallback = NULL;
579 xmlOutputCallbackTable[i].closecallback = NULL;
582 xmlOutputCallbackNr = 0;
583 xmlOutputCallbackInitialized = 0;
585 #endif /* LIBXML_OUTPUT_ENABLED */
587 /************************************************************************
589 * Standard I/O for file accesses *
591 ************************************************************************/
593 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
596 * xmlWrapOpenUtf8:
597 * @path: the path in utf-8 encoding
598 * @mode: type of access (0 - read, 1 - write)
600 * function opens the file specified by @path
603 static FILE*
604 xmlWrapOpenUtf8(const char *path,int mode)
606 FILE *fd = NULL;
607 wchar_t *wPath;
609 wPath = __xmlIOWin32UTF8ToWChar(path);
610 if(wPath)
612 fd = _wfopen(wPath, mode ? L"wb" : L"rb");
613 xmlFree(wPath);
615 /* maybe path in native encoding */
616 if(fd == NULL)
617 fd = fopen(path, mode ? "wb" : "rb");
619 return fd;
622 #ifdef HAVE_ZLIB_H
623 static gzFile
624 xmlWrapGzOpenUtf8(const char *path, const char *mode)
626 gzFile fd;
627 wchar_t *wPath;
629 fd = gzopen (path, mode);
630 if (fd)
631 return fd;
633 wPath = __xmlIOWin32UTF8ToWChar(path);
634 if(wPath)
636 int d, m = (strstr(mode, "r") ? O_RDONLY : O_RDWR);
637 #ifdef _O_BINARY
638 m |= (strstr(mode, "b") ? _O_BINARY : 0);
639 #endif
640 d = _wopen(wPath, m);
641 if (d >= 0)
642 fd = gzdopen(d, mode);
643 xmlFree(wPath);
646 return fd;
648 #endif
651 * xmlWrapStatUtf8:
652 * @path: the path in utf-8 encoding
653 * @info: structure that stores results
655 * function obtains information about the file or directory
658 static int
659 xmlWrapStatUtf8(const char *path,struct stat *info)
661 #ifdef HAVE_STAT
662 int retval = -1;
663 wchar_t *wPath;
665 wPath = __xmlIOWin32UTF8ToWChar(path);
666 if (wPath)
668 retval = _wstat(wPath,info);
669 xmlFree(wPath);
671 /* maybe path in native encoding */
672 if(retval < 0)
673 retval = stat(path,info);
674 return retval;
675 #else
676 return -1;
677 #endif
681 * xmlWrapOpenNative:
682 * @path: the path
683 * @mode: type of access (0 - read, 1 - write)
685 * function opens the file specified by @path
688 static FILE*
689 xmlWrapOpenNative(const char *path,int mode)
691 return fopen(path,mode ? "wb" : "rb");
695 * xmlWrapStatNative:
696 * @path: the path
697 * @info: structure that stores results
699 * function obtains information about the file or directory
702 static int
703 xmlWrapStatNative(const char *path,struct stat *info)
705 #ifdef HAVE_STAT
706 return stat(path,info);
707 #else
708 return -1;
709 #endif
712 typedef int (* xmlWrapStatFunc) (const char *f, struct stat *s);
713 static xmlWrapStatFunc xmlWrapStat = xmlWrapStatNative;
714 typedef FILE* (* xmlWrapOpenFunc)(const char *f,int mode);
715 static xmlWrapOpenFunc xmlWrapOpen = xmlWrapOpenNative;
716 #ifdef HAVE_ZLIB_H
717 typedef gzFile (* xmlWrapGzOpenFunc) (const char *f, const char *mode);
718 static xmlWrapGzOpenFunc xmlWrapGzOpen = gzopen;
719 #endif
721 * xmlInitPlatformSpecificIo:
723 * Initialize platform specific features.
725 static void
726 xmlInitPlatformSpecificIo(void)
728 static int xmlPlatformIoInitialized = 0;
729 OSVERSIONINFO osvi;
731 if(xmlPlatformIoInitialized)
732 return;
734 osvi.dwOSVersionInfoSize = sizeof(osvi);
736 if(GetVersionEx(&osvi) && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT)) {
737 xmlWrapStat = xmlWrapStatUtf8;
738 xmlWrapOpen = xmlWrapOpenUtf8;
739 #ifdef HAVE_ZLIB_H
740 xmlWrapGzOpen = xmlWrapGzOpenUtf8;
741 #endif
742 } else {
743 xmlWrapStat = xmlWrapStatNative;
744 xmlWrapOpen = xmlWrapOpenNative;
745 #ifdef HAVE_ZLIB_H
746 xmlWrapGzOpen = gzopen;
747 #endif
750 xmlPlatformIoInitialized = 1;
751 return;
754 #endif
757 * xmlCheckFilename:
758 * @path: the path to check
760 * function checks to see if @path is a valid source
761 * (file, socket...) for XML.
763 * if stat is not available on the target machine,
764 * returns 1. if stat fails, returns 0 (if calling
765 * stat on the filename fails, it can't be right).
766 * if stat succeeds and the file is a directory,
767 * returns 2. otherwise returns 1.
771 xmlCheckFilename (const char *path)
773 #ifdef HAVE_STAT
774 struct stat stat_buffer;
775 #endif
776 if (path == NULL)
777 return(0);
779 #ifdef HAVE_STAT
780 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
782 * On Windows stat and wstat do not work with long pathname,
783 * which start with '\\?\'
785 if ((path[0] == '\\') && (path[1] == '\\') && (path[2] == '?') &&
786 (path[3] == '\\') )
787 return 1;
789 if (xmlWrapStat(path, &stat_buffer) == -1)
790 return 0;
791 #else
792 if (stat(path, &stat_buffer) == -1)
793 return 0;
794 #endif
795 #ifdef S_ISDIR
796 if (S_ISDIR(stat_buffer.st_mode))
797 return 2;
798 #endif
799 #endif /* HAVE_STAT */
800 return 1;
804 xmlNop(void) {
805 return(0);
809 * xmlFdRead:
810 * @context: the I/O context
811 * @buffer: where to drop data
812 * @len: number of bytes to read
814 * Read @len bytes to @buffer from the I/O channel.
816 * Returns the number of bytes written
818 static int
819 xmlFdRead (void * context, char * buffer, int len) {
820 int ret;
822 ret = read((int) (long) context, &buffer[0], len);
823 if (ret < 0) xmlIOErr(0, "read()");
824 return(ret);
827 #ifdef LIBXML_OUTPUT_ENABLED
829 * xmlFdWrite:
830 * @context: the I/O context
831 * @buffer: where to get data
832 * @len: number of bytes to write
834 * Write @len bytes from @buffer to the I/O channel.
836 * Returns the number of bytes written
838 static int
839 xmlFdWrite (void * context, const char * buffer, int len) {
840 int ret = 0;
842 if (len > 0) {
843 ret = write((int) (long) context, &buffer[0], len);
844 if (ret < 0) xmlIOErr(0, "write()");
846 return(ret);
848 #endif /* LIBXML_OUTPUT_ENABLED */
851 * xmlFdClose:
852 * @context: the I/O context
854 * Close an I/O channel
856 * Returns 0 in case of success and error code otherwise
858 static int
859 xmlFdClose (void * context) {
860 int ret;
861 ret = close((int) (long) context);
862 if (ret < 0) xmlIOErr(0, "close()");
863 return(ret);
867 * xmlFileMatch:
868 * @filename: the URI for matching
870 * input from FILE *
872 * Returns 1 if matches, 0 otherwise
875 xmlFileMatch (const char *filename ATTRIBUTE_UNUSED) {
876 return(1);
880 * xmlFileOpen_real:
881 * @filename: the URI for matching
883 * input from FILE *, supports compressed input
884 * if @filename is " " then the standard input is used
886 * Returns an I/O context or NULL in case of error
888 static void *
889 xmlFileOpen_real (const char *filename) {
890 const char *path = NULL;
891 FILE *fd;
893 if (filename == NULL)
894 return(NULL);
896 if (!strcmp(filename, "-")) {
897 fd = stdin;
898 return((void *) fd);
901 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
902 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
903 path = &filename[17];
904 #else
905 path = &filename[16];
906 #endif
907 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
908 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
909 path = &filename[8];
910 #else
911 path = &filename[7];
912 #endif
913 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
914 /* lots of generators seems to lazy to read RFC 1738 */
915 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
916 path = &filename[6];
917 #else
918 path = &filename[5];
919 #endif
920 } else
921 path = filename;
923 if (path == NULL)
924 return(NULL);
925 if (!xmlCheckFilename(path))
926 return(NULL);
928 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
929 fd = xmlWrapOpen(path, 0);
930 #else
931 fd = fopen(path, "r");
932 #endif /* WIN32 */
933 if (fd == NULL) xmlIOErr(0, path);
934 return((void *) fd);
938 * xmlFileOpen:
939 * @filename: the URI for matching
941 * Wrapper around xmlFileOpen_real that try it with an unescaped
942 * version of @filename, if this fails fallback to @filename
944 * Returns a handler or NULL in case or failure
946 void *
947 xmlFileOpen (const char *filename) {
948 char *unescaped;
949 void *retval;
951 retval = xmlFileOpen_real(filename);
952 if (retval == NULL) {
953 unescaped = xmlURIUnescapeString(filename, 0, NULL);
954 if (unescaped != NULL) {
955 retval = xmlFileOpen_real(unescaped);
956 xmlFree(unescaped);
960 return retval;
963 #ifdef LIBXML_OUTPUT_ENABLED
965 * xmlFileOpenW:
966 * @filename: the URI for matching
968 * output to from FILE *,
969 * if @filename is "-" then the standard output is used
971 * Returns an I/O context or NULL in case of error
973 static void *
974 xmlFileOpenW (const char *filename) {
975 const char *path = NULL;
976 FILE *fd;
978 if (!strcmp(filename, "-")) {
979 fd = stdout;
980 return((void *) fd);
983 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
984 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
985 path = &filename[17];
986 #else
987 path = &filename[16];
988 #endif
989 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
990 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
991 path = &filename[8];
992 #else
993 path = &filename[7];
994 #endif
995 } else
996 path = filename;
998 if (path == NULL)
999 return(NULL);
1001 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1002 fd = xmlWrapOpen(path, 1);
1003 #else
1004 fd = fopen(path, "wb");
1005 #endif /* WIN32 */
1007 if (fd == NULL) xmlIOErr(0, path);
1008 return((void *) fd);
1010 #endif /* LIBXML_OUTPUT_ENABLED */
1013 * xmlFileRead:
1014 * @context: the I/O context
1015 * @buffer: where to drop data
1016 * @len: number of bytes to write
1018 * Read @len bytes to @buffer from the I/O channel.
1020 * Returns the number of bytes written or < 0 in case of failure
1023 xmlFileRead (void * context, char * buffer, int len) {
1024 int ret;
1025 if ((context == NULL) || (buffer == NULL))
1026 return(-1);
1027 ret = fread(&buffer[0], 1, len, (FILE *) context);
1028 if (ret < 0) xmlIOErr(0, "fread()");
1029 return(ret);
1032 #ifdef LIBXML_OUTPUT_ENABLED
1034 * xmlFileWrite:
1035 * @context: the I/O context
1036 * @buffer: where to drop data
1037 * @len: number of bytes to write
1039 * Write @len bytes from @buffer to the I/O channel.
1041 * Returns the number of bytes written
1043 static int
1044 xmlFileWrite (void * context, const char * buffer, int len) {
1045 int items;
1047 if ((context == NULL) || (buffer == NULL))
1048 return(-1);
1049 items = fwrite(&buffer[0], len, 1, (FILE *) context);
1050 if ((items == 0) && (ferror((FILE *) context))) {
1051 xmlIOErr(0, "fwrite()");
1052 return(-1);
1054 return(items * len);
1056 #endif /* LIBXML_OUTPUT_ENABLED */
1059 * xmlFileClose:
1060 * @context: the I/O context
1062 * Close an I/O channel
1064 * Returns 0 or -1 in case of error
1067 xmlFileClose (void * context) {
1068 FILE *fil;
1069 int ret;
1071 if (context == NULL)
1072 return(-1);
1073 fil = (FILE *) context;
1074 if ((fil == stdout) || (fil == stderr)) {
1075 ret = fflush(fil);
1076 if (ret < 0)
1077 xmlIOErr(0, "fflush()");
1078 return(0);
1080 if (fil == stdin)
1081 return(0);
1082 ret = ( fclose((FILE *) context) == EOF ) ? -1 : 0;
1083 if (ret < 0)
1084 xmlIOErr(0, "fclose()");
1085 return(ret);
1089 * xmlFileFlush:
1090 * @context: the I/O context
1092 * Flush an I/O channel
1094 static int
1095 xmlFileFlush (void * context) {
1096 int ret;
1098 if (context == NULL)
1099 return(-1);
1100 ret = ( fflush((FILE *) context) == EOF ) ? -1 : 0;
1101 if (ret < 0)
1102 xmlIOErr(0, "fflush()");
1103 return(ret);
1106 #ifdef LIBXML_OUTPUT_ENABLED
1108 * xmlBufferWrite:
1109 * @context: the xmlBuffer
1110 * @buffer: the data to write
1111 * @len: number of bytes to write
1113 * Write @len bytes from @buffer to the xml buffer
1115 * Returns the number of bytes written
1117 static int
1118 xmlBufferWrite (void * context, const char * buffer, int len) {
1119 int ret;
1121 ret = xmlBufferAdd((xmlBufferPtr) context, (const xmlChar *) buffer, len);
1122 if (ret != 0)
1123 return(-1);
1124 return(len);
1126 #endif
1128 #ifdef HAVE_ZLIB_H
1129 /************************************************************************
1131 * I/O for compressed file accesses *
1133 ************************************************************************/
1135 * xmlGzfileMatch:
1136 * @filename: the URI for matching
1138 * input from compressed file test
1140 * Returns 1 if matches, 0 otherwise
1142 static int
1143 xmlGzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1144 return(1);
1148 * xmlGzfileOpen_real:
1149 * @filename: the URI for matching
1151 * input from compressed file open
1152 * if @filename is " " then the standard input is used
1154 * Returns an I/O context or NULL in case of error
1156 static void *
1157 xmlGzfileOpen_real (const char *filename) {
1158 const char *path = NULL;
1159 gzFile fd;
1161 if (!strcmp(filename, "-")) {
1162 fd = gzdopen(dup(0), "rb");
1163 return((void *) fd);
1166 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
1167 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1168 path = &filename[17];
1169 #else
1170 path = &filename[16];
1171 #endif
1172 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1173 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1174 path = &filename[8];
1175 #else
1176 path = &filename[7];
1177 #endif
1178 } else
1179 path = filename;
1181 if (path == NULL)
1182 return(NULL);
1183 if (!xmlCheckFilename(path))
1184 return(NULL);
1186 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1187 fd = xmlWrapGzOpen(path, "rb");
1188 #else
1189 fd = gzopen(path, "rb");
1190 #endif
1191 return((void *) fd);
1195 * xmlGzfileOpen:
1196 * @filename: the URI for matching
1198 * Wrapper around xmlGzfileOpen if the open fais, it will
1199 * try to unescape @filename
1201 static void *
1202 xmlGzfileOpen (const char *filename) {
1203 char *unescaped;
1204 void *retval;
1206 retval = xmlGzfileOpen_real(filename);
1207 if (retval == NULL) {
1208 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1209 if (unescaped != NULL) {
1210 retval = xmlGzfileOpen_real(unescaped);
1212 xmlFree(unescaped);
1214 return retval;
1217 #ifdef LIBXML_OUTPUT_ENABLED
1219 * xmlGzfileOpenW:
1220 * @filename: the URI for matching
1221 * @compression: the compression factor (0 - 9 included)
1223 * input from compressed file open
1224 * if @filename is " " then the standard input is used
1226 * Returns an I/O context or NULL in case of error
1228 static void *
1229 xmlGzfileOpenW (const char *filename, int compression) {
1230 const char *path = NULL;
1231 char mode[15];
1232 gzFile fd;
1234 snprintf(mode, sizeof(mode), "wb%d", compression);
1235 if (!strcmp(filename, "-")) {
1236 fd = gzdopen(dup(1), mode);
1237 return((void *) fd);
1240 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17))
1241 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1242 path = &filename[17];
1243 #else
1244 path = &filename[16];
1245 #endif
1246 else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1247 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
1248 path = &filename[8];
1249 #else
1250 path = &filename[7];
1251 #endif
1252 } else
1253 path = filename;
1255 if (path == NULL)
1256 return(NULL);
1258 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
1259 fd = xmlWrapGzOpen(path, mode);
1260 #else
1261 fd = gzopen(path, mode);
1262 #endif
1263 return((void *) fd);
1265 #endif /* LIBXML_OUTPUT_ENABLED */
1268 * xmlGzfileRead:
1269 * @context: the I/O context
1270 * @buffer: where to drop data
1271 * @len: number of bytes to write
1273 * Read @len bytes to @buffer from the compressed I/O channel.
1275 * Returns the number of bytes written
1277 static int
1278 xmlGzfileRead (void * context, char * buffer, int len) {
1279 int ret;
1281 ret = gzread((gzFile) context, &buffer[0], len);
1282 if (ret < 0) xmlIOErr(0, "gzread()");
1283 return(ret);
1286 #ifdef LIBXML_OUTPUT_ENABLED
1288 * xmlGzfileWrite:
1289 * @context: the I/O context
1290 * @buffer: where to drop data
1291 * @len: number of bytes to write
1293 * Write @len bytes from @buffer to the compressed I/O channel.
1295 * Returns the number of bytes written
1297 static int
1298 xmlGzfileWrite (void * context, const char * buffer, int len) {
1299 int ret;
1301 ret = gzwrite((gzFile) context, (char *) &buffer[0], len);
1302 if (ret < 0) xmlIOErr(0, "gzwrite()");
1303 return(ret);
1305 #endif /* LIBXML_OUTPUT_ENABLED */
1308 * xmlGzfileClose:
1309 * @context: the I/O context
1311 * Close a compressed I/O channel
1313 static int
1314 xmlGzfileClose (void * context) {
1315 int ret;
1317 ret = (gzclose((gzFile) context) == Z_OK ) ? 0 : -1;
1318 if (ret < 0) xmlIOErr(0, "gzclose()");
1319 return(ret);
1321 #endif /* HAVE_ZLIB_H */
1323 #ifdef HAVE_LZMA_H
1324 /************************************************************************
1326 * I/O for compressed file accesses *
1328 ************************************************************************/
1329 #include "xzlib.h"
1331 * xmlXzfileMatch:
1332 * @filename: the URI for matching
1334 * input from compressed file test
1336 * Returns 1 if matches, 0 otherwise
1338 static int
1339 xmlXzfileMatch (const char *filename ATTRIBUTE_UNUSED) {
1340 return(1);
1344 * xmlXzFileOpen_real:
1345 * @filename: the URI for matching
1347 * input from compressed file open
1348 * if @filename is " " then the standard input is used
1350 * Returns an I/O context or NULL in case of error
1352 static void *
1353 xmlXzfileOpen_real (const char *filename) {
1354 const char *path = NULL;
1355 xzFile fd;
1357 if (!strcmp(filename, "-")) {
1358 fd = __libxml2_xzdopen(dup(0), "rb");
1359 return((void *) fd);
1362 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file://localhost/", 17)) {
1363 path = &filename[16];
1364 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:///", 8)) {
1365 path = &filename[7];
1366 } else if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "file:/", 6)) {
1367 /* lots of generators seems to lazy to read RFC 1738 */
1368 path = &filename[5];
1369 } else
1370 path = filename;
1372 if (path == NULL)
1373 return(NULL);
1374 if (!xmlCheckFilename(path))
1375 return(NULL);
1377 fd = __libxml2_xzopen(path, "rb");
1378 return((void *) fd);
1382 * xmlXzfileOpen:
1383 * @filename: the URI for matching
1385 * Wrapper around xmlXzfileOpen_real that try it with an unescaped
1386 * version of @filename, if this fails fallback to @filename
1388 * Returns a handler or NULL in case or failure
1390 static void *
1391 xmlXzfileOpen (const char *filename) {
1392 char *unescaped;
1393 void *retval;
1395 retval = xmlXzfileOpen_real(filename);
1396 if (retval == NULL) {
1397 unescaped = xmlURIUnescapeString(filename, 0, NULL);
1398 if (unescaped != NULL) {
1399 retval = xmlXzfileOpen_real(unescaped);
1401 xmlFree(unescaped);
1404 return retval;
1408 * xmlXzfileRead:
1409 * @context: the I/O context
1410 * @buffer: where to drop data
1411 * @len: number of bytes to write
1413 * Read @len bytes to @buffer from the compressed I/O channel.
1415 * Returns the number of bytes written
1417 static int
1418 xmlXzfileRead (void * context, char * buffer, int len) {
1419 int ret;
1421 ret = __libxml2_xzread((xzFile) context, &buffer[0], len);
1422 if (ret < 0) xmlIOErr(0, "xzread()");
1423 return(ret);
1427 * xmlXzfileClose:
1428 * @context: the I/O context
1430 * Close a compressed I/O channel
1432 static int
1433 xmlXzfileClose (void * context) {
1434 int ret;
1436 ret = (__libxml2_xzclose((xzFile) context) == LZMA_OK ) ? 0 : -1;
1437 if (ret < 0) xmlIOErr(0, "xzclose()");
1438 return(ret);
1440 #endif /* HAVE_LZMA_H */
1442 #ifdef LIBXML_HTTP_ENABLED
1443 /************************************************************************
1445 * I/O for HTTP file accesses *
1447 ************************************************************************/
1449 #ifdef LIBXML_OUTPUT_ENABLED
1450 typedef struct xmlIOHTTPWriteCtxt_
1452 int compression;
1454 char * uri;
1456 void * doc_buff;
1458 } xmlIOHTTPWriteCtxt, *xmlIOHTTPWriteCtxtPtr;
1460 #ifdef HAVE_ZLIB_H
1462 #define DFLT_WBITS ( -15 )
1463 #define DFLT_MEM_LVL ( 8 )
1464 #define GZ_MAGIC1 ( 0x1f )
1465 #define GZ_MAGIC2 ( 0x8b )
1466 #define LXML_ZLIB_OS_CODE ( 0x03 )
1467 #define INIT_HTTP_BUFF_SIZE ( 32768 )
1468 #define DFLT_ZLIB_RATIO ( 5 )
1471 ** Data structure and functions to work with sending compressed data
1472 ** via HTTP.
1475 typedef struct xmlZMemBuff_
1477 unsigned long size;
1478 unsigned long crc;
1480 unsigned char * zbuff;
1481 z_stream zctrl;
1483 } xmlZMemBuff, *xmlZMemBuffPtr;
1486 * append_reverse_ulong
1487 * @buff: Compressed memory buffer
1488 * @data: Unsigned long to append
1490 * Append a unsigned long in reverse byte order to the end of the
1491 * memory buffer.
1493 static void
1494 append_reverse_ulong( xmlZMemBuff * buff, unsigned long data ) {
1496 int idx;
1498 if ( buff == NULL )
1499 return;
1502 ** This is plagiarized from putLong in gzio.c (zlib source) where
1503 ** the number "4" is hardcoded. If zlib is ever patched to
1504 ** support 64 bit file sizes, this code would need to be patched
1505 ** as well.
1508 for ( idx = 0; idx < 4; idx++ ) {
1509 *buff->zctrl.next_out = ( data & 0xff );
1510 data >>= 8;
1511 buff->zctrl.next_out++;
1514 return;
1519 * xmlFreeZMemBuff
1520 * @buff: The memory buffer context to clear
1522 * Release all the resources associated with the compressed memory buffer.
1524 static void
1525 xmlFreeZMemBuff( xmlZMemBuffPtr buff ) {
1527 #ifdef DEBUG_HTTP
1528 int z_err;
1529 #endif
1531 if ( buff == NULL )
1532 return;
1534 xmlFree( buff->zbuff );
1535 #ifdef DEBUG_HTTP
1536 z_err = deflateEnd( &buff->zctrl );
1537 if ( z_err != Z_OK )
1538 xmlGenericError( xmlGenericErrorContext,
1539 "xmlFreeZMemBuff: Error releasing zlib context: %d\n",
1540 z_err );
1541 #else
1542 deflateEnd( &buff->zctrl );
1543 #endif
1545 xmlFree( buff );
1546 return;
1550 * xmlCreateZMemBuff
1551 *@compression: Compression value to use
1553 * Create a memory buffer to hold the compressed XML document. The
1554 * compressed document in memory will end up being identical to what
1555 * would be created if gzopen/gzwrite/gzclose were being used to
1556 * write the document to disk. The code for the header/trailer data to
1557 * the compression is plagiarized from the zlib source files.
1559 static void *
1560 xmlCreateZMemBuff( int compression ) {
1562 int z_err;
1563 int hdr_lgth;
1564 xmlZMemBuffPtr buff = NULL;
1566 if ( ( compression < 1 ) || ( compression > 9 ) )
1567 return ( NULL );
1569 /* Create the control and data areas */
1571 buff = xmlMalloc( sizeof( xmlZMemBuff ) );
1572 if ( buff == NULL ) {
1573 xmlIOErrMemory("creating buffer context");
1574 return ( NULL );
1577 (void)memset( buff, 0, sizeof( xmlZMemBuff ) );
1578 buff->size = INIT_HTTP_BUFF_SIZE;
1579 buff->zbuff = xmlMalloc( buff->size );
1580 if ( buff->zbuff == NULL ) {
1581 xmlFreeZMemBuff( buff );
1582 xmlIOErrMemory("creating buffer");
1583 return ( NULL );
1586 z_err = deflateInit2( &buff->zctrl, compression, Z_DEFLATED,
1587 DFLT_WBITS, DFLT_MEM_LVL, Z_DEFAULT_STRATEGY );
1588 if ( z_err != Z_OK ) {
1589 xmlChar msg[500];
1590 xmlFreeZMemBuff( buff );
1591 buff = NULL;
1592 xmlStrPrintf(msg, 500,
1593 (const xmlChar *) "xmlCreateZMemBuff: %s %d\n",
1594 "Error initializing compression context. ZLIB error:",
1595 z_err );
1596 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1597 return ( NULL );
1600 /* Set the header data. The CRC will be needed for the trailer */
1601 buff->crc = crc32( 0L, NULL, 0 );
1602 hdr_lgth = snprintf( (char *)buff->zbuff, buff->size,
1603 "%c%c%c%c%c%c%c%c%c%c",
1604 GZ_MAGIC1, GZ_MAGIC2, Z_DEFLATED,
1605 0, 0, 0, 0, 0, 0, LXML_ZLIB_OS_CODE );
1606 buff->zctrl.next_out = buff->zbuff + hdr_lgth;
1607 buff->zctrl.avail_out = buff->size - hdr_lgth;
1609 return ( buff );
1613 * xmlZMemBuffExtend
1614 * @buff: Buffer used to compress and consolidate data.
1615 * @ext_amt: Number of bytes to extend the buffer.
1617 * Extend the internal buffer used to store the compressed data by the
1618 * specified amount.
1620 * Returns 0 on success or -1 on failure to extend the buffer. On failure
1621 * the original buffer still exists at the original size.
1623 static int
1624 xmlZMemBuffExtend( xmlZMemBuffPtr buff, size_t ext_amt ) {
1626 int rc = -1;
1627 size_t new_size;
1628 size_t cur_used;
1630 unsigned char * tmp_ptr = NULL;
1632 if ( buff == NULL )
1633 return ( -1 );
1635 else if ( ext_amt == 0 )
1636 return ( 0 );
1638 cur_used = buff->zctrl.next_out - buff->zbuff;
1639 new_size = buff->size + ext_amt;
1641 #ifdef DEBUG_HTTP
1642 if ( cur_used > new_size )
1643 xmlGenericError( xmlGenericErrorContext,
1644 "xmlZMemBuffExtend: %s\n%s %d bytes.\n",
1645 "Buffer overwrite detected during compressed memory",
1646 "buffer extension. Overflowed by",
1647 (cur_used - new_size ) );
1648 #endif
1650 tmp_ptr = xmlRealloc( buff->zbuff, new_size );
1651 if ( tmp_ptr != NULL ) {
1652 rc = 0;
1653 buff->size = new_size;
1654 buff->zbuff = tmp_ptr;
1655 buff->zctrl.next_out = tmp_ptr + cur_used;
1656 buff->zctrl.avail_out = new_size - cur_used;
1658 else {
1659 xmlChar msg[500];
1660 xmlStrPrintf(msg, 500,
1661 (const xmlChar *) "xmlZMemBuffExtend: %s %lu bytes.\n",
1662 "Allocation failure extending output buffer to",
1663 new_size );
1664 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1667 return ( rc );
1671 * xmlZMemBuffAppend
1672 * @buff: Buffer used to compress and consolidate data
1673 * @src: Uncompressed source content to append to buffer
1674 * @len: Length of source data to append to buffer
1676 * Compress and append data to the internal buffer. The data buffer
1677 * will be expanded if needed to store the additional data.
1679 * Returns the number of bytes appended to the buffer or -1 on error.
1681 static int
1682 xmlZMemBuffAppend( xmlZMemBuffPtr buff, const char * src, int len ) {
1684 int z_err;
1685 size_t min_accept;
1687 if ( ( buff == NULL ) || ( src == NULL ) )
1688 return ( -1 );
1690 buff->zctrl.avail_in = len;
1691 buff->zctrl.next_in = (unsigned char *)src;
1692 while ( buff->zctrl.avail_in > 0 ) {
1694 ** Extend the buffer prior to deflate call if a reasonable amount
1695 ** of output buffer space is not available.
1697 min_accept = buff->zctrl.avail_in / DFLT_ZLIB_RATIO;
1698 if ( buff->zctrl.avail_out <= min_accept ) {
1699 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1700 return ( -1 );
1703 z_err = deflate( &buff->zctrl, Z_NO_FLUSH );
1704 if ( z_err != Z_OK ) {
1705 xmlChar msg[500];
1706 xmlStrPrintf(msg, 500,
1707 (const xmlChar *) "xmlZMemBuffAppend: %s %d %s - %d",
1708 "Compression error while appending",
1709 len, "bytes to buffer. ZLIB error", z_err );
1710 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1711 return ( -1 );
1715 buff->crc = crc32( buff->crc, (unsigned char *)src, len );
1717 return ( len );
1721 * xmlZMemBuffGetContent
1722 * @buff: Compressed memory content buffer
1723 * @data_ref: Pointer reference to point to compressed content
1725 * Flushes the compression buffers, appends gzip file trailers and
1726 * returns the compressed content and length of the compressed data.
1727 * NOTE: The gzip trailer code here is plagiarized from zlib source.
1729 * Returns the length of the compressed data or -1 on error.
1731 static int
1732 xmlZMemBuffGetContent( xmlZMemBuffPtr buff, char ** data_ref ) {
1734 int zlgth = -1;
1735 int z_err;
1737 if ( ( buff == NULL ) || ( data_ref == NULL ) )
1738 return ( -1 );
1740 /* Need to loop until compression output buffers are flushed */
1744 z_err = deflate( &buff->zctrl, Z_FINISH );
1745 if ( z_err == Z_OK ) {
1746 /* In this case Z_OK means more buffer space needed */
1748 if ( xmlZMemBuffExtend( buff, buff->size ) == -1 )
1749 return ( -1 );
1752 while ( z_err == Z_OK );
1754 /* If the compression state is not Z_STREAM_END, some error occurred */
1756 if ( z_err == Z_STREAM_END ) {
1758 /* Need to append the gzip data trailer */
1760 if ( buff->zctrl.avail_out < ( 2 * sizeof( unsigned long ) ) ) {
1761 if ( xmlZMemBuffExtend(buff, (2 * sizeof(unsigned long))) == -1 )
1762 return ( -1 );
1766 ** For whatever reason, the CRC and length data are pushed out
1767 ** in reverse byte order. So a memcpy can't be used here.
1770 append_reverse_ulong( buff, buff->crc );
1771 append_reverse_ulong( buff, buff->zctrl.total_in );
1773 zlgth = buff->zctrl.next_out - buff->zbuff;
1774 *data_ref = (char *)buff->zbuff;
1777 else {
1778 xmlChar msg[500];
1779 xmlStrPrintf(msg, 500,
1780 (const xmlChar *) "xmlZMemBuffGetContent: %s - %d\n",
1781 "Error flushing zlib buffers. Error code", z_err );
1782 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1785 return ( zlgth );
1787 #endif /* LIBXML_OUTPUT_ENABLED */
1788 #endif /* HAVE_ZLIB_H */
1790 #ifdef LIBXML_OUTPUT_ENABLED
1792 * xmlFreeHTTPWriteCtxt
1793 * @ctxt: Context to cleanup
1795 * Free allocated memory and reclaim system resources.
1797 * No return value.
1799 static void
1800 xmlFreeHTTPWriteCtxt( xmlIOHTTPWriteCtxtPtr ctxt )
1802 if ( ctxt->uri != NULL )
1803 xmlFree( ctxt->uri );
1805 if ( ctxt->doc_buff != NULL ) {
1807 #ifdef HAVE_ZLIB_H
1808 if ( ctxt->compression > 0 ) {
1809 xmlFreeZMemBuff( ctxt->doc_buff );
1811 else
1812 #endif
1814 xmlOutputBufferClose( ctxt->doc_buff );
1818 xmlFree( ctxt );
1819 return;
1821 #endif /* LIBXML_OUTPUT_ENABLED */
1825 * xmlIOHTTPMatch:
1826 * @filename: the URI for matching
1828 * check if the URI matches an HTTP one
1830 * Returns 1 if matches, 0 otherwise
1833 xmlIOHTTPMatch (const char *filename) {
1834 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "http://", 7))
1835 return(1);
1836 return(0);
1840 * xmlIOHTTPOpen:
1841 * @filename: the URI for matching
1843 * open an HTTP I/O channel
1845 * Returns an I/O context or NULL in case of error
1847 void *
1848 xmlIOHTTPOpen (const char *filename) {
1849 return(xmlNanoHTTPOpen(filename, NULL));
1852 #ifdef LIBXML_OUTPUT_ENABLED
1854 * xmlIOHTTPOpenW:
1855 * @post_uri: The destination URI for the document
1856 * @compression: The compression desired for the document.
1858 * Open a temporary buffer to collect the document for a subsequent HTTP POST
1859 * request. Non-static as is called from the output buffer creation routine.
1861 * Returns an I/O context or NULL in case of error.
1864 void *
1865 xmlIOHTTPOpenW(const char *post_uri, int compression)
1868 xmlIOHTTPWriteCtxtPtr ctxt = NULL;
1870 if (post_uri == NULL)
1871 return (NULL);
1873 ctxt = xmlMalloc(sizeof(xmlIOHTTPWriteCtxt));
1874 if (ctxt == NULL) {
1875 xmlIOErrMemory("creating HTTP output context");
1876 return (NULL);
1879 (void) memset(ctxt, 0, sizeof(xmlIOHTTPWriteCtxt));
1881 ctxt->uri = (char *) xmlStrdup((const xmlChar *)post_uri);
1882 if (ctxt->uri == NULL) {
1883 xmlIOErrMemory("copying URI");
1884 xmlFreeHTTPWriteCtxt(ctxt);
1885 return (NULL);
1889 * ** Since the document length is required for an HTTP post,
1890 * ** need to put the document into a buffer. A memory buffer
1891 * ** is being used to avoid pushing the data to disk and back.
1894 #ifdef HAVE_ZLIB_H
1895 if ((compression > 0) && (compression <= 9)) {
1897 ctxt->compression = compression;
1898 ctxt->doc_buff = xmlCreateZMemBuff(compression);
1899 } else
1900 #endif
1902 /* Any character conversions should have been done before this */
1904 ctxt->doc_buff = xmlAllocOutputBufferInternal(NULL);
1907 if (ctxt->doc_buff == NULL) {
1908 xmlFreeHTTPWriteCtxt(ctxt);
1909 ctxt = NULL;
1912 return (ctxt);
1914 #endif /* LIBXML_OUTPUT_ENABLED */
1916 #ifdef LIBXML_OUTPUT_ENABLED
1918 * xmlIOHTTPDfltOpenW
1919 * @post_uri: The destination URI for this document.
1921 * Calls xmlIOHTTPOpenW with no compression to set up for a subsequent
1922 * HTTP post command. This function should generally not be used as
1923 * the open callback is short circuited in xmlOutputBufferCreateFile.
1925 * Returns a pointer to the new IO context.
1927 static void *
1928 xmlIOHTTPDfltOpenW( const char * post_uri ) {
1929 return ( xmlIOHTTPOpenW( post_uri, 0 ) );
1931 #endif /* LIBXML_OUTPUT_ENABLED */
1934 * xmlIOHTTPRead:
1935 * @context: the I/O context
1936 * @buffer: where to drop data
1937 * @len: number of bytes to write
1939 * Read @len bytes to @buffer from the I/O channel.
1941 * Returns the number of bytes written
1944 xmlIOHTTPRead(void * context, char * buffer, int len) {
1945 if ((buffer == NULL) || (len < 0)) return(-1);
1946 return(xmlNanoHTTPRead(context, &buffer[0], len));
1949 #ifdef LIBXML_OUTPUT_ENABLED
1951 * xmlIOHTTPWrite
1952 * @context: previously opened writing context
1953 * @buffer: data to output to temporary buffer
1954 * @len: bytes to output
1956 * Collect data from memory buffer into a temporary file for later
1957 * processing.
1959 * Returns number of bytes written.
1962 static int
1963 xmlIOHTTPWrite( void * context, const char * buffer, int len ) {
1965 xmlIOHTTPWriteCtxtPtr ctxt = context;
1967 if ( ( ctxt == NULL ) || ( ctxt->doc_buff == NULL ) || ( buffer == NULL ) )
1968 return ( -1 );
1970 if ( len > 0 ) {
1972 /* Use gzwrite or fwrite as previously setup in the open call */
1974 #ifdef HAVE_ZLIB_H
1975 if ( ctxt->compression > 0 )
1976 len = xmlZMemBuffAppend( ctxt->doc_buff, buffer, len );
1978 else
1979 #endif
1980 len = xmlOutputBufferWrite( ctxt->doc_buff, len, buffer );
1982 if ( len < 0 ) {
1983 xmlChar msg[500];
1984 xmlStrPrintf(msg, 500,
1985 (const xmlChar *) "xmlIOHTTPWrite: %s\n%s '%s'.\n",
1986 "Error appending to internal buffer.",
1987 "Error sending document to URI",
1988 ctxt->uri );
1989 xmlIOErr(XML_IO_WRITE, (const char *) msg);
1993 return ( len );
1995 #endif /* LIBXML_OUTPUT_ENABLED */
1999 * xmlIOHTTPClose:
2000 * @context: the I/O context
2002 * Close an HTTP I/O channel
2004 * Returns 0
2007 xmlIOHTTPClose (void * context) {
2008 xmlNanoHTTPClose(context);
2009 return 0;
2012 #ifdef LIBXML_OUTPUT_ENABLED
2014 * xmlIOHTTCloseWrite
2015 * @context: The I/O context
2016 * @http_mthd: The HTTP method to be used when sending the data
2018 * Close the transmit HTTP I/O channel and actually send the data.
2020 static int
2021 xmlIOHTTPCloseWrite( void * context, const char * http_mthd ) {
2023 int close_rc = -1;
2024 int http_rtn = 0;
2025 int content_lgth = 0;
2026 xmlIOHTTPWriteCtxtPtr ctxt = context;
2028 char * http_content = NULL;
2029 char * content_encoding = NULL;
2030 char * content_type = (char *) "text/xml";
2031 void * http_ctxt = NULL;
2033 if ( ( ctxt == NULL ) || ( http_mthd == NULL ) )
2034 return ( -1 );
2036 /* Retrieve the content from the appropriate buffer */
2038 #ifdef HAVE_ZLIB_H
2040 if ( ctxt->compression > 0 ) {
2041 content_lgth = xmlZMemBuffGetContent( ctxt->doc_buff, &http_content );
2042 content_encoding = (char *) "Content-Encoding: gzip";
2044 else
2045 #endif
2047 /* Pull the data out of the memory output buffer */
2049 xmlOutputBufferPtr dctxt = ctxt->doc_buff;
2050 http_content = (char *) xmlBufContent(dctxt->buffer);
2051 content_lgth = xmlBufUse(dctxt->buffer);
2054 if ( http_content == NULL ) {
2055 xmlChar msg[500];
2056 xmlStrPrintf(msg, 500,
2057 (const xmlChar *) "xmlIOHTTPCloseWrite: %s '%s' %s '%s'.\n",
2058 "Error retrieving content.\nUnable to",
2059 http_mthd, "data to URI", ctxt->uri );
2060 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2063 else {
2065 http_ctxt = xmlNanoHTTPMethod( ctxt->uri, http_mthd, http_content,
2066 &content_type, content_encoding,
2067 content_lgth );
2069 if ( http_ctxt != NULL ) {
2070 #ifdef DEBUG_HTTP
2071 /* If testing/debugging - dump reply with request content */
2073 FILE * tst_file = NULL;
2074 char buffer[ 4096 ];
2075 char * dump_name = NULL;
2076 int avail;
2078 xmlGenericError( xmlGenericErrorContext,
2079 "xmlNanoHTTPCloseWrite: HTTP %s to\n%s returned %d.\n",
2080 http_mthd, ctxt->uri,
2081 xmlNanoHTTPReturnCode( http_ctxt ) );
2084 ** Since either content or reply may be gzipped,
2085 ** dump them to separate files instead of the
2086 ** standard error context.
2089 dump_name = tempnam( NULL, "lxml" );
2090 if ( dump_name != NULL ) {
2091 (void)snprintf( buffer, sizeof(buffer), "%s.content", dump_name );
2093 tst_file = fopen( buffer, "wb" );
2094 if ( tst_file != NULL ) {
2095 xmlGenericError( xmlGenericErrorContext,
2096 "Transmitted content saved in file: %s\n", buffer );
2098 fwrite( http_content, sizeof( char ),
2099 content_lgth, tst_file );
2100 fclose( tst_file );
2103 (void)snprintf( buffer, sizeof(buffer), "%s.reply", dump_name );
2104 tst_file = fopen( buffer, "wb" );
2105 if ( tst_file != NULL ) {
2106 xmlGenericError( xmlGenericErrorContext,
2107 "Reply content saved in file: %s\n", buffer );
2110 while ( (avail = xmlNanoHTTPRead( http_ctxt,
2111 buffer, sizeof( buffer ) )) > 0 ) {
2113 fwrite( buffer, sizeof( char ), avail, tst_file );
2116 fclose( tst_file );
2119 free( dump_name );
2121 #endif /* DEBUG_HTTP */
2123 http_rtn = xmlNanoHTTPReturnCode( http_ctxt );
2124 if ( ( http_rtn >= 200 ) && ( http_rtn < 300 ) )
2125 close_rc = 0;
2126 else {
2127 xmlChar msg[500];
2128 xmlStrPrintf(msg, 500,
2129 (const xmlChar *) "xmlIOHTTPCloseWrite: HTTP '%s' of %d %s\n'%s' %s %d\n",
2130 http_mthd, content_lgth,
2131 "bytes to URI", ctxt->uri,
2132 "failed. HTTP return code:", http_rtn );
2133 xmlIOErr(XML_IO_WRITE, (const char *) msg);
2136 xmlNanoHTTPClose( http_ctxt );
2137 xmlFree( content_type );
2141 /* Final cleanups */
2143 xmlFreeHTTPWriteCtxt( ctxt );
2145 return ( close_rc );
2149 * xmlIOHTTPClosePut
2151 * @context: The I/O context
2153 * Close the transmit HTTP I/O channel and actually send data using a PUT
2154 * HTTP method.
2156 static int
2157 xmlIOHTTPClosePut( void * ctxt ) {
2158 return ( xmlIOHTTPCloseWrite( ctxt, "PUT" ) );
2163 * xmlIOHTTPClosePost
2165 * @context: The I/O context
2167 * Close the transmit HTTP I/O channel and actually send data using a POST
2168 * HTTP method.
2170 static int
2171 xmlIOHTTPClosePost( void * ctxt ) {
2172 return ( xmlIOHTTPCloseWrite( ctxt, "POST" ) );
2174 #endif /* LIBXML_OUTPUT_ENABLED */
2176 #endif /* LIBXML_HTTP_ENABLED */
2178 #ifdef LIBXML_FTP_ENABLED
2179 /************************************************************************
2181 * I/O for FTP file accesses *
2183 ************************************************************************/
2185 * xmlIOFTPMatch:
2186 * @filename: the URI for matching
2188 * check if the URI matches an FTP one
2190 * Returns 1 if matches, 0 otherwise
2193 xmlIOFTPMatch (const char *filename) {
2194 if (!xmlStrncasecmp(BAD_CAST filename, BAD_CAST "ftp://", 6))
2195 return(1);
2196 return(0);
2200 * xmlIOFTPOpen:
2201 * @filename: the URI for matching
2203 * open an FTP I/O channel
2205 * Returns an I/O context or NULL in case of error
2207 void *
2208 xmlIOFTPOpen (const char *filename) {
2209 return(xmlNanoFTPOpen(filename));
2213 * xmlIOFTPRead:
2214 * @context: the I/O context
2215 * @buffer: where to drop data
2216 * @len: number of bytes to write
2218 * Read @len bytes to @buffer from the I/O channel.
2220 * Returns the number of bytes written
2223 xmlIOFTPRead(void * context, char * buffer, int len) {
2224 if ((buffer == NULL) || (len < 0)) return(-1);
2225 return(xmlNanoFTPRead(context, &buffer[0], len));
2229 * xmlIOFTPClose:
2230 * @context: the I/O context
2232 * Close an FTP I/O channel
2234 * Returns 0
2237 xmlIOFTPClose (void * context) {
2238 return ( xmlNanoFTPClose(context) );
2240 #endif /* LIBXML_FTP_ENABLED */
2244 * xmlRegisterInputCallbacks:
2245 * @matchFunc: the xmlInputMatchCallback
2246 * @openFunc: the xmlInputOpenCallback
2247 * @readFunc: the xmlInputReadCallback
2248 * @closeFunc: the xmlInputCloseCallback
2250 * Register a new set of I/O callback for handling parser input.
2252 * Returns the registered handler number or -1 in case of error
2255 xmlRegisterInputCallbacks(xmlInputMatchCallback matchFunc,
2256 xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc,
2257 xmlInputCloseCallback closeFunc) {
2258 if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
2259 return(-1);
2261 xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = matchFunc;
2262 xmlInputCallbackTable[xmlInputCallbackNr].opencallback = openFunc;
2263 xmlInputCallbackTable[xmlInputCallbackNr].readcallback = readFunc;
2264 xmlInputCallbackTable[xmlInputCallbackNr].closecallback = closeFunc;
2265 xmlInputCallbackInitialized = 1;
2266 return(xmlInputCallbackNr++);
2269 #ifdef LIBXML_OUTPUT_ENABLED
2271 * xmlRegisterOutputCallbacks:
2272 * @matchFunc: the xmlOutputMatchCallback
2273 * @openFunc: the xmlOutputOpenCallback
2274 * @writeFunc: the xmlOutputWriteCallback
2275 * @closeFunc: the xmlOutputCloseCallback
2277 * Register a new set of I/O callback for handling output.
2279 * Returns the registered handler number or -1 in case of error
2282 xmlRegisterOutputCallbacks(xmlOutputMatchCallback matchFunc,
2283 xmlOutputOpenCallback openFunc, xmlOutputWriteCallback writeFunc,
2284 xmlOutputCloseCallback closeFunc) {
2285 if (xmlOutputCallbackNr >= MAX_OUTPUT_CALLBACK) {
2286 return(-1);
2288 xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = matchFunc;
2289 xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = openFunc;
2290 xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = writeFunc;
2291 xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = closeFunc;
2292 xmlOutputCallbackInitialized = 1;
2293 return(xmlOutputCallbackNr++);
2295 #endif /* LIBXML_OUTPUT_ENABLED */
2298 * xmlRegisterDefaultInputCallbacks:
2300 * Registers the default compiled-in I/O handlers.
2302 void
2303 xmlRegisterDefaultInputCallbacks(void) {
2304 if (xmlInputCallbackInitialized)
2305 return;
2307 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2308 xmlInitPlatformSpecificIo();
2309 #endif
2311 xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
2312 xmlFileRead, xmlFileClose);
2313 #ifdef HAVE_ZLIB_H
2314 xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2315 xmlGzfileRead, xmlGzfileClose);
2316 #endif /* HAVE_ZLIB_H */
2317 #ifdef HAVE_LZMA_H
2318 xmlRegisterInputCallbacks(xmlXzfileMatch, xmlXzfileOpen,
2319 xmlXzfileRead, xmlXzfileClose);
2320 #endif /* HAVE_ZLIB_H */
2322 #ifdef LIBXML_HTTP_ENABLED
2323 xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
2324 xmlIOHTTPRead, xmlIOHTTPClose);
2325 #endif /* LIBXML_HTTP_ENABLED */
2327 #ifdef LIBXML_FTP_ENABLED
2328 xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2329 xmlIOFTPRead, xmlIOFTPClose);
2330 #endif /* LIBXML_FTP_ENABLED */
2331 xmlInputCallbackInitialized = 1;
2334 #ifdef LIBXML_OUTPUT_ENABLED
2336 * xmlRegisterDefaultOutputCallbacks:
2338 * Registers the default compiled-in I/O handlers.
2340 void
2341 xmlRegisterDefaultOutputCallbacks (void) {
2342 if (xmlOutputCallbackInitialized)
2343 return;
2345 #if defined(_WIN32) || defined (__DJGPP__) && !defined (__CYGWIN__)
2346 xmlInitPlatformSpecificIo();
2347 #endif
2349 xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
2350 xmlFileWrite, xmlFileClose);
2352 #ifdef LIBXML_HTTP_ENABLED
2353 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2354 xmlIOHTTPWrite, xmlIOHTTPClosePut);
2355 #endif
2357 /*********************************
2358 No way a-priori to distinguish between gzipped files from
2359 uncompressed ones except opening if existing then closing
2360 and saving with same compression ratio ... a pain.
2362 #ifdef HAVE_ZLIB_H
2363 xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
2364 xmlGzfileWrite, xmlGzfileClose);
2365 #endif
2367 Nor FTP PUT ....
2368 #ifdef LIBXML_FTP_ENABLED
2369 xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
2370 xmlIOFTPWrite, xmlIOFTPClose);
2371 #endif
2372 **********************************/
2373 xmlOutputCallbackInitialized = 1;
2376 #ifdef LIBXML_HTTP_ENABLED
2378 * xmlRegisterHTTPPostCallbacks:
2380 * By default, libxml submits HTTP output requests using the "PUT" method.
2381 * Calling this method changes the HTTP output method to use the "POST"
2382 * method instead.
2385 void
2386 xmlRegisterHTTPPostCallbacks( void ) {
2388 /* Register defaults if not done previously */
2390 if ( xmlOutputCallbackInitialized == 0 )
2391 xmlRegisterDefaultOutputCallbacks( );
2393 xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPDfltOpenW,
2394 xmlIOHTTPWrite, xmlIOHTTPClosePost);
2395 return;
2397 #endif
2398 #endif /* LIBXML_OUTPUT_ENABLED */
2401 * xmlAllocParserInputBuffer:
2402 * @enc: the charset encoding if known
2404 * Create a buffered parser input for progressive parsing
2406 * Returns the new parser input or NULL
2408 xmlParserInputBufferPtr
2409 xmlAllocParserInputBuffer(xmlCharEncoding enc) {
2410 xmlParserInputBufferPtr ret;
2412 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
2413 if (ret == NULL) {
2414 xmlIOErrMemory("creating input buffer");
2415 return(NULL);
2417 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
2418 ret->buffer = xmlBufCreateSize(2 * xmlDefaultBufferSize);
2419 if (ret->buffer == NULL) {
2420 xmlFree(ret);
2421 return(NULL);
2423 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
2424 ret->encoder = xmlGetCharEncodingHandler(enc);
2425 if (ret->encoder != NULL)
2426 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
2427 else
2428 ret->raw = NULL;
2429 ret->readcallback = NULL;
2430 ret->closecallback = NULL;
2431 ret->context = NULL;
2432 ret->compressed = -1;
2433 ret->rawconsumed = 0;
2435 return(ret);
2438 #ifdef LIBXML_OUTPUT_ENABLED
2440 * xmlAllocOutputBuffer:
2441 * @encoder: the encoding converter or NULL
2443 * Create a buffered parser output
2445 * Returns the new parser output or NULL
2447 xmlOutputBufferPtr
2448 xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
2449 xmlOutputBufferPtr ret;
2451 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2452 if (ret == NULL) {
2453 xmlIOErrMemory("creating output buffer");
2454 return(NULL);
2456 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2457 ret->buffer = xmlBufCreate();
2458 if (ret->buffer == NULL) {
2459 xmlFree(ret);
2460 return(NULL);
2463 /* try to avoid a performance problem with Windows realloc() */
2464 if (xmlBufGetAllocationScheme(ret->buffer) == XML_BUFFER_ALLOC_EXACT)
2465 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_DOUBLEIT);
2467 ret->encoder = encoder;
2468 if (encoder != NULL) {
2469 ret->conv = xmlBufCreateSize(4000);
2470 if (ret->conv == NULL) {
2471 xmlFree(ret);
2472 return(NULL);
2476 * This call is designed to initiate the encoder state
2478 xmlCharEncOutput(ret, 1);
2479 } else
2480 ret->conv = NULL;
2481 ret->writecallback = NULL;
2482 ret->closecallback = NULL;
2483 ret->context = NULL;
2484 ret->written = 0;
2486 return(ret);
2490 * xmlAllocOutputBufferInternal:
2491 * @encoder: the encoding converter or NULL
2493 * Create a buffered parser output
2495 * Returns the new parser output or NULL
2497 xmlOutputBufferPtr
2498 xmlAllocOutputBufferInternal(xmlCharEncodingHandlerPtr encoder) {
2499 xmlOutputBufferPtr ret;
2501 ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
2502 if (ret == NULL) {
2503 xmlIOErrMemory("creating output buffer");
2504 return(NULL);
2506 memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
2507 ret->buffer = xmlBufCreate();
2508 if (ret->buffer == NULL) {
2509 xmlFree(ret);
2510 return(NULL);
2515 * For conversion buffers we use the special IO handling
2517 xmlBufSetAllocationScheme(ret->buffer, XML_BUFFER_ALLOC_IO);
2519 ret->encoder = encoder;
2520 if (encoder != NULL) {
2521 ret->conv = xmlBufCreateSize(4000);
2522 if (ret->conv == NULL) {
2523 xmlFree(ret);
2524 return(NULL);
2528 * This call is designed to initiate the encoder state
2530 xmlCharEncOutput(ret, 1);
2531 } else
2532 ret->conv = NULL;
2533 ret->writecallback = NULL;
2534 ret->closecallback = NULL;
2535 ret->context = NULL;
2536 ret->written = 0;
2538 return(ret);
2541 #endif /* LIBXML_OUTPUT_ENABLED */
2544 * xmlFreeParserInputBuffer:
2545 * @in: a buffered parser input
2547 * Free up the memory used by a buffered parser input
2549 void
2550 xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
2551 if (in == NULL) return;
2553 if (in->raw) {
2554 xmlBufFree(in->raw);
2555 in->raw = NULL;
2557 if (in->encoder != NULL) {
2558 xmlCharEncCloseFunc(in->encoder);
2560 if (in->closecallback != NULL) {
2561 in->closecallback(in->context);
2563 if (in->buffer != NULL) {
2564 xmlBufFree(in->buffer);
2565 in->buffer = NULL;
2568 xmlFree(in);
2571 #ifdef LIBXML_OUTPUT_ENABLED
2573 * xmlOutputBufferClose:
2574 * @out: a buffered output
2576 * flushes and close the output I/O channel
2577 * and free up all the associated resources
2579 * Returns the number of byte written or -1 in case of error.
2582 xmlOutputBufferClose(xmlOutputBufferPtr out)
2584 int written;
2585 int err_rc = 0;
2587 if (out == NULL)
2588 return (-1);
2589 if (out->writecallback != NULL)
2590 xmlOutputBufferFlush(out);
2591 if (out->closecallback != NULL) {
2592 err_rc = out->closecallback(out->context);
2594 written = out->written;
2595 if (out->conv) {
2596 xmlBufFree(out->conv);
2597 out->conv = NULL;
2599 if (out->encoder != NULL) {
2600 xmlCharEncCloseFunc(out->encoder);
2602 if (out->buffer != NULL) {
2603 xmlBufFree(out->buffer);
2604 out->buffer = NULL;
2607 if (out->error)
2608 err_rc = -1;
2609 xmlFree(out);
2610 return ((err_rc == 0) ? written : err_rc);
2612 #endif /* LIBXML_OUTPUT_ENABLED */
2614 xmlParserInputBufferPtr
2615 __xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2616 xmlParserInputBufferPtr ret;
2617 int i = 0;
2618 void *context = NULL;
2620 if (xmlInputCallbackInitialized == 0)
2621 xmlRegisterDefaultInputCallbacks();
2623 if (URI == NULL) return(NULL);
2626 * Try to find one of the input accept method accepting that scheme
2627 * Go in reverse to give precedence to user defined handlers.
2629 if (context == NULL) {
2630 for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
2631 if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
2632 (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
2633 context = xmlInputCallbackTable[i].opencallback(URI);
2634 if (context != NULL) {
2635 break;
2640 if (context == NULL) {
2641 return(NULL);
2645 * Allocate the Input buffer front-end.
2647 ret = xmlAllocParserInputBuffer(enc);
2648 if (ret != NULL) {
2649 ret->context = context;
2650 ret->readcallback = xmlInputCallbackTable[i].readcallback;
2651 ret->closecallback = xmlInputCallbackTable[i].closecallback;
2652 #ifdef HAVE_ZLIB_H
2653 if ((xmlInputCallbackTable[i].opencallback == xmlGzfileOpen) &&
2654 (strcmp(URI, "-") != 0)) {
2655 #if defined(ZLIB_VERNUM) && ZLIB_VERNUM >= 0x1230
2656 ret->compressed = !gzdirect(context);
2657 #else
2658 if (((z_stream *)context)->avail_in > 4) {
2659 char *cptr, buff4[4];
2660 cptr = (char *) ((z_stream *)context)->next_in;
2661 if (gzread(context, buff4, 4) == 4) {
2662 if (strncmp(buff4, cptr, 4) == 0)
2663 ret->compressed = 0;
2664 else
2665 ret->compressed = 1;
2666 gzrewind(context);
2669 #endif
2671 #endif
2673 else
2674 xmlInputCallbackTable[i].closecallback (context);
2676 return(ret);
2680 * xmlParserInputBufferCreateFilename:
2681 * @URI: a C string containing the URI or filename
2682 * @enc: the charset encoding if known
2684 * Create a buffered parser input for the progressive parsing of a file
2685 * If filename is "-' then we use stdin as the input.
2686 * Automatic support for ZLIB/Compress compressed document is provided
2687 * by default if found at compile-time.
2688 * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
2690 * Returns the new parser input or NULL
2692 xmlParserInputBufferPtr
2693 xmlParserInputBufferCreateFilename(const char *URI, xmlCharEncoding enc) {
2694 if ((xmlParserInputBufferCreateFilenameValue)) {
2695 return xmlParserInputBufferCreateFilenameValue(URI, enc);
2697 return __xmlParserInputBufferCreateFilename(URI, enc);
2700 #ifdef LIBXML_OUTPUT_ENABLED
2701 xmlOutputBufferPtr
2702 __xmlOutputBufferCreateFilename(const char *URI,
2703 xmlCharEncodingHandlerPtr encoder,
2704 int compression ATTRIBUTE_UNUSED) {
2705 xmlOutputBufferPtr ret;
2706 xmlURIPtr puri;
2707 int i = 0;
2708 void *context = NULL;
2709 char *unescaped = NULL;
2710 #ifdef HAVE_ZLIB_H
2711 int is_file_uri = 1;
2712 #endif
2714 if (xmlOutputCallbackInitialized == 0)
2715 xmlRegisterDefaultOutputCallbacks();
2717 if (URI == NULL) return(NULL);
2719 puri = xmlParseURI(URI);
2720 if (puri != NULL) {
2721 #ifdef HAVE_ZLIB_H
2722 if ((puri->scheme != NULL) &&
2723 (!xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
2724 is_file_uri = 0;
2725 #endif
2727 * try to limit the damages of the URI unescaping code.
2729 if ((puri->scheme == NULL) ||
2730 (xmlStrEqual(BAD_CAST puri->scheme, BAD_CAST "file")))
2731 unescaped = xmlURIUnescapeString(URI, 0, NULL);
2732 xmlFreeURI(puri);
2736 * Try to find one of the output accept method accepting that scheme
2737 * Go in reverse to give precedence to user defined handlers.
2738 * try with an unescaped version of the URI
2740 if (unescaped != NULL) {
2741 #ifdef HAVE_ZLIB_H
2742 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
2743 context = xmlGzfileOpenW(unescaped, compression);
2744 if (context != NULL) {
2745 ret = xmlAllocOutputBufferInternal(encoder);
2746 if (ret != NULL) {
2747 ret->context = context;
2748 ret->writecallback = xmlGzfileWrite;
2749 ret->closecallback = xmlGzfileClose;
2751 xmlFree(unescaped);
2752 return(ret);
2755 #endif
2756 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2757 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2758 (xmlOutputCallbackTable[i].matchcallback(unescaped) != 0)) {
2759 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2760 /* Need to pass compression parameter into HTTP open calls */
2761 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2762 context = xmlIOHTTPOpenW(unescaped, compression);
2763 else
2764 #endif
2765 context = xmlOutputCallbackTable[i].opencallback(unescaped);
2766 if (context != NULL)
2767 break;
2770 xmlFree(unescaped);
2774 * If this failed try with a non-escaped URI this may be a strange
2775 * filename
2777 if (context == NULL) {
2778 #ifdef HAVE_ZLIB_H
2779 if ((compression > 0) && (compression <= 9) && (is_file_uri == 1)) {
2780 context = xmlGzfileOpenW(URI, compression);
2781 if (context != NULL) {
2782 ret = xmlAllocOutputBufferInternal(encoder);
2783 if (ret != NULL) {
2784 ret->context = context;
2785 ret->writecallback = xmlGzfileWrite;
2786 ret->closecallback = xmlGzfileClose;
2788 return(ret);
2791 #endif
2792 for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
2793 if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
2794 (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
2795 #if defined(LIBXML_HTTP_ENABLED) && defined(HAVE_ZLIB_H)
2796 /* Need to pass compression parameter into HTTP open calls */
2797 if (xmlOutputCallbackTable[i].matchcallback == xmlIOHTTPMatch)
2798 context = xmlIOHTTPOpenW(URI, compression);
2799 else
2800 #endif
2801 context = xmlOutputCallbackTable[i].opencallback(URI);
2802 if (context != NULL)
2803 break;
2808 if (context == NULL) {
2809 return(NULL);
2813 * Allocate the Output buffer front-end.
2815 ret = xmlAllocOutputBufferInternal(encoder);
2816 if (ret != NULL) {
2817 ret->context = context;
2818 ret->writecallback = xmlOutputCallbackTable[i].writecallback;
2819 ret->closecallback = xmlOutputCallbackTable[i].closecallback;
2821 return(ret);
2825 * xmlOutputBufferCreateFilename:
2826 * @URI: a C string containing the URI or filename
2827 * @encoder: the encoding converter or NULL
2828 * @compression: the compression ration (0 none, 9 max).
2830 * Create a buffered output for the progressive saving of a file
2831 * If filename is "-' then we use stdout as the output.
2832 * Automatic support for ZLIB/Compress compressed document is provided
2833 * by default if found at compile-time.
2834 * TODO: currently if compression is set, the library only support
2835 * writing to a local file.
2837 * Returns the new output or NULL
2839 xmlOutputBufferPtr
2840 xmlOutputBufferCreateFilename(const char *URI,
2841 xmlCharEncodingHandlerPtr encoder,
2842 int compression ATTRIBUTE_UNUSED) {
2843 if ((xmlOutputBufferCreateFilenameValue)) {
2844 return xmlOutputBufferCreateFilenameValue(URI, encoder, compression);
2846 return __xmlOutputBufferCreateFilename(URI, encoder, compression);
2848 #endif /* LIBXML_OUTPUT_ENABLED */
2851 * xmlParserInputBufferCreateFile:
2852 * @file: a FILE*
2853 * @enc: the charset encoding if known
2855 * Create a buffered parser input for the progressive parsing of a FILE *
2856 * buffered C I/O
2858 * Returns the new parser input or NULL
2860 xmlParserInputBufferPtr
2861 xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
2862 xmlParserInputBufferPtr ret;
2864 if (xmlInputCallbackInitialized == 0)
2865 xmlRegisterDefaultInputCallbacks();
2867 if (file == NULL) return(NULL);
2869 ret = xmlAllocParserInputBuffer(enc);
2870 if (ret != NULL) {
2871 ret->context = file;
2872 ret->readcallback = xmlFileRead;
2873 ret->closecallback = xmlFileFlush;
2876 return(ret);
2879 #ifdef LIBXML_OUTPUT_ENABLED
2881 * xmlOutputBufferCreateFile:
2882 * @file: a FILE*
2883 * @encoder: the encoding converter or NULL
2885 * Create a buffered output for the progressive saving to a FILE *
2886 * buffered C I/O
2888 * Returns the new parser output or NULL
2890 xmlOutputBufferPtr
2891 xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
2892 xmlOutputBufferPtr ret;
2894 if (xmlOutputCallbackInitialized == 0)
2895 xmlRegisterDefaultOutputCallbacks();
2897 if (file == NULL) return(NULL);
2899 ret = xmlAllocOutputBufferInternal(encoder);
2900 if (ret != NULL) {
2901 ret->context = file;
2902 ret->writecallback = xmlFileWrite;
2903 ret->closecallback = xmlFileFlush;
2906 return(ret);
2910 * xmlOutputBufferCreateBuffer:
2911 * @buffer: a xmlBufferPtr
2912 * @encoder: the encoding converter or NULL
2914 * Create a buffered output for the progressive saving to a xmlBuffer
2916 * Returns the new parser output or NULL
2918 xmlOutputBufferPtr
2919 xmlOutputBufferCreateBuffer(xmlBufferPtr buffer,
2920 xmlCharEncodingHandlerPtr encoder) {
2921 xmlOutputBufferPtr ret;
2923 if (buffer == NULL) return(NULL);
2925 ret = xmlOutputBufferCreateIO((xmlOutputWriteCallback)
2926 xmlBufferWrite,
2927 (xmlOutputCloseCallback)
2928 NULL, (void *) buffer, encoder);
2930 return(ret);
2934 * xmlOutputBufferGetContent:
2935 * @out: an xmlOutputBufferPtr
2937 * Gives a pointer to the data currently held in the output buffer
2939 * Returns a pointer to the data or NULL in case of error
2941 const xmlChar *
2942 xmlOutputBufferGetContent(xmlOutputBufferPtr out) {
2943 if ((out == NULL) || (out->buffer == NULL))
2944 return(NULL);
2946 return(xmlBufContent(out->buffer));
2950 * xmlOutputBufferGetSize:
2951 * @out: an xmlOutputBufferPtr
2953 * Gives the length of the data currently held in the output buffer
2955 * Returns 0 in case or error or no data is held, the size otherwise
2957 size_t
2958 xmlOutputBufferGetSize(xmlOutputBufferPtr out) {
2959 if ((out == NULL) || (out->buffer == NULL))
2960 return(0);
2962 return(xmlBufUse(out->buffer));
2966 #endif /* LIBXML_OUTPUT_ENABLED */
2969 * xmlParserInputBufferCreateFd:
2970 * @fd: a file descriptor number
2971 * @enc: the charset encoding if known
2973 * Create a buffered parser input for the progressive parsing for the input
2974 * from a file descriptor
2976 * Returns the new parser input or NULL
2978 xmlParserInputBufferPtr
2979 xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
2980 xmlParserInputBufferPtr ret;
2982 if (fd < 0) return(NULL);
2984 ret = xmlAllocParserInputBuffer(enc);
2985 if (ret != NULL) {
2986 ret->context = (void *) (long) fd;
2987 ret->readcallback = xmlFdRead;
2988 ret->closecallback = xmlFdClose;
2991 return(ret);
2995 * xmlParserInputBufferCreateMem:
2996 * @mem: the memory input
2997 * @size: the length of the memory block
2998 * @enc: the charset encoding if known
3000 * Create a buffered parser input for the progressive parsing for the input
3001 * from a memory area.
3003 * Returns the new parser input or NULL
3005 xmlParserInputBufferPtr
3006 xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
3007 xmlParserInputBufferPtr ret;
3008 int errcode;
3010 if (size <= 0) return(NULL);
3011 if (mem == NULL) return(NULL);
3013 ret = xmlAllocParserInputBuffer(enc);
3014 if (ret != NULL) {
3015 ret->context = (void *) mem;
3016 ret->readcallback = (xmlInputReadCallback) xmlNop;
3017 ret->closecallback = NULL;
3018 errcode = xmlBufAdd(ret->buffer, (const xmlChar *) mem, size);
3019 if (errcode != 0) {
3020 xmlFree(ret);
3021 return(NULL);
3025 return(ret);
3029 * xmlParserInputBufferCreateStatic:
3030 * @mem: the memory input
3031 * @size: the length of the memory block
3032 * @enc: the charset encoding if known
3034 * Create a buffered parser input for the progressive parsing for the input
3035 * from an immutable memory area. This will not copy the memory area to
3036 * the buffer, but the memory is expected to be available until the end of
3037 * the parsing, this is useful for example when using mmap'ed file.
3039 * Returns the new parser input or NULL
3041 xmlParserInputBufferPtr
3042 xmlParserInputBufferCreateStatic(const char *mem, int size,
3043 xmlCharEncoding enc) {
3044 xmlParserInputBufferPtr ret;
3046 if (size <= 0) return(NULL);
3047 if (mem == NULL) return(NULL);
3049 ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
3050 if (ret == NULL) {
3051 xmlIOErrMemory("creating input buffer");
3052 return(NULL);
3054 memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
3055 ret->buffer = xmlBufCreateStatic((void *)mem, (size_t) size);
3056 if (ret->buffer == NULL) {
3057 xmlFree(ret);
3058 return(NULL);
3060 ret->encoder = xmlGetCharEncodingHandler(enc);
3061 if (ret->encoder != NULL)
3062 ret->raw = xmlBufCreateSize(2 * xmlDefaultBufferSize);
3063 else
3064 ret->raw = NULL;
3065 ret->compressed = -1;
3066 ret->context = (void *) mem;
3067 ret->readcallback = NULL;
3068 ret->closecallback = NULL;
3070 return(ret);
3073 #ifdef LIBXML_OUTPUT_ENABLED
3075 * xmlOutputBufferCreateFd:
3076 * @fd: a file descriptor number
3077 * @encoder: the encoding converter or NULL
3079 * Create a buffered output for the progressive saving
3080 * to a file descriptor
3082 * Returns the new parser output or NULL
3084 xmlOutputBufferPtr
3085 xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
3086 xmlOutputBufferPtr ret;
3088 if (fd < 0) return(NULL);
3090 ret = xmlAllocOutputBufferInternal(encoder);
3091 if (ret != NULL) {
3092 ret->context = (void *) (long) fd;
3093 ret->writecallback = xmlFdWrite;
3094 ret->closecallback = NULL;
3097 return(ret);
3099 #endif /* LIBXML_OUTPUT_ENABLED */
3102 * xmlParserInputBufferCreateIO:
3103 * @ioread: an I/O read function
3104 * @ioclose: an I/O close function
3105 * @ioctx: an I/O handler
3106 * @enc: the charset encoding if known
3108 * Create a buffered parser input for the progressive parsing for the input
3109 * from an I/O handler
3111 * Returns the new parser input or NULL
3113 xmlParserInputBufferPtr
3114 xmlParserInputBufferCreateIO(xmlInputReadCallback ioread,
3115 xmlInputCloseCallback ioclose, void *ioctx, xmlCharEncoding enc) {
3116 xmlParserInputBufferPtr ret;
3118 if (ioread == NULL) return(NULL);
3120 ret = xmlAllocParserInputBuffer(enc);
3121 if (ret != NULL) {
3122 ret->context = (void *) ioctx;
3123 ret->readcallback = ioread;
3124 ret->closecallback = ioclose;
3127 return(ret);
3130 #ifdef LIBXML_OUTPUT_ENABLED
3132 * xmlOutputBufferCreateIO:
3133 * @iowrite: an I/O write function
3134 * @ioclose: an I/O close function
3135 * @ioctx: an I/O handler
3136 * @encoder: the charset encoding if known
3138 * Create a buffered output for the progressive saving
3139 * to an I/O handler
3141 * Returns the new parser output or NULL
3143 xmlOutputBufferPtr
3144 xmlOutputBufferCreateIO(xmlOutputWriteCallback iowrite,
3145 xmlOutputCloseCallback ioclose, void *ioctx,
3146 xmlCharEncodingHandlerPtr encoder) {
3147 xmlOutputBufferPtr ret;
3149 if (iowrite == NULL) return(NULL);
3151 ret = xmlAllocOutputBufferInternal(encoder);
3152 if (ret != NULL) {
3153 ret->context = (void *) ioctx;
3154 ret->writecallback = iowrite;
3155 ret->closecallback = ioclose;
3158 return(ret);
3160 #endif /* LIBXML_OUTPUT_ENABLED */
3163 * xmlParserInputBufferCreateFilenameDefault:
3164 * @func: function pointer to the new ParserInputBufferCreateFilenameFunc
3166 * Registers a callback for URI input file handling
3168 * Returns the old value of the registration function
3170 xmlParserInputBufferCreateFilenameFunc
3171 xmlParserInputBufferCreateFilenameDefault(xmlParserInputBufferCreateFilenameFunc func)
3173 xmlParserInputBufferCreateFilenameFunc old = xmlParserInputBufferCreateFilenameValue;
3174 if (old == NULL) {
3175 old = __xmlParserInputBufferCreateFilename;
3178 xmlParserInputBufferCreateFilenameValue = func;
3179 return(old);
3183 * xmlOutputBufferCreateFilenameDefault:
3184 * @func: function pointer to the new OutputBufferCreateFilenameFunc
3186 * Registers a callback for URI output file handling
3188 * Returns the old value of the registration function
3190 xmlOutputBufferCreateFilenameFunc
3191 xmlOutputBufferCreateFilenameDefault(xmlOutputBufferCreateFilenameFunc func)
3193 xmlOutputBufferCreateFilenameFunc old = xmlOutputBufferCreateFilenameValue;
3194 #ifdef LIBXML_OUTPUT_ENABLED
3195 if (old == NULL) {
3196 old = __xmlOutputBufferCreateFilename;
3198 #endif
3199 xmlOutputBufferCreateFilenameValue = func;
3200 return(old);
3204 * xmlParserInputBufferPush:
3205 * @in: a buffered parser input
3206 * @len: the size in bytes of the array.
3207 * @buf: an char array
3209 * Push the content of the arry in the input buffer
3210 * This routine handle the I18N transcoding to internal UTF-8
3211 * This is used when operating the parser in progressive (push) mode.
3213 * Returns the number of chars read and stored in the buffer, or -1
3214 * in case of error.
3217 xmlParserInputBufferPush(xmlParserInputBufferPtr in,
3218 int len, const char *buf) {
3219 int nbchars = 0;
3220 int ret;
3222 if (len < 0) return(0);
3223 if ((in == NULL) || (in->error)) return(-1);
3224 if (in->encoder != NULL) {
3225 unsigned int use;
3228 * Store the data in the incoming raw buffer
3230 if (in->raw == NULL) {
3231 in->raw = xmlBufCreate();
3233 ret = xmlBufAdd(in->raw, (const xmlChar *) buf, len);
3234 if (ret != 0)
3235 return(-1);
3238 * convert as much as possible to the parser reading buffer.
3240 use = xmlBufUse(in->raw);
3241 nbchars = xmlCharEncInput(in, 1);
3242 if (nbchars < 0) {
3243 xmlIOErr(XML_IO_ENCODER, NULL);
3244 in->error = XML_IO_ENCODER;
3245 return(-1);
3247 in->rawconsumed += (use - xmlBufUse(in->raw));
3248 } else {
3249 nbchars = len;
3250 ret = xmlBufAdd(in->buffer, (xmlChar *) buf, nbchars);
3251 if (ret != 0)
3252 return(-1);
3254 #ifdef DEBUG_INPUT
3255 xmlGenericError(xmlGenericErrorContext,
3256 "I/O: pushed %d chars, buffer %d/%d\n",
3257 nbchars, xmlBufUse(in->buffer), xmlBufLength(in->buffer));
3258 #endif
3259 return(nbchars);
3263 * endOfInput:
3265 * When reading from an Input channel indicated end of file or error
3266 * don't reread from it again.
3268 static int
3269 endOfInput (void * context ATTRIBUTE_UNUSED,
3270 char * buffer ATTRIBUTE_UNUSED,
3271 int len ATTRIBUTE_UNUSED) {
3272 return(0);
3276 * xmlParserInputBufferGrow:
3277 * @in: a buffered parser input
3278 * @len: indicative value of the amount of chars to read
3280 * Grow up the content of the input buffer, the old data are preserved
3281 * This routine handle the I18N transcoding to internal UTF-8
3282 * This routine is used when operating the parser in normal (pull) mode
3284 * TODO: one should be able to remove one extra copy by copying directly
3285 * onto in->buffer or in->raw
3287 * Returns the number of chars read and stored in the buffer, or -1
3288 * in case of error.
3291 xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
3292 char *buffer = NULL;
3293 int res = 0;
3294 int nbchars = 0;
3296 if ((in == NULL) || (in->error)) return(-1);
3297 if ((len <= MINLEN) && (len != 4))
3298 len = MINLEN;
3300 if (xmlBufAvail(in->buffer) <= 0) {
3301 xmlIOErr(XML_IO_BUFFER_FULL, NULL);
3302 in->error = XML_IO_BUFFER_FULL;
3303 return(-1);
3306 if (xmlBufGrow(in->buffer, len + 1) < 0) {
3307 xmlIOErrMemory("growing input buffer");
3308 in->error = XML_ERR_NO_MEMORY;
3309 return(-1);
3311 buffer = (char *)xmlBufEnd(in->buffer);
3314 * Call the read method for this I/O type.
3316 if (in->readcallback != NULL) {
3317 res = in->readcallback(in->context, &buffer[0], len);
3318 if (res <= 0)
3319 in->readcallback = endOfInput;
3320 } else {
3321 xmlIOErr(XML_IO_NO_INPUT, NULL);
3322 in->error = XML_IO_NO_INPUT;
3323 return(-1);
3325 if (res < 0) {
3326 return(-1);
3328 len = res;
3329 if (in->encoder != NULL) {
3330 unsigned int use;
3333 * Store the data in the incoming raw buffer
3335 if (in->raw == NULL) {
3336 in->raw = xmlBufCreate();
3338 res = xmlBufAdd(in->raw, (const xmlChar *) buffer, len);
3339 if (res != 0)
3340 return(-1);
3343 * convert as much as possible to the parser reading buffer.
3345 use = xmlBufUse(in->raw);
3346 nbchars = xmlCharEncInput(in, 1);
3347 if (nbchars < 0) {
3348 xmlIOErr(XML_IO_ENCODER, NULL);
3349 in->error = XML_IO_ENCODER;
3350 return(-1);
3352 in->rawconsumed += (use - xmlBufUse(in->raw));
3353 } else {
3354 nbchars = len;
3355 xmlBufAddLen(in->buffer, nbchars);
3357 #ifdef DEBUG_INPUT
3358 xmlGenericError(xmlGenericErrorContext,
3359 "I/O: read %d chars, buffer %d\n",
3360 nbchars, xmlBufUse(in->buffer));
3361 #endif
3362 return(nbchars);
3366 * xmlParserInputBufferRead:
3367 * @in: a buffered parser input
3368 * @len: indicative value of the amount of chars to read
3370 * Refresh the content of the input buffer, the old data are considered
3371 * consumed
3372 * This routine handle the I18N transcoding to internal UTF-8
3374 * Returns the number of chars read and stored in the buffer, or -1
3375 * in case of error.
3378 xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
3379 if ((in == NULL) || (in->error)) return(-1);
3380 if (in->readcallback != NULL)
3381 return(xmlParserInputBufferGrow(in, len));
3382 else if (xmlBufGetAllocationScheme(in->buffer) == XML_BUFFER_ALLOC_IMMUTABLE)
3383 return(0);
3384 else
3385 return(-1);
3388 #ifdef LIBXML_OUTPUT_ENABLED
3390 * xmlOutputBufferWrite:
3391 * @out: a buffered parser output
3392 * @len: the size in bytes of the array.
3393 * @buf: an char array
3395 * Write the content of the array in the output I/O buffer
3396 * This routine handle the I18N transcoding from internal UTF-8
3397 * The buffer is lossless, i.e. will store in case of partial
3398 * or delayed writes.
3400 * Returns the number of chars immediately written, or -1
3401 * in case of error.
3404 xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
3405 int nbchars = 0; /* number of chars to output to I/O */
3406 int ret; /* return from function call */
3407 int written = 0; /* number of char written to I/O so far */
3408 int chunk; /* number of byte curreent processed from buf */
3410 if ((out == NULL) || (out->error)) return(-1);
3411 if (len < 0) return(0);
3412 if (out->error) return(-1);
3414 do {
3415 chunk = len;
3416 if (chunk > 4 * MINLEN)
3417 chunk = 4 * MINLEN;
3420 * first handle encoding stuff.
3422 if (out->encoder != NULL) {
3424 * Store the data in the incoming raw buffer
3426 if (out->conv == NULL) {
3427 out->conv = xmlBufCreate();
3429 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
3430 if (ret != 0)
3431 return(-1);
3433 if ((xmlBufUse(out->buffer) < MINLEN) && (chunk == len))
3434 goto done;
3437 * convert as much as possible to the parser reading buffer.
3439 ret = xmlCharEncOutput(out, 0);
3440 if ((ret < 0) && (ret != -3)) {
3441 xmlIOErr(XML_IO_ENCODER, NULL);
3442 out->error = XML_IO_ENCODER;
3443 return(-1);
3445 nbchars = xmlBufUse(out->conv);
3446 } else {
3447 ret = xmlBufAdd(out->buffer, (const xmlChar *) buf, chunk);
3448 if (ret != 0)
3449 return(-1);
3450 nbchars = xmlBufUse(out->buffer);
3452 buf += chunk;
3453 len -= chunk;
3455 if ((nbchars < MINLEN) && (len <= 0))
3456 goto done;
3458 if (out->writecallback) {
3460 * second write the stuff to the I/O channel
3462 if (out->encoder != NULL) {
3463 ret = out->writecallback(out->context,
3464 (const char *)xmlBufContent(out->conv), nbchars);
3465 if (ret >= 0)
3466 xmlBufShrink(out->conv, ret);
3467 } else {
3468 ret = out->writecallback(out->context,
3469 (const char *)xmlBufContent(out->buffer), nbchars);
3470 if (ret >= 0)
3471 xmlBufShrink(out->buffer, ret);
3473 if (ret < 0) {
3474 xmlIOErr(XML_IO_WRITE, NULL);
3475 out->error = XML_IO_WRITE;
3476 return(ret);
3478 out->written += ret;
3480 written += nbchars;
3481 } while (len > 0);
3483 done:
3484 #ifdef DEBUG_INPUT
3485 xmlGenericError(xmlGenericErrorContext,
3486 "I/O: wrote %d chars\n", written);
3487 #endif
3488 return(written);
3492 * xmlEscapeContent:
3493 * @out: a pointer to an array of bytes to store the result
3494 * @outlen: the length of @out
3495 * @in: a pointer to an array of unescaped UTF-8 bytes
3496 * @inlen: the length of @in
3498 * Take a block of UTF-8 chars in and escape them.
3499 * Returns 0 if success, or -1 otherwise
3500 * The value of @inlen after return is the number of octets consumed
3501 * if the return value is positive, else unpredictable.
3502 * The value of @outlen after return is the number of octets consumed.
3504 static int
3505 xmlEscapeContent(unsigned char* out, int *outlen,
3506 const xmlChar* in, int *inlen) {
3507 unsigned char* outstart = out;
3508 const unsigned char* base = in;
3509 unsigned char* outend = out + *outlen;
3510 const unsigned char* inend;
3512 inend = in + (*inlen);
3514 while ((in < inend) && (out < outend)) {
3515 if (*in == '<') {
3516 if (outend - out < 4) break;
3517 *out++ = '&';
3518 *out++ = 'l';
3519 *out++ = 't';
3520 *out++ = ';';
3521 } else if (*in == '>') {
3522 if (outend - out < 4) break;
3523 *out++ = '&';
3524 *out++ = 'g';
3525 *out++ = 't';
3526 *out++ = ';';
3527 } else if (*in == '&') {
3528 if (outend - out < 5) break;
3529 *out++ = '&';
3530 *out++ = 'a';
3531 *out++ = 'm';
3532 *out++ = 'p';
3533 *out++ = ';';
3534 } else if (*in == '\r') {
3535 if (outend - out < 5) break;
3536 *out++ = '&';
3537 *out++ = '#';
3538 *out++ = '1';
3539 *out++ = '3';
3540 *out++ = ';';
3541 } else {
3542 *out++ = (unsigned char) *in;
3544 ++in;
3546 *outlen = out - outstart;
3547 *inlen = in - base;
3548 return(0);
3552 * xmlOutputBufferWriteEscape:
3553 * @out: a buffered parser output
3554 * @str: a zero terminated UTF-8 string
3555 * @escaping: an optional escaping function (or NULL)
3557 * Write the content of the string in the output I/O buffer
3558 * This routine escapes the caracters and then handle the I18N
3559 * transcoding from internal UTF-8
3560 * The buffer is lossless, i.e. will store in case of partial
3561 * or delayed writes.
3563 * Returns the number of chars immediately written, or -1
3564 * in case of error.
3567 xmlOutputBufferWriteEscape(xmlOutputBufferPtr out, const xmlChar *str,
3568 xmlCharEncodingOutputFunc escaping) {
3569 int nbchars = 0; /* number of chars to output to I/O */
3570 int ret; /* return from function call */
3571 int written = 0; /* number of char written to I/O so far */
3572 int oldwritten=0;/* loop guard */
3573 int chunk; /* number of byte currently processed from str */
3574 int len; /* number of bytes in str */
3575 int cons; /* byte from str consumed */
3577 if ((out == NULL) || (out->error) || (str == NULL) ||
3578 (out->buffer == NULL) ||
3579 (xmlBufGetAllocationScheme(out->buffer) == XML_BUFFER_ALLOC_IMMUTABLE))
3580 return(-1);
3581 len = strlen((const char *)str);
3582 if (len < 0) return(0);
3583 if (out->error) return(-1);
3584 if (escaping == NULL) escaping = xmlEscapeContent;
3586 do {
3587 oldwritten = written;
3590 * how many bytes to consume and how many bytes to store.
3592 cons = len;
3593 chunk = xmlBufAvail(out->buffer) - 1;
3596 * make sure we have enough room to save first, if this is
3597 * not the case force a flush, but make sure we stay in the loop
3599 if (chunk < 40) {
3600 if (xmlBufGrow(out->buffer, 100) < 0)
3601 return(-1);
3602 oldwritten = -1;
3603 continue;
3607 * first handle encoding stuff.
3609 if (out->encoder != NULL) {
3611 * Store the data in the incoming raw buffer
3613 if (out->conv == NULL) {
3614 out->conv = xmlBufCreate();
3616 ret = escaping(xmlBufEnd(out->buffer) ,
3617 &chunk, str, &cons);
3618 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
3619 return(-1);
3620 xmlBufAddLen(out->buffer, chunk);
3622 if ((xmlBufUse(out->buffer) < MINLEN) && (cons == len))
3623 goto done;
3626 * convert as much as possible to the output buffer.
3628 ret = xmlCharEncOutput(out, 0);
3629 if ((ret < 0) && (ret != -3)) {
3630 xmlIOErr(XML_IO_ENCODER, NULL);
3631 out->error = XML_IO_ENCODER;
3632 return(-1);
3634 nbchars = xmlBufUse(out->conv);
3635 } else {
3636 ret = escaping(xmlBufEnd(out->buffer), &chunk, str, &cons);
3637 if ((ret < 0) || (chunk == 0)) /* chunk==0 => nothing done */
3638 return(-1);
3639 xmlBufAddLen(out->buffer, chunk);
3640 nbchars = xmlBufUse(out->buffer);
3642 str += cons;
3643 len -= cons;
3645 if ((nbchars < MINLEN) && (len <= 0))
3646 goto done;
3648 if (out->writecallback) {
3650 * second write the stuff to the I/O channel
3652 if (out->encoder != NULL) {
3653 ret = out->writecallback(out->context,
3654 (const char *)xmlBufContent(out->conv), nbchars);
3655 if (ret >= 0)
3656 xmlBufShrink(out->conv, ret);
3657 } else {
3658 ret = out->writecallback(out->context,
3659 (const char *)xmlBufContent(out->buffer), nbchars);
3660 if (ret >= 0)
3661 xmlBufShrink(out->buffer, ret);
3663 if (ret < 0) {
3664 xmlIOErr(XML_IO_WRITE, NULL);
3665 out->error = XML_IO_WRITE;
3666 return(ret);
3668 out->written += ret;
3669 } else if (xmlBufAvail(out->buffer) < MINLEN) {
3670 xmlBufGrow(out->buffer, MINLEN);
3672 written += nbchars;
3673 } while ((len > 0) && (oldwritten != written));
3675 done:
3676 #ifdef DEBUG_INPUT
3677 xmlGenericError(xmlGenericErrorContext,
3678 "I/O: wrote %d chars\n", written);
3679 #endif
3680 return(written);
3684 * xmlOutputBufferWriteString:
3685 * @out: a buffered parser output
3686 * @str: a zero terminated C string
3688 * Write the content of the string in the output I/O buffer
3689 * This routine handle the I18N transcoding from internal UTF-8
3690 * The buffer is lossless, i.e. will store in case of partial
3691 * or delayed writes.
3693 * Returns the number of chars immediately written, or -1
3694 * in case of error.
3697 xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
3698 int len;
3700 if ((out == NULL) || (out->error)) return(-1);
3701 if (str == NULL)
3702 return(-1);
3703 len = strlen(str);
3705 if (len > 0)
3706 return(xmlOutputBufferWrite(out, len, str));
3707 return(len);
3711 * xmlOutputBufferFlush:
3712 * @out: a buffered output
3714 * flushes the output I/O channel
3716 * Returns the number of byte written or -1 in case of error.
3719 xmlOutputBufferFlush(xmlOutputBufferPtr out) {
3720 int nbchars = 0, ret = 0;
3722 if ((out == NULL) || (out->error)) return(-1);
3724 * first handle encoding stuff.
3726 if ((out->conv != NULL) && (out->encoder != NULL)) {
3728 * convert as much as possible to the parser output buffer.
3730 do {
3731 nbchars = xmlCharEncOutput(out, 0);
3732 if (nbchars < 0) {
3733 xmlIOErr(XML_IO_ENCODER, NULL);
3734 out->error = XML_IO_ENCODER;
3735 return(-1);
3737 } while (nbchars);
3741 * second flush the stuff to the I/O channel
3743 if ((out->conv != NULL) && (out->encoder != NULL) &&
3744 (out->writecallback != NULL)) {
3745 ret = out->writecallback(out->context,
3746 (const char *)xmlBufContent(out->conv),
3747 xmlBufUse(out->conv));
3748 if (ret >= 0)
3749 xmlBufShrink(out->conv, ret);
3750 } else if (out->writecallback != NULL) {
3751 ret = out->writecallback(out->context,
3752 (const char *)xmlBufContent(out->buffer),
3753 xmlBufUse(out->buffer));
3754 if (ret >= 0)
3755 xmlBufShrink(out->buffer, ret);
3757 if (ret < 0) {
3758 xmlIOErr(XML_IO_FLUSH, NULL);
3759 out->error = XML_IO_FLUSH;
3760 return(ret);
3762 out->written += ret;
3764 #ifdef DEBUG_INPUT
3765 xmlGenericError(xmlGenericErrorContext,
3766 "I/O: flushed %d chars\n", ret);
3767 #endif
3768 return(ret);
3770 #endif /* LIBXML_OUTPUT_ENABLED */
3773 * xmlParserGetDirectory:
3774 * @filename: the path to a file
3776 * lookup the directory for that file
3778 * Returns a new allocated string containing the directory, or NULL.
3780 char *
3781 xmlParserGetDirectory(const char *filename) {
3782 char *ret = NULL;
3783 char dir[1024];
3784 char *cur;
3786 #ifdef _WIN32_WCE /* easy way by now ... wince does not have dirs! */
3787 return NULL;
3788 #endif
3790 if (xmlInputCallbackInitialized == 0)
3791 xmlRegisterDefaultInputCallbacks();
3793 if (filename == NULL) return(NULL);
3795 #if defined(WIN32) && !defined(__CYGWIN__)
3796 # define IS_XMLPGD_SEP(ch) ((ch=='/')||(ch=='\\'))
3797 #else
3798 # define IS_XMLPGD_SEP(ch) (ch=='/')
3799 #endif
3801 strncpy(dir, filename, 1023);
3802 dir[1023] = 0;
3803 cur = &dir[strlen(dir)];
3804 while (cur > dir) {
3805 if (IS_XMLPGD_SEP(*cur)) break;
3806 cur --;
3808 if (IS_XMLPGD_SEP(*cur)) {
3809 if (cur == dir) dir[1] = 0;
3810 else *cur = 0;
3811 ret = xmlMemStrdup(dir);
3812 } else {
3813 if (getcwd(dir, 1024) != NULL) {
3814 dir[1023] = 0;
3815 ret = xmlMemStrdup(dir);
3818 return(ret);
3819 #undef IS_XMLPGD_SEP
3822 /****************************************************************
3824 * External entities loading *
3826 ****************************************************************/
3829 * xmlCheckHTTPInput:
3830 * @ctxt: an XML parser context
3831 * @ret: an XML parser input
3833 * Check an input in case it was created from an HTTP stream, in that
3834 * case it will handle encoding and update of the base URL in case of
3835 * redirection. It also checks for HTTP errors in which case the input
3836 * is cleanly freed up and an appropriate error is raised in context
3838 * Returns the input or NULL in case of HTTP error.
3840 xmlParserInputPtr
3841 xmlCheckHTTPInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr ret) {
3842 #ifdef LIBXML_HTTP_ENABLED
3843 if ((ret != NULL) && (ret->buf != NULL) &&
3844 (ret->buf->readcallback == xmlIOHTTPRead) &&
3845 (ret->buf->context != NULL)) {
3846 const char *encoding;
3847 const char *redir;
3848 const char *mime;
3849 int code;
3851 code = xmlNanoHTTPReturnCode(ret->buf->context);
3852 if (code >= 400) {
3853 /* fatal error */
3854 if (ret->filename != NULL)
3855 __xmlLoaderErr(ctxt, "failed to load HTTP resource \"%s\"\n",
3856 (const char *) ret->filename);
3857 else
3858 __xmlLoaderErr(ctxt, "failed to load HTTP resource\n", NULL);
3859 xmlFreeInputStream(ret);
3860 ret = NULL;
3861 } else {
3863 mime = xmlNanoHTTPMimeType(ret->buf->context);
3864 if ((xmlStrstr(BAD_CAST mime, BAD_CAST "/xml")) ||
3865 (xmlStrstr(BAD_CAST mime, BAD_CAST "+xml"))) {
3866 encoding = xmlNanoHTTPEncoding(ret->buf->context);
3867 if (encoding != NULL) {
3868 xmlCharEncodingHandlerPtr handler;
3870 handler = xmlFindCharEncodingHandler(encoding);
3871 if (handler != NULL) {
3872 xmlSwitchInputEncoding(ctxt, ret, handler);
3873 } else {
3874 __xmlErrEncoding(ctxt, XML_ERR_UNKNOWN_ENCODING,
3875 "Unknown encoding %s",
3876 BAD_CAST encoding, NULL);
3878 if (ret->encoding == NULL)
3879 ret->encoding = xmlStrdup(BAD_CAST encoding);
3881 #if 0
3882 } else if (xmlStrstr(BAD_CAST mime, BAD_CAST "html")) {
3883 #endif
3885 redir = xmlNanoHTTPRedir(ret->buf->context);
3886 if (redir != NULL) {
3887 if (ret->filename != NULL)
3888 xmlFree((xmlChar *) ret->filename);
3889 if (ret->directory != NULL) {
3890 xmlFree((xmlChar *) ret->directory);
3891 ret->directory = NULL;
3893 ret->filename =
3894 (char *) xmlStrdup((const xmlChar *) redir);
3898 #endif
3899 return(ret);
3902 static int xmlNoNetExists(const char *URL) {
3903 const char *path;
3905 if (URL == NULL)
3906 return(0);
3908 if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file://localhost/", 17))
3909 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3910 path = &URL[17];
3911 #else
3912 path = &URL[16];
3913 #endif
3914 else if (!xmlStrncasecmp(BAD_CAST URL, BAD_CAST "file:///", 8)) {
3915 #if defined (_WIN32) || defined (__DJGPP__) && !defined(__CYGWIN__)
3916 path = &URL[8];
3917 #else
3918 path = &URL[7];
3919 #endif
3920 } else
3921 path = URL;
3923 return xmlCheckFilename(path);
3926 #ifdef LIBXML_CATALOG_ENABLED
3929 * xmlResolveResourceFromCatalog:
3930 * @URL: the URL for the entity to load
3931 * @ID: the System ID for the entity to load
3932 * @ctxt: the context in which the entity is called or NULL
3934 * Resolves the URL and ID against the appropriate catalog.
3935 * This function is used by xmlDefaultExternalEntityLoader and
3936 * xmlNoNetExternalEntityLoader.
3938 * Returns a new allocated URL, or NULL.
3940 static xmlChar *
3941 xmlResolveResourceFromCatalog(const char *URL, const char *ID,
3942 xmlParserCtxtPtr ctxt) {
3943 xmlChar *resource = NULL;
3944 xmlCatalogAllow pref;
3947 * If the resource doesn't exists as a file,
3948 * try to load it from the resource pointed in the catalogs
3950 pref = xmlCatalogGetDefaults();
3952 if ((pref != XML_CATA_ALLOW_NONE) && (!xmlNoNetExists(URL))) {
3954 * Do a local lookup
3956 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3957 ((pref == XML_CATA_ALLOW_ALL) ||
3958 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3959 resource = xmlCatalogLocalResolve(ctxt->catalogs,
3960 (const xmlChar *)ID,
3961 (const xmlChar *)URL);
3964 * Try a global lookup
3966 if ((resource == NULL) &&
3967 ((pref == XML_CATA_ALLOW_ALL) ||
3968 (pref == XML_CATA_ALLOW_GLOBAL))) {
3969 resource = xmlCatalogResolve((const xmlChar *)ID,
3970 (const xmlChar *)URL);
3972 if ((resource == NULL) && (URL != NULL))
3973 resource = xmlStrdup((const xmlChar *) URL);
3976 * TODO: do an URI lookup on the reference
3978 if ((resource != NULL) && (!xmlNoNetExists((const char *)resource))) {
3979 xmlChar *tmp = NULL;
3981 if ((ctxt != NULL) && (ctxt->catalogs != NULL) &&
3982 ((pref == XML_CATA_ALLOW_ALL) ||
3983 (pref == XML_CATA_ALLOW_DOCUMENT))) {
3984 tmp = xmlCatalogLocalResolveURI(ctxt->catalogs, resource);
3986 if ((tmp == NULL) &&
3987 ((pref == XML_CATA_ALLOW_ALL) ||
3988 (pref == XML_CATA_ALLOW_GLOBAL))) {
3989 tmp = xmlCatalogResolveURI(resource);
3992 if (tmp != NULL) {
3993 xmlFree(resource);
3994 resource = tmp;
3999 return resource;
4002 #endif
4005 * xmlDefaultExternalEntityLoader:
4006 * @URL: the URL for the entity to load
4007 * @ID: the System ID for the entity to load
4008 * @ctxt: the context in which the entity is called or NULL
4010 * By default we don't load external entitites, yet.
4012 * Returns a new allocated xmlParserInputPtr, or NULL.
4014 static xmlParserInputPtr
4015 xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
4016 xmlParserCtxtPtr ctxt)
4018 xmlParserInputPtr ret = NULL;
4019 xmlChar *resource = NULL;
4021 #ifdef DEBUG_EXTERNAL_ENTITIES
4022 xmlGenericError(xmlGenericErrorContext,
4023 "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
4024 #endif
4025 if ((ctxt != NULL) && (ctxt->options & XML_PARSE_NONET)) {
4026 int options = ctxt->options;
4028 ctxt->options -= XML_PARSE_NONET;
4029 ret = xmlNoNetExternalEntityLoader(URL, ID, ctxt);
4030 ctxt->options = options;
4031 return(ret);
4033 #ifdef LIBXML_CATALOG_ENABLED
4034 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
4035 #endif
4037 if (resource == NULL)
4038 resource = (xmlChar *) URL;
4040 if (resource == NULL) {
4041 if (ID == NULL)
4042 ID = "NULL";
4043 __xmlLoaderErr(ctxt, "failed to load external entity \"%s\"\n", ID);
4044 return (NULL);
4046 ret = xmlNewInputFromFile(ctxt, (const char *) resource);
4047 if ((resource != NULL) && (resource != (xmlChar *) URL))
4048 xmlFree(resource);
4049 return (ret);
4052 static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
4053 xmlDefaultExternalEntityLoader;
4056 * xmlSetExternalEntityLoader:
4057 * @f: the new entity resolver function
4059 * Changes the defaultexternal entity resolver function for the application
4061 void
4062 xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
4063 xmlCurrentExternalEntityLoader = f;
4067 * xmlGetExternalEntityLoader:
4069 * Get the default external entity resolver function for the application
4071 * Returns the xmlExternalEntityLoader function pointer
4073 xmlExternalEntityLoader
4074 xmlGetExternalEntityLoader(void) {
4075 return(xmlCurrentExternalEntityLoader);
4079 * xmlLoadExternalEntity:
4080 * @URL: the URL for the entity to load
4081 * @ID: the Public ID for the entity to load
4082 * @ctxt: the context in which the entity is called or NULL
4084 * Load an external entity, note that the use of this function for
4085 * unparsed entities may generate problems
4087 * Returns the xmlParserInputPtr or NULL
4089 xmlParserInputPtr
4090 xmlLoadExternalEntity(const char *URL, const char *ID,
4091 xmlParserCtxtPtr ctxt) {
4092 if ((URL != NULL) && (xmlNoNetExists(URL) == 0)) {
4093 char *canonicFilename;
4094 xmlParserInputPtr ret;
4096 canonicFilename = (char *) xmlCanonicPath((const xmlChar *) URL);
4097 if (canonicFilename == NULL) {
4098 xmlIOErrMemory("building canonical path\n");
4099 return(NULL);
4102 ret = xmlCurrentExternalEntityLoader(canonicFilename, ID, ctxt);
4103 xmlFree(canonicFilename);
4104 return(ret);
4106 return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
4109 /************************************************************************
4111 * Disabling Network access *
4113 ************************************************************************/
4116 * xmlNoNetExternalEntityLoader:
4117 * @URL: the URL for the entity to load
4118 * @ID: the System ID for the entity to load
4119 * @ctxt: the context in which the entity is called or NULL
4121 * A specific entity loader disabling network accesses, though still
4122 * allowing local catalog accesses for resolution.
4124 * Returns a new allocated xmlParserInputPtr, or NULL.
4126 xmlParserInputPtr
4127 xmlNoNetExternalEntityLoader(const char *URL, const char *ID,
4128 xmlParserCtxtPtr ctxt) {
4129 xmlParserInputPtr input = NULL;
4130 xmlChar *resource = NULL;
4132 #ifdef LIBXML_CATALOG_ENABLED
4133 resource = xmlResolveResourceFromCatalog(URL, ID, ctxt);
4134 #endif
4136 if (resource == NULL)
4137 resource = (xmlChar *) URL;
4139 if (resource != NULL) {
4140 if ((!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "ftp://", 6)) ||
4141 (!xmlStrncasecmp(BAD_CAST resource, BAD_CAST "http://", 7))) {
4142 xmlIOErr(XML_IO_NETWORK_ATTEMPT, (const char *) resource);
4143 if (resource != (xmlChar *) URL)
4144 xmlFree(resource);
4145 return(NULL);
4148 input = xmlDefaultExternalEntityLoader((const char *) resource, ID, ctxt);
4149 if (resource != (xmlChar *) URL)
4150 xmlFree(resource);
4151 return(input);
4154 #define bottom_xmlIO
4155 #include "elfgcchack.h"